<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>leesungjoon-net.log</title>
        <link>https://velog.io/</link>
        <description>Time-Series</description>
        <lastBuildDate>Sun, 14 Jan 2024 09:59:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>leesungjoon-net.log</title>
            <url>https://velog.velcdn.com/images/leesungjoon-net/profile/5d53ef03-d374-4c85-9b17-baafed86b497/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. leesungjoon-net.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/leesungjoon-net" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Iterative Method vs Direct Method]]></title>
            <link>https://velog.io/@leesungjoon-net/Iterative-Method-vs-Direct-Method</link>
            <guid>https://velog.io/@leesungjoon-net/Iterative-Method-vs-Direct-Method</guid>
            <pubDate>Sun, 14 Jan 2024 09:59:19 GMT</pubDate>
            <description><![CDATA[<p><strong>Iterative Method:</strong>
이전 시간의 값을 재귀적으로 넣어서 시계열의 예측을 수행하는 것이다.따라서 이전의 모든 시간에 대한 정보가 필요하다.
예를 들어서, t시점에서 f(t+h)를 예측하는데 f(t+h-1),f(t+h-2),..의 값들이 필요한 것을 말하고, “Training만을 하는 곳 부터 예측을 하는 곳 까지 모든 시간에 같은 Covariate를 포함해야 한다는 단점이 있다.”</p>
<p><strong>Direct Method:</strong>
Seq2Seq가 대표적인 방법으로써, 과거 시간의 값을 하나의 벡터로 축적을 하여 미래를 예측하는 것으로 미래에 알려진 Covariate만을 사용하여서 예측을 수행할 수 있다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/fd4eb89c-5592-487c-8a50-30c48e22e62b/image.png" alt="">
<a href="https://arxiv.org/pdf/2004.13408.pdf">출처</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DeepLearning개요와DeepAR_[Updated]]]></title>
            <link>https://velog.io/@leesungjoon-net/DeepLearning%EC%9A%94%EC%99%80DeepARUpdated</link>
            <guid>https://velog.io/@leesungjoon-net/DeepLearning%EC%9A%94%EC%99%80DeepARUpdated</guid>
            <pubDate>Mon, 08 Jan 2024 14:57:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/319941b9-09d6-4440-9e87-889bea369078/image.png" alt=""></p>
<h1 id="deeplearning-개요와-deepar">DeepLearning 개요와 DeepAR</h1>
<h1 id="개요">개요</h1>
<ol>
<li>딥러닝 Basic<ul>
<li>딥러닝 학습과정</li>
<li>활성화 함수</li>
<li>목적함수</li>
<li>Optimizer 와 Gradient Descent</li>
<li>BackPropagation for matrix computing</li>
</ul>
</li>
<li>딥러닝 모델<ul>
<li>RNN</li>
<li>TBPTT</li>
<li>LSTM</li>
<li>Encoder-Decoder구조</li>
</ul>
</li>
<li>Deep AR 논문 review</li>
</ol>
<h1 id="1-deeplearning-basic">1. DeepLearning Basic</h1>
<h2 id="11-deeplearning-학습-과정">1.1 DeepLearning 학습 과정</h2>
<p>다음과 같은 과정을 거친다.</p>
<ol>
<li><strong>데이터 준비:</strong></li>
</ol>
<p>→ 데이터 준비 후 누락 값 이상치 제거 등의 과정을 거친다.</p>
<ol>
<li><strong>모델 정의:</strong></li>
</ol>
<p>→ 신경망을 생성한다. 일반적으로 Hidden Layer의 개수가 많을수록 성능이 좋아지지만 과적합이 발생할 확률이 높다.
또한 활성화 함수, 목적 함수, Optimizer등을 선택한다.</p>
<ol>
<li><strong>트레이닝:</strong></li>
</ol>
<ul>
<li>트레이닝은 forward propagation과 backward propagation 과정으로 나뉜다.</li>
</ul>
<p>Forward propagation 과정에서 우리는 우리가 준비한 데이터를 input layer에 값으로 집어넣고 여러 가중치와 hidden layer에 활성화 함수를 거치면서 우리는 Output layer에 도달하게 된다.
이때 목적함수를 최적화 하는 방향으로 가중치를 업데이트 하는 backward propagation 과정을 거치면서 가중치를 업데이트 한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/c2505071-edf2-4006-a8a0-07c1e2e2b87c/image.png" alt=""></p>
<p>[Multi-Layer Perceptrons]</p>
<p>→ MLP는 Activation Function을 갖는  Hidden Layer가 하나 이상인 Neural Network를 의미한다.</p>
<h2 id="12-활성화-함수activation-function">1.2 활성화 함수(Activation Function)</h2>
<p>활성화 함수의 목적은 전체 Network에 Non-Linearity를 부여하는데 있다. 다음의 예제를 살펴보자.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c97e013c-9876-4b9e-b878-a6ddb25227c3/image.png" alt=""></p>
<p>위와 같은 경우 Hidden Layer를 추가한 의미가 없어진다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/815b8859-8e74-4ff0-9eb6-e4b152106d60/image.png" alt=""></p>
<p>Hidden Layer를 추가하지 않아도 결과 값을 표현하는데 문제가 없고, 선형적인 예측만 가능한 것을 볼 수 있다.</p>
<p>따라서 이를 해결하기 위해서 여러 Activation Function을 추가하는데, 몇 가지 Activation Function을 살펴보겠다.</p>
<p><strong>1) Sigmoid</strong></p>
<p>$$
\phi(x) = \frac1{1+e^{-x}}
$$
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/09fbc107-bec6-499a-9f35-2a9fb8faaf57/image.png" alt=""></p>
<p>단점 :</p>
<p>가. Saturation 현상</p>
<p>좌우로 접선의 기울기가 0이 되는 지점이 -6과 +6만 되어도 시작이 되기 때문에 </p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/ea8d36b7-c0ca-49d2-8185-a6c2d573651a/image.png" alt=""></p>
<p>위처럼 BackPropagation이 진행될 때, Gradient Vanishing 현상이 발생한다.</p>
<p>나. exp연산이 들어가므로 연산이 느리다.</p>
<p>다. Zig Zag 업데이트 현상</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/aa057081-f8f9-4974-befb-98a34de9570a/image.png" alt=""></p>
<p>이렇게 0이 중심(<strong><strong>zero-centered</strong></strong>)가 아닌 활성화 함수는 Zig Zag현상에 의해 학습 속도가 느리다.</p>
<p><strong>2) Tanh(Hyperbolic Tangent)</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/8fa1a624-7d6b-4de2-96a4-341f6ee8d293/image.png" alt=""></p>
<p>장점: 결과 값이 -1~1 사이 이기 때문에 ZigZag현상이 덜하다.</p>
<p>단점: 변함없이 Saturation 현상이 있어 w 업데이트가 멈출 수 있다.</p>
<p><strong>3)  ReLU(Rectified Linear Unit):</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/dfcf9dc3-4c06-4b31-a5d9-8029369a2a28/image.png" alt=""></p>
<p>장점:</p>
<ul>
<li>Saturation되는 부분이 2곳에서 1곳으로 줄었다.</li>
<li>Exp 연산이 없어서 연산이 빠르다.</li>
<li>수렴 속도가 Sigmoid/Tanh에 비해 빠르다.</li>
</ul>
<p>단점:</p>
<ul>
<li>Zero-Centered 가 아니기 때문에 ZigZag 현상이 발생한다.</li>
</ul>
<h2 id="13-목적함수objective-function">1.3 목적함수(Objective Function)</h2>
<p>학습을 통해 최적화 시키고자 하는 함수로써, DeepLearning에서는 일반적으로 학습을 통해 Loss를 최적화 시키려는 작업을 수행하고, 이때의 Loss를 계산하기 위한 함수를 Objective Function혹은 Loss Function 이라고 한다.</p>
<p>여러 Loss Function이 있고, Loss Function에 따라서 모델의 성능 향상이 일어나기도 한다.</p>
<h2 id="14-optimizer와-gradient-descent">1.4 Optimizer와 Gradient Descent</h2>
<p>위에서 언급했듯 Loss Function을 최적화 시키는 방향으로 학습을 진행하는데, 이때 최적화 알고리즘을 <strong>Optimizer</strong>라고 한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/396bb3bd-b9aa-4b09-9f67-f02a335af3e9/image.png" alt=""></p>
<p>핵심적인 optimizer는 다음과 같다.</p>
<ul>
<li>Gradient Descent</li>
<li>Stochastic Gradient Descent</li>
<li>Batch Gradient Descent</li>
<li>Mini-Batch Gradient Descent</li>
<li>Momentum</li>
<li>Adagrad</li>
<li>RMSProp</li>
<li>Adam</li>
</ul>
<p><strong>1) Gradient Descent</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/5487e59a-5344-4738-8c71-05a3338a94ab/image.png" alt=""></p>
<p>위의 사진에서 weight에 따른 loss function을 볼 수 있다. Backpropagation과정에서 우리는 모델의 weight를 loss function을 최적화 하는 방향으로 업데이트 시켜야 하는데, 이때 loss function을 w로 편미분을 한 것이 바로 <strong>Gradient</strong>라고 정의하고,
한번에 다가갈 step을 learning rate라고 한다.</p>
<p>만약 learning rate가 이상적이라면 아래와 같이 수렴하겠지만</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/73b4e114-70b1-4687-80b7-b1dd2bfc2f0b/image.png" alt=""></p>
<p>Learning rate가 크다면 다음과 같이 진행돼서 minimum값에 수렴하지 못하는 상황이 발생한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/22233112-3b27-48b5-a4bc-0fc03088f249/image.png" alt=""></p>
<p>반대로 Learning Rate가 작다면 수렴하긴 하지만 최종 값으로 찾아갈 때까지 너무 많은 훈련을 수행해야 한다. 따라서 학습 속도가 느려진다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b849f090-aff2-4518-8811-c5b584fbb695/image.png" alt=""></p>
<p><strong>2) Stochastic Gradient Descent(SGD)</strong></p>
<p>우리의 데이터가 100만개 있다고 가정해보자.
우리는 이 데이터를 한 sample씩 Neural Net에 집어넣을 수 있다.
하지만 이렇게 되면 100만개의 데이터를 모두 처리하는데 시간이 많이 걸리고 비효율이 따른다.
따라서 우리는 Stochastic이라는 말을 붙여서 이중에 랜덤으로 몇 개의 Sample을 선택해서 최솟값으로 수렴하도록 하는 것이다.
랜덤으로 선택하는 방법은 단순하게 데이터 Sample을 섞어주면 된다.
확률적 경사 하강법은 극단적으로 노이즈가 많을 수 있지만 평균적으로는 좋은 방향으로 가게 된다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/87607a98-753b-444d-8e09-739329daba14/image.png" alt=""></p>
<p>위와 같이 Local Minimum에 빠지는 것을 막아 줄 수도 있다.</p>
<p><strong>3) Full-Batch Gradient Descent</strong></p>
<p>Batch의 뜻은 다음과 같다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/ba875e09-b827-4cbb-8a3e-4760f521dd67/image.png" alt=""></p>
<p>Full-Batch Gradient Descent는 행렬을 사용하여서 처리하는데, 하나의 가중치 Set이 있고, 
이 가중치에 대해서 모든 Sample로 이루어진 1 Batch(즉, 행렬)를 입력으로 넣게 된다. </p>
<p>이렇게 행렬 계산을 통해 각 Sample마다 예측 값을 구해낼 수 있고, 구해진 예측 값들을 하나의 Loss로 만드는 과정에서 Sum이 사용되고, 이렇게 구해진 Loss를 BackPropagation시킨다.</p>
<p>아래는 배치 경사하강법을 잘 설명한 동영상이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/19dc0e89-1c8a-4d00-b7af-eaa6f4756af5/image.png" alt=""></p>
<p>[출처]<a href="https://www.youtube.com/watch?v=mccscAH2kkk">https://www.youtube.com/watch?v=mccscAH2kkk</a></p>
<p>위와 같이 모든 데이터를 하나의 Batch로 사용해서, Training의 1Epoch을 수행하는 것을 Full-Batch Gradient Descent라고 한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e287c223-ecf8-4f2c-b8b7-e144b72c71ca/image.png" alt=""></p>
<p>한번의 Epoch에 우리가 가지고 있는 모든 샘플을 사용하므로 데이터의 일관성이 유지 돼서 Smooth하게 Cost Function에 최적 값에 수렴 가능하다.</p>
<p>하지만 데이터가 큰 경우에는 너무 많은 Computing 자원을 소모하게 되는데 따라서 생각해 낸 것이 Mini-Batch GD이다.</p>
<p><strong>4) Mini Batch Gradient Descent</strong></p>
<p>Mini Batch Gradient Descent는 Stochastic Gradient Descent와 Batch Gradient Descent의 절충안으로써, Batch Size를 정하여서, 작은 Size의 Batch를 여러 개 만든 후 해당 Batch를 이용해, Gradient Descent를 진행한다. </p>
<p>Pytorch에서 채택하는 loss.backward()를 사용할 때, 우리는 Batch Size를 입력하여 만든 DataLoader를 이용해서 Gradient Descent를 진행한다. </p>
<p>Mini Batch는 Full Batch보단 덜 Smooth하게 수렴하는 것을 알 수있다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/8cef4168-5e2e-49d5-88d4-be8bf01261e4/image.png" alt=""></p>
<p>보통 Batch Size는 2의 n제곱을 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/f1c9083a-545b-469b-8afd-396bfb88e096/image.png" alt=""></p>
<aside>
💡 그런데, 이런 의문이 들었다 
Batch GD와 Mini-Batch GD 둘 다 1 Epoch에 모든 데이터를 사용하는 것은 마찬가지인데, 그러면 데이터 연산의 총 양은 둘 다 같은 것 아닌가? Mini-Batch GD가 Batch GD보다 연산 속도가 빠르다는 것의 의미가 무엇일까?

<p>찾아보니 다음과 같은 설명이 있었다.
→ 실제 우리가 딥러닝 모델을 훈련 시킬때는 DataLoader를 For문을 이용해서 훈련을 시키기 때문에 행렬 연산을 GPU를 이용하여 병렬로 수행 시키지 않지만, 추가적인 설정을 통해 행렬 연산을 병렬로 수행 시킨다면, 속도 상의 이점을 가질 수 있다.</p>
<p><strong>더욱 중요한 이점은 다음과 같다.
→</strong> Mini-Batch GD는 Batch GD와 Stochastic GD의 절충안 인데, Batch GD에서 Local Minimum의 빠질 가능성을 Mini-Batch GD를 사용함으로써 줄여주는 것이다. 
→ 추가적으로, 너무 많은 데이터의 경우 Batch GD를 사용하면 메모리에 한번에 안 올라갈 수 있기 때문에 Mini-Batch를 사용하여 이런 위험을 줄일 수 있다.</p>
</aside>

<h1 id="2-딥러닝-모델">2. 딥러닝 모델</h1>
<hr>
<p><strong>❗&lt;참고&gt;Pytorch에서 사용하는 Linear Layer와 RNN의 입력 Tensor</strong> </p>
<p>보통 pytorch의 RNN모델을 사용하게 되면 Input Tensor의 크기를 <strong>(Batch_Size, Sequence_Length,Feature Dimension)</strong>으로 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/812b77de-ed9f-4619-adf1-d5d6477ef487/image.png" alt=""></p>
<p>반면에 일반적인 Linear Layer를 사용할 때는 2차원 텐서<strong>(Batch Size, Input dimension)</strong>을 사용하는데, </p>
<p>Pytorch의 Linear Layer는 임의의 Tensor Size를 갖을 수 있다.
예를 들어 Input Size가 (10,3,4)인 Tensor를 Linear(4, 5)에 넣게 되면,
Output Size는 마지막 dimension만 바뀌어서 (10,3,5)로 나오게 되고 이때의 원리는 Pytorch는 (10,3,4)를 10*3 = 30개의 4차원 벡터로 바라본다. </p>
<p>따라서 각각의 벡터에 같은 Weight를 적용한 결과가 나오게 된다.</p>
<p>출처: <a href="https://stackoverflow.com/questions/58587057/multi-dimensional-inputs-in-pytorch-linear-method">https://stackoverflow.com/questions/58587057/multi-dimensional-inputs-in-pytorch-linear-method</a></p>
<p><strong>실습&gt;</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/cf142aa9-dddd-400a-92b8-1e13297cec3c/image.png" alt=""></p>
<hr>
<h3 id="21-rnnrecurrent-neural-net"><strong>2.1. RNN(Recurrent Neural Net)</strong></h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e4d3150e-537a-4f40-9946-6ac04530b6ac/image.png" alt=""></p>
<p>RNN에서는 메모리 셀( RNN CELL )을 도입해서 여기에서 나오는 결과값인 $h_t$(Hidden state)를 사용하여 이전의 결과 값이 다음의 결과의 영향을 주도록 만들었다.</p>
<p>따라서, 시계열 데이터에 적합한 모델로써,
시간에 따라서 입력이 Neural Net에 하나 씩 들어오게 되고 결과적으로는 같은 RNN에 입력이 바뀌어서 들어오는 것이기 때문에 시간에 따라 가중치가 공유된다.
RNN을 위와 같이 표현할 수도 있지만 펼쳐서 표현할 수도 있다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/dc41416e-6ba3-4f52-988f-54fcb620629d/image.png" alt=""></p>
<p>RNN에 대한 수식을 작성해보겠다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/ece95d13-825a-4981-a882-84bad8531b99/image.png" alt=""></p>
<p>입력 벡터의 차원이 d라고 하고 은닉 상태의 크기를 $D_h$ 라고 할 때, 각 벡터와 행렬의 크기는 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/52317dfc-3fea-41a7-98ed-073f2db0895f/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/827e3f6f-a105-4bed-8232-87d04638ee8f/image.png" alt=""></p>
<p><strong>RNN의BackPropagation (BackPropagation Through Time)[BPTT]</strong></p>
<blockquote>
<p>💡아래와 같이 표현한 것은 RNN Cell을 시간의 흐름에 따라서 길게 늘어뜨린 것일 뿐이고 <strong>실제로는 한 개의 Cell임</strong>을 다시 한번 상기하자.<br><img src="https://velog.velcdn.com/images/leesungjoon-net/post/dc41416e-6ba3-4f52-988f-54fcb620629d/image.png" alt=""></p>
</blockquote>
<p>RNN이 시간의 흐름에 따라 입력을 받기 때문에, BackPropagation을 할 때에도 시간의 흐름에 따른 입력을 고려하여서 BackPropagation을 진행해야 한다. </p>
<p>BPTT는 손실 함수를 사용한 모든 출력에서 역방향으로 전파된다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/5478aad1-02b2-4299-b260-fdcf92fcc0f8/image.png" alt=""></p>
<p>이때, 시계열의 Sequence 길이가 길어지면 곱해지는 것이 계속해서 많아지게 될 것이고 BackPropagation 과정에서 초반의 입력에 대해서는 가중치가 거의 업데이트 되지 않는 Gradient Vanishing문제가 발생한다.</p>
<p>이를 해결하기 위해 Truncated BPTT와 LSTM등의 아이디어가 제안 됐다.</p>
<h3 id="22-truncated-back-propagation-through-timetbptt"><strong>2.2 Truncated Back Propagation Through Time(TBPTT)</strong></h3>
<p>💡 TBPTT의 핵심 아이디어는 다음과 같다.
예를 들어 5000 Step 앞을 예측한다고 해보자. 그러면, 위에서 언급했던 이유로 Gradient Vanishing 문제가 발생할 것이다. 따라서, 우리는 50 Step씩 100개로 쪼갤 것이다.
원래는 5000 Step을 거쳐서 Weight가 업데이트 돼야 하지만
그렇게 하지 말고 50 Step씩 100개의 그룹으로 쪼갠후
1번째 그룹에서 50번째를 예측한 후 구해진 Error로 Weight를 <strong>Estimate</strong> 하고 
2번째 그룹에서 100번째를 예측한 후 구해진 Error로 Weight  를 <strong>Estimate</strong> 하는 과정을 거치면서
최종적으로 100번째 그룹에서 Weight의 업데이트를 확정 짓는 과정을 거친다.
이때, 각 그룹의 초기 Hidden State는 이전 그룹의 Last Hidden State와 연결 지어 주는 것이 핵심이다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/a04dc30e-5b24-4a42-a6f3-00a8f2736159/image.png" alt=""></p>
<p>한글로 된 블로그나 여러가지를 찾아보면 다음과 같이 돼있고 알아보기 너무 어려웠다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e93d3863-ff50-4842-b201-39570b66dd29/image.png" alt=""></p>
<p><a href="https://www.youtube.com/watch?v=v5FFzZTivwU">https://www.youtube.com/watch?v=v5FFzZTivwU</a></p>
<p>위의 동영상에 설명이 나와있으니 확인해보길 바란다.</p>
<p>아래는 Truncated BPTT 구현의 관련한 Pytorch Forum이다. 여기서 핵심 아이디어는 Forward를 진행하다가 멈추고 싶은 지점에서 반복문으로 멈춘 후 BackPropagation을 진행하는 방식을 사용한다.</p>
<p><a href="https://discuss.pytorch.org/t/implementing-truncated-backpropagation-through-time/15500/24">https://discuss.pytorch.org/t/implementing-truncated-backpropagation-through-time/15500/24</a></p>
<p>아래는 Chat GPT로 구현한 예제이다.</p>
<pre><code class="language-jsx">import torch
import torch.nn as nn

# 예제를 위한 RNN 모델 정의
class SimpleRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleRNN, self).__init__()
        self.hidden_size = hidden_size
        self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        batch_size = x.size(0)
        hidden = self.init_hidden(batch_size)
        out, _ = self.rnn(x, hidden)
        out = self.fc(out[:, -1, :])  # 마지막 시퀀스에 대한 결과만 사용
        return out

    def init_hidden(self, batch_size):
        return torch.zeros(1, batch_size, self.hidden_size)  # 초기 hidden state 생성

# Truncated BPTT 구현
def train_truncated_bptt(model, criterion, optimizer, data, sequence_length=10, num_epochs=10):
    for epoch in range(num_epochs):
        for i in range(0, len(data), sequence_length):
            # 시퀀스를 작은 조각으로 나눔
            inputs = data[i:i+sequence_length]
            targets = data[i+sequence_length]

            optimizer.zero_grad()

            # 순전파
            outputs = model(inputs.unsqueeze(0))  # 배치 차원 추가
            loss = criterion(outputs, targets.unsqueeze(0))  # 손실 계산

            # 역전파 및 최적화
            loss.backward()
            optimizer.step()

        print(f&#39;Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item()}&#39;)

# 예제 데이터 생성
input_size = 1
hidden_size = 16
output_size = 1
data = torch.sin(torch.arange(0, 1000) * 0.1)  # 임의의 sine 데이터 생성

# 모델, 손실 함수, 옵티마이저 초기화
model = SimpleRNN(input_size, hidden_size, output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# Truncated BPTT 학습
train_truncated_bptt(model, criterion, optimizer, data)</code></pre>
<h3 id="23-lstm"><strong>2.3 LSTM</strong></h3>
<p>앞서 언급해온 Long Term Dependency와 관련한 문제를 해결하기 위해 TBPTT를 사용할 수 있지만, RNN대신에 Cell-State를 도입한 LSTM을 사용하여 문제를 해결할 수도 있다.</p>
<blockquote>
<p>💡 장기 의존성을 챙기기 위해서 직통 통로를 뚫어 놓았다고 이해하면 좋다.</p>
</blockquote>
<p>LSTM의 구조</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/95d08af5-c36e-43a9-852d-ab64c3fa3990/image.png" alt=""></p>
<p>LSTM은 2가지 <strong>Input Gate</strong>와 <strong>Forget Gate</strong>를 이용해서 Cell-State가 이전의 정보를 얼마나 잊고 현재의 정보를 얼마나 기억할지를 정한다.</p>
<p>또 현재의 입력과 Cell-State를 조합하여 새로운 Hidden State를 생성하는 <strong>Output Gate</strong>를 두게된다.</p>
<p>각각을 살펴보면 다음과 같다.</p>
<p><strong>1) Forget Gate</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/532a70e2-1f85-4199-8b2d-832c88cf9ff3/image.png" alt=""></p>
<p>이전으로부터 받은 정보와 우리가 새로 입력 받은 정보를 토대로 이전의 정보를 얼마나 잊을지 결정하는 Forget Gate</p>
<p><strong>2) Input Gate</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/64d5aaff-bf19-4912-b542-2e053adabdef/image.png" alt=""></p>
<p>우리가 입력 받은 정보를 토대로 우리의 입력 값을 얼마나 입력할지 결정하는 Input gate</p>
<p><strong>3) Cell State</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/d54e39c0-166a-45aa-a307-9aae75a6ee38/image.png" alt=""></p>
<blockquote>
<p>💡 이때, LSTM에서 Sigmoid함수는 값을 얼마나 기억할지, 잊을지를 결정하는 말 그대로 Gate의 역할을 하기 위해서 사용하고 Tanh는 값을 입력할 때 방향까지 고려하기 위해서 사용한다.</p>
</blockquote>
<p><strong>4) Output Gate</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e1db9252-1801-4998-be10-0cd1e579d60d/image.png" alt=""></p>
<p><strong>5) Hidden State</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/bbff3204-7308-4a88-8cbf-7a7796f28068/image.png" alt=""></p>
<blockquote>
<p>❗ LSTM도 Gradient Vanishing을 완전히 막는 것은 아니다. 단지 Cell State를 도입함으로써 Gradient가 초반 부분까지 잘 전달 되도록 어느 정도 유지해주는 역할을 한다.</p>
</blockquote>
<h3 id="24-encoder-decoder-구조">2.4 Encoder-Decoder 구조</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b6b0b326-fbfa-489c-9083-bc6f3c0be8c7/image.png" alt=""></p>
<ul>
<li>Encoder</li>
</ul>
<p>→ RNN을 쌓은 것이고, Input Sequence 로부터 정보를 받아서 순전파 시킨다.</p>
<p>→ QA Task에서 Question의 각 단어가 Input $x_i$  이다.</p>
<ul>
<li>Encoder Vector</li>
</ul>
<p>→ Enocder 부분의 Final Hidden State이다.</p>
<p>→ 모델의 예측 정확도 향상을 위해 Input Element의 정보를 Encapsulate 하는 것이 목표이다.</p>
<p>→ 모델의 Decoder 부분의 최초 Hidden State 역할을 한다.</p>
<ul>
<li>Decoder</li>
</ul>
<p>→ Encoder의 RNN을 쌓은 것이고 각 Time Step에 대해서 예측을 한다.</p>
<h1 id="deepar">DeepAR</h1>
<h1 id="introduction">Introduction</h1>
<p>최근에 다량의 서로 연관된 Time Series를 예측하는 문제가 대두 됐다.</p>
<p>예를 들어 거대한 retailer에 의해 제공되는 모든 상품들에 대한 수요 예측 등이 있다</p>
<p>이러한 예제에서는 유사한 종류의 Time Series가 예측에 영향을 미칠 수 있다.</p>
<p>유사한 종류의 Time Series Data를 사용하는 것은 과적합 없이 모델을 더욱 Flexible하게 Fitting할 수 있고 Neural Network를 사용하면서 Classical Technique 들에서 요구됐던 feature engineering과 model selection 과정을 덜 할 수 있다</p>
<p>DeepAR은 LSTM기반의 모델로써,  확률분포를 추정하는 것을 목표로 한다. 우리는 일상생활에서 다음과 같은 분포를 일반적으로 볼 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/424afc92-d1f6-4d1e-8b79-e8cd655ded13/image.png" alt=""></p>
<p>Sales 예시에서의 분포로써 많이 말리는 물건은 극소수 이고 적게 팔리는 물건이 매우 많다는 것이다.</p>
<p>이 논문의 메인 Contribution은 다음과 같다.</p>
<blockquote>
<p>💡  <strong>Effectiveness of Deep-learning for Time Series</strong>
→ 확률분포를 근사하는데 여러 확률분포를 포함하는 RNN Architecture를 제안한다. 이 모델은 여러 다른 스케일을 가지는 데이터를 효과적으로 다룬다.<br>
→ 여러 Real World Data에 대해 이 모델이 정확함을 보여줌으로써 시계열에 대한 Deep Learning based Approach가 충분히 효과적임을 보여준다.</p>
</blockquote>
<h2 id="model">Model</h2>
<p>시점 t에서 시계열 i의 값을 $z_{i,t}$ 로 하자
우리의 목표는 각 시계열 i에 대해서 conditional distribution( conditional probability function)을 구하는 것이다
다음과 같이 notation을 정의 한다
<strong>[Future]</strong>
$[t_0 , T]$ : prediction Range</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/dbe07d9a-dfba-41f0-9d04-6260e87c3010/image.png" alt=""></p>
<p><strong>[Past]</strong>
$[1 , t_0-1]$ : Conditioning Range</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/003da9a3-3f83-4da9-9af3-0c35cd78c3aa/image.png" alt=""></p>
<p><strong>[Covariates]</strong>
$X_{i,T}$ : 우리는 Covariates를 모든 시간 범위에 대해 알고 있다고 가정한다</p>
<p>우리의 모델은 RNN 구조의 network architecture이고 우리는 모델의 예측 확률 분포를 likelihood factor의 곱으로 가정한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/fb7c8c5d-9255-45e0-b875-52b563cf6060/image.png" alt=""></p>
<blockquote>
<p>likelihood function
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/eab03419-df5f-4b9b-b9d4-dcae8347b8c8/image.png" alt="">
log likelihood function
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/5c475176-8e0d-4e40-9cf1-e7edb4864cf6/image.png" alt="">
표본 데이터(sample)를 모두 평균 값으로 지정해 likelihood 값을 계산하고 likelihood가 가장 큰 지점을 찾는다. 이렇게 찾게된 지점은 데이터와 제일 잘 맞는 모델과 추정치를 계산할 수 있게 된다.<br>
likelihood function을 세타에 대해 편미분하고 그 값이 0이 되도록하는 세타를 찾는 방식으로 추정을 진행한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/11d8eb50-7f8a-4425-ab61-166804a207c1/image.png" alt=""></p>
</blockquote>
<p>여기서 $h_{i,t}$ 는 각 time에 대한 RNN의 출력값이다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/79771ca2-17e7-4e7a-957a-c0ec9d9a3e7f/image.png" alt=""></p>
<p>여기서 h는 LSTM cell을 갖고 있는 multi-layer RNN(Layer개수가 3개 number of hidden units(hidden unit의 dimension)는 작은 건 40개 큰 것은 120개) 에 의해 구현된 함수이다</p>
<p><strong>Training</strong></p>
<p>Train과 prediction의 Figure는 다음과 같다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/86ae251c-6473-4e16-a5a4-a02b50f98c23/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/faf479f8-fbca-4a7c-9e40-a83d178f9438/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/0d30e9d5-8751-4980-8d07-b57fbf8481d9/image.png" alt=""></p>
<p>이 architecture 뒤에 있는 아이디어는 직관적이다:
여기서의 목표는 each time step의 분포에 대해 예측하는 것이다. 이것은 network 가 이전의 관찰값($z_{t-1}$)을 optional covariates인 $x_i$ 와 함께 input으로 받아야 한다는 것을 의미한다.
( 그 시점의 관찰 값을 추정하는 것이기 때문이 한 타임 이전 스텝의 값을 받는다.)
그 정보는 hidden layer로 전파된다. 여기서는 loss function대신 objective function으로 likelihood function을 사용한다 likelihood function은 Gaussian 이거나 Negative Binomial 일 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/415c7417-d003-4d90-9749-2b1334a9ef42/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/381956d0-ac94-4324-9655-c88b3e02de4f/image.png" alt=""></p>
<p>우리는 아래의 Objective Function의 stochastic gradient descenting을 통해 RNN의 h(<strong>·</strong>)에 구성된 가중치 <strong>𝛩</strong>뿐만 아니라 위의 $\theta$(<strong>·</strong>)의 가중치 또한 갱신할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/da248f05-3030-4518-9dfc-65c8602244a3/image.png" alt=""></p>
<p>t = $t_0$<del>$T$ : prediction의 모든값
i = 1</del>N : 모든 Time Series</p>
<p>우리는 물건 데이터 집합의 <strong>각 시계열에 대해 원래 시계열과는 다른 시작점을 선택</strong>해서 여러 개의 Training Instance를 생성한다. 
이때 전체 길이 T뿐만 아니라 모든 Training Instance에 대해 conditioning range의 길이와 prediction range의 길이를 같게 설정한다</p>
<p>예를 들어, 주어진 시계열의 총 사용 가능 범위가 2013-01-01부터 2017-01-01까지일 때 우리는 training example을 1일 단위로 생성해서 2013-01-01, 2013-01-02, 2013-01-03 이런 식으로 생성할 수 있다.
이때 training window는 우리의 ground-truth-data를 prediction window가 포함하도록 생성 해야 한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f687c8e9-8a73-4f61-96a3-6fe883b4c4ec/image.png" alt=""></p>
<p>그러나 우리는 시계열 데이터 시작 전 값인 2012-12-01이 시작점으로 선택 할 수도 있다 이러한 관측되지 않은 target값은 0으로 채운다. 이러한 과정으로 인해 새롭게 나타나는 시계열의 행동에 대해 학습할 수 있도록 한다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/30c2b349-c889-440f-a215-9e48eb7bbd51/image.png" alt=""></p>
<blockquote>
<p>💡 “Ground-Truth”는 &#39;우리가 정한 정답’,’우리의 모델이 우리가 원하는 답으로 예측해주길 바라는 답’이다.</p>
</blockquote>
<p>By augmenting the data using this windowing procedure, we ensure that information about absolute time is only available to the model through covariates, but not through the relative position of z_i,t in the time series</p>
<p><strong>prediction</strong></p>
<p>우리는 encoding과정에서 마지막으로 얻은 cell state값을 prediction의 초기값으로 설정하고 encoding에서 얻은 마지막 output값을 prediction의 초기 관측 값으로 설정한다</p>
<p>이제 미래를 예측할 시간이다: 유념해야 할 것이 우리가 매 time step에서 얻는 예측은 distribution인 것을 기억해라 우리는 첫번째 timestep에서 output distribution으로부터 하나의 sample 뽑음으로써 시작한다 여기서 뽑은 sample은 두번째 time step에서의 input이 되고 and so on.</p>
<p>이렇게 만들어낸 Objective function을 Backpropagation을 통해 최적화를 진행한다</p>
<p><strong>Problem</strong></p>
<p>우리가 일상에서 쉽게 볼 수 있는 Power-law distribution을 보이는 data에 모델을 적용하는 것은 두가지의 문제점이 있다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/02c87ac7-d24e-428e-8601-0b39c1a10d6c/image.png" alt=""></p>
<h3 id="scale-problem">Scale Problem</h3>
<p>첫째로 모델의 autoregressive 속성 때문에 input과 output이 observation $z_{i,t}$의 scale에 직접적으로 영향을 받는다 따라서 이를 input layer에서 적절히 scale 해주고 output layer에서 다시 inverse 해주는 방법을 사용한다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b489ee21-6db7-445a-8cc6-f5dda4fc7286/image.png" alt=""></p>
<p>여기서 그럼 $||z||$는 무엇이냐? 
이는 item-dependent scale factor $v_i$ 로 scale을 하는데 예를 들어 negative binomial likelihood function에는 다음과 같이 scale 해준다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/2049e62a-eb05-4443-a6ca-86e6800bcb79/image.png" alt=""></p>
<p>이 논문에서는 $v_i$를 heuristic하게 선택한 average value로 scale을 해봤는데 모델의 성능이 괜찮았다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/a8a77618-23c4-4d25-b3d3-bdca241b3fc7/image.png" alt=""></p>
<h3 id="unbalanced-data">Unbalanced Data</h3>
<p>두번째로 대부분의 상품이 적게 팔리고 아주 극소수의 상품만이 많이 팔리는 데이터의 불균형 때문에 training instance를 random하게 뽑아버리면 많이 팔리는 극소수의 상품이 뽑힐 확률이 매우 적고 결국 모델이 underfitting 될 가능성이 있다 이는 demand forecasting에서 많이 팔리는 상품을 더 잘 예측하는 것이 business 측면에서 유리하기 때문에 non uniform하게 데이터를 선택해야한다</p>
<p>따라서 위에서 구한 $v_i$ 를 이용해서 $v_i$ 가 큰 Product가 더 잘 뽑히도록 확률을 크게 조정했다.</p>
<h3 id="result">Result</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e799aef4-ac02-436a-8257-f607d295a606/image.png" alt=""></p>
<p>이 결과에서 중요한 것은 이전의 데이터가 거의 없고 거의 안 팔리는 것도 어느정도 잘 맞추는 걸 볼 수 있다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/16f62728-3edb-4549-89e1-12ced34acfef/image.png" alt=""></p>
<p>모델의 Forecasting Interval을 보면 미래로 갈수록 더 불확실한 것을 Interval의 크기가 커지는 것으로 보여주고 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Part of XAI(2)[Feature Importance & Permutation Importance]]]></title>
            <link>https://velog.io/@leesungjoon-net/Part-of-XAI2Feature-Importance-Permutation-Importance</link>
            <guid>https://velog.io/@leesungjoon-net/Part-of-XAI2Feature-Importance-Permutation-Importance</guid>
            <pubDate>Wed, 06 Sep 2023 14:59:46 GMT</pubDate>
            <description><![CDATA[<h1 id="feature-importance">Feature Importance</h1>
<p>우선, feature importance에 관해서 알아보자.
먼저 트리 기반 모델들(random forest, xgboost, lightgbm 등)은 기본적으로 feature importance를 API 혹은 모델 내장 함수로 제공한다. 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c47b8834-709f-4d45-b2ee-df5b97f1d738/image.png" alt="">위 그림은 Kaggle의 타이타닉 생존자 예측에서 사용된 Feature Importance 그림이다. 그런데 이렇게 구해진 Feature Importance가 과연 정확할까? 즉, 실제로도 성별이 가장 영향을 많이 미칠까? 실제로는 그렇지 않다. 이를 알기 위해서는, Feature Importance를 구하는 방식을 먼저 알아보겠다.</p>
<p>트리기반 머신러닝 모델에서는 각 Feature별로 엔트로피(Entrophy)[불확실성] 혹은 지니 계수라 불리는 것들을 계산해서 가지치기를 한다. (fit과정)
엔트로피와 지니계수 자체는 이 노드가 얼마나 불균일한가를 측정하고 이를 통해서 얼마나 균일하게 만드는지를 측정하여서 Feature Importance로 사용한다.
<HR></HR>
&lt;엔트로피 &amp; 크로스엔트로피 참고&gt;</p>
<p><a href="https://velog.io/@leesungjoon-net/%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC%EC%99%80-%ED%81%AC%EB%A1%9C%EC%8A%A4%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC-KL-Divergence">MyVelog</a></p>
<p><strong>엔트로피</strong>
먼저, 직관적인 이해를 위해 물리공부를 했을때를 떠올려보면 엔트로피라는 말은 불확실성과 동치인 말이었다. 이를 그대로 생각해보면, Tree에서 분류하는 과정에 있어서 적절한 Feature를 사용해서 분류를 하는 경우에는 잘 분류가 될 것이고, 이는 곧 불확실성이 낮게 나오게 된다.
그렇다면 얼마나 불확실성이 낮아졌을까? 라는 말은 -&gt; 정보를 얼마나 얻어서 불확실성이 낮아졌을까? 로 대치가 되고, 이것이 의미하는 것이 바로 정보이득(Information Gain)[IG]이다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/89c4af86-5a19-4259-9359-810ce0bca5f6/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/cf731b45-0655-4ebe-af97-4879ed1aeba1/image.png" alt=""></p>
<p><strong>지니계수(Gini Index)</strong>
지니계수는 얼마나 Impure한지를 측정하는 지표이다. 따라서 지니지수가 0 이라면, 이는 해당 클래스가 모두 ‘같은 Class’ 이기 때문에, 아주 Pure한 상태를 말하는 것이고 가장 Impure한 상태는 당연히 절반 절반 클래스가 섞여있을때이고 이때의 지니계수는 1/2 이다.
Gini Index는 다음과 같이 계산한다. Gini Split은 분기하는 기준을 정하기 위해서 사용하는 지표이다. [자식 노드의 Gini Index를 weighted sum을 취한다.]</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b2f813b9-7c74-403d-b77c-d443850228c6/image.png" alt="">
C 는 클래스의 총 개수</p>
<p>아래의 예시를 확인해보자</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/182fe7bd-7bd1-47b0-b7a5-feb5239e46ee/image.png" alt=""></p>
<blockquote>
<p>정보이득 그리고 Gini Split을 이용해서 트리를 분기함을 알 수 있다.</p>
</blockquote>
<p><a href="https://bigdaheta.tistory.com/26">참고1</a>
<a href="https://bigdaheta.tistory.com/27">참고2</a>
<a href="https://velog.io/@claude_ssim/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A7%88%EC%9D%B4%EB%8B%9D-Decision-Tree-Measures">참고3</a>
<HR></HR></p>
<p>우리는 위와 같이 불확실성을 낮추는 방향으로 노드를 이어나간다. 이때 위에서 구한 다양한 측도(measure)를 이용해서 우리의 Feature Importance를 구하는 방법은 MDI와 같은 것들이 있다.</p>
<h3 id="mdimean-decrease-impurity">MDI(Mean Decrease Impurity)</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/f8f2485a-b65f-40da-82d1-b225d7a47da0/image.png" alt=""></p>
<p><strong>MDI(Mean Decrease Impurity)는 감소분[Information Gain, Gini_split]의 평균을 중요도로 정의하는 것이다.
아래의 그림처럼 차이를 구한이후 앙상블의 전체 tree에서 해당 Feature를 포함하는 수 만큼 다 더한이후, 그것을 평균낸다</strong></p>
<p>MDI의 장점: 빠르고 직관적
MDI의 단점: 여러종류(high cardinality)를 갖는 범주형 Feature는 트리가 분기될 때 이용될 확률이 높다.(why? /Self answer-&gt; 여러종류 범주이면 정보이득이나 gini 계수의 차를 계산하는 과정에서 빠지는 것이 많기 때문에 좀더 변화의 크기가 커져서 이용될 확률이 높다) 그래서 전체적인 일반화보단 범주가 많은 Feature에 대해서 과적합을 일으키기 쉽고, 따라서 Pure하게 구분될 확률이 높아 빠지는 값이 적어 Δi(t) 값이 높게 나온다.(&lt;-&gt; Feature Importance가 높게 나올수 있다) 따라서 이 경우 잘못된 해석이 되지 않도록 조심하여야 한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/88e51e60-37ea-4a9e-b1a0-08ffd0a32186/image.png" alt="">
<a href="https://velog.io/@73syjs/%ED%8A%B9%EC%84%B1-%EC%A4%91%EC%9A%94%EB%8F%84Feature-Importances">참고</a>
<a href="https://medium.com/the-artificial-impostor/feature-importance-measures-for-tree-models-part-i-47f187c1a2c3">참고2</a></p>
<h1 id="permutation-importance">Permutation Importance</h1>
<p>Permutation Importance는 이전에 SHAP/LIME에 비해서 개념이 쉽다. 또한, LIME과 SHAP과 달리 모델의 Feature에 대한 전역설명을 위해서 검증 데이터의 특정값을 무작위로 섞어서 중요도를 계산한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/5e87beac-ec75-41f6-85cc-a368fba8994b/image.png" alt=""></p>
<p>위와 같이 Feature의 값을 무작위로 섞는다. 이렇게 뿔뿔이 흩어진 Feature 값은 모델에서 Noise처럼 도움이 되지 않는다. 만약 위에서 처럼 섞었는데 예측 오차가 증가할경우, 예측은 이 Feature에 의존함을 알 수 있다. 꽤나 직관적인 설명이다.</p>
<p><a href="https://www.kaggle.com/code/dansbecker/permutation-importance">https://www.kaggle.com/code/dansbecker/permutation-importance</a>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/60ca6030-962c-430e-8f22-fd0d63988355/image.png" alt="">
하나씩 설명 해보겠다.<span style="color:blue">(L: 손실함수 E: 평균(앙상블 전체의 평균을 의미)</span>
(1)    먼저, 기본적인 베이스라인 예측 오차를 계산한다.
(2)    Randomly shuffle 한 예측 오차를 계산한다
(3)    이둘을 비율로써 나타낸다.
(4)    (1)~(3)의 계산을 모든 Feature에 대해서 수행해 모델 f의 Feature Importance를 출력한다</p>
<p><strong>장점</strong></p>
<ul>
<li>직관적으로 단순하다 -&gt; 단순한 표현 방식으로 이해하기 쉽다</li>
<li>일관된 Feature의 중요도 </li>
<li>재학습 불필요 -&gt; 모델의 재학습이 불필요하고 중요도를 고속으로 산출할 수 있다.</li>
</ul>
<p><strong>주의할점</strong></p>
<ul>
<li><strong>정렬의 무작위성에 의존한다.</strong> -&gt; 계산을 반복해서 평균을 구한다면 안정된 결과를 얻을 수 있지만 그만큼 시간이 길어진다.</li>
<li><strong>동일 성향을 가진 Feature에 의해 보충된다</strong> -&gt; Multicollinearity[다중공선성]에 영향을 받아 오차를 완화시켜 중요도가 낮게 산출될 수 있다.</li>
<li><strong>주효과와 상호작용 효과를 구분할 수 없다</strong> -&gt; Feature Importance를 산출할 때 예측값을 사용하기 때문에 <strong>다른 Feature들의 상호작용으로 randomly Shuffle을 시킨 Feature의 효과를 낼 수도 있다</strong></li>
</ul>
<blockquote>
<p>다음 포스팅인 IG는 논문을 딥하게 읽었기에 Paper Review와 이곳 두곳에 올리겠다 !</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Part of XAI(1)]]></title>
            <link>https://velog.io/@leesungjoon-net/Part-of-XAI1</link>
            <guid>https://velog.io/@leesungjoon-net/Part-of-XAI1</guid>
            <pubDate>Wed, 06 Sep 2023 13:51:50 GMT</pubDate>
            <description><![CDATA[<h1 id="이-글의-references">이 글의 References</h1>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/52191f3e-ad41-4934-bb4f-b5a66d0be407/image.png" alt="">
XAI관련 Velog는 XAI를 공부하기 위해서 위의 책을 참고하고자 했는데, 너무 제한적인 설명때문에 구글링을 찾아봤고 일부는 직접 논문을 읽었다.
시작하겠다.</p>
<h1 id="introduction">Introduction</h1>
<p>XAI는 Explanable AI로써 우리는 딥러닝 모델들의 결과가 왜 이렇게 나온건지에 대한 설명을 할 수 없었다. 이러한 문제를 해결하기 위해서 나온 기술이고 파이썬의 XAI 라이브러리인 LIME과 SHAP등을 안내할 것이다.
책을 통해 얻을 수 있는점</p>
<p>&rightarrow; AI의 책임성
&rightarrow; AI를 어떤 업무에 적용할 때 어떤 설명이 필요한지
&rightarrow; XAI의 전역 설명과 국소 설명을 구분해 사용 가능
&rightarrow; XAI의 목표와 작동원리를 수식으로 파악하고 주요기법의 장단점 및 다루는 데이터나 풀어야할 Task에 따른 모델의 성능 차이
&rightarrow; 어떤 Task가 갖는 데이터의 특성, AI알고리즘, 성능 요건등에 따라 적절한 XAI기술 선정</p>
<h1 id="11----ai-보급과-새로운-요구-사항">1.1    AI 보급과 새로운 요구 사항</h1>
<p>AI 활용의 대상인 ‘인식’과 ‘분류’ ‘예측’이라는 요소에서 지금까지 중요하다고 여겨진 것은 바로 “정확도” 였다. 하지만 지금에 와서는 AI에 정확도 이외의 가치도 요구되기 시작됐다.
우리는 AI의 발전으로 인해서 일자리가 대체될 것이라고 말을 해왔지만 실제로 그러한 일은 거의 발생하지 않았다. 왜 그럴까? 그 이유를 저자는 다음과 같이 설명한다.
먼저 대전제는 AI도 일종의 소프트웨어이다. 우리는 다른 소프트웨어는 Input에 대한 Output값을 추적을 통해 설명할 수 있다. 하지만 AI는 데이터를 통한 “학습”에 의해 이 데이터도 이전의 학습한 Boundary안에서 찾는 것이다. 따라서 역추적하기가 어렵다. AI는 일종의 패턴을 학습하는 것이라고 볼 수 있기 때문에, 학습 데이터에 맞추어서 유연한 처리 방법을 학습 할 수 있기 때문에, 사람의 업무에 AI를 적용하는 경우가 늘어난다. <span style="color:red">하지만 우리의 의사결정에 AI가 관여하는 것에 대해서 출력결과의 공평성이나 윤리적 타당성이 요구되고 있다.</span>
AI의 활용의 확대에 따라서 요구되는 가치는 3가지가 있다</p>
<ul>
<li>Fairness(공평성)</li>
<li>Accountability(책임성)</li>
<li>Transparency(투명성)<h1 id="2장-xai의-개요">2장 XAI의 개요</h1>
<h2 id="21-xai란-무엇인가">2.1. XAI란 무엇인가?</h2>
XAI는 어떠한 특정 기술이나 도구를 지칭하는 말이 아니고 다양한 종류의 AI를 다양한 관점에서 이해한다는 목적을 위해 개발된 기술이나 도구들을 총칭하는 말이다.</li>
</ul>
<h2 id="22-설명-가능한-ai-explanable-ai와-해석-가능한-aiinterpretable-ai">2.2 설명 가능한 AI (Explanable AI)와 해석 가능한 AI(Interpretable AI)</h2>
<p>$InterpretableAI⊂XAI$
<strong>설명가능한 AI(Explanable AI)</strong></p>
<ul>
<li>AI 모델의 내부를 정교하게 해석할 필요는 없고, AI가 도출한 결과에 대한 이유를 설명하는 기술을 나타낸다.
Ex) 
데이터의 어떠한 부분이 중요한가? 
판단 기준이 되는 요소에는 어떠한 것이 있는가?</li>
</ul>
<p><strong>해석가능한 AI(Interpretable AI)</strong></p>
<ul>
<li>위에 설명가능한 AI와는 다르게 내부구조를 해석함으로써 예측에 이르는 계산 과정을 확인할 수 있는 AI
EX)
고전적인 의사결정 트리</li>
</ul>
<h2 id="23-xai의-설명-범위에-따른-분류">2.3. XAI의 설명 범위에 따른 분류</h2>
<p>XAI를 활용한 AI의 설명은 설명 범위에 따라 구분된다.</p>
<p><strong>전역 설명(Global Explanation)</strong></p>
<ul>
<li>AI 모델의 전체적인 동작을 이해하는 것을 목적으로 하는 설명 방법이다.
&rightarrow; 하나 하나의 데이터에 대한 예측과정을 설명하는 것이 아니고, General하게 나타나는 AI 내부의 지배적인 경향을 나타낸다.
Ex&gt;<span style = "color:blue"><ol>
<li>Feature 별 예측에 대한 중요도 산출</li>
<li>AI의 logic을 가시화</span></li>
</ol>
</li>
</ul>
<p>위의 예시와 같은 Global Explanation에 따른 AI의 이해는 모델 자체의 평가나 학습 개선을 야기한다.</p>
<p><strong>국소 설명(Local Explanation)</strong></p>
<ul>
<li>어떠한 데이터에 대한 예측 결과를 설명하는 것이다.
Ex&gt;
구체적으로 어떠한 사례에 대한 AI의 예측 데이터에 기록된 몇 개의 변수에 대해 각 예측 확률을 어느 정도 높이냐에 따라 ‘기여도’를 산출해 예측의 판단 결과를 설명한다.</li>
</ul>
<blockquote>
<p>전역설명의 ‘Feature별 예측에 대한 중요도 산출’과 국소 설명의 ‘예측 데이터에 기록된 변수의 기여도를 산출’의 차이 ?
&rightarrow; 다르게 생각해보면 전체 데이터에 대해서 기여도 산출 &lt;-&gt; 전역설명
일부 데이터에 대해서 기여도 산출 &lt;-&gt; 국소설명</p>
</blockquote>
<h2 id="24----xai의-설명-방법에-따른-분류">2.4.    XAI의 설명 방법에 따른 분류</h2>
<p><strong>1.    Feature를 활용한 설명</strong></p>
<ul>
<li>어떤 입력 데이터에 대해 Feature가 예측 결과에 어느 정도 영향도가 있는지를 산출</li>
<li><span style = "color:blue">이는 데이터의 종류에 따라 표에서는 중요한 Feature를 표시하는 방식으로 이미지에서는 중요한 부분을 marking 하는 방식으로 나타날 수 있다.</span></li>
<li>E.g.) 허스키와 늑대의 사진을 보고 눈을 보고 판단을 했다~.. 와 같이 눈 부분이 marking된 경우</li>
</ul>
<p><strong>2.    판단 규칙을 활용한 설명</strong></p>
<ul>
<li>EX&gt; 의사결정트리</li>
<li>인간이 이해할 수 있을 정도의 규칙의 수여야 한다.</li>
</ul>
<p><strong>3.    학습데이터를 활용한 설명</strong></p>
<ul>
<li>이는 이미지 데이터를 기준으로 이해하면 좋다.</li>
<li><span style = "color:blue">여러 이미지 학습데이터가 주어질텐데, 가장 많이 참고한 학습데이터를 제시함으로서 판단 이유의 설명으로 나타낸다</span></li>
<li>Effect) 예측에 악영향을 미치는 학습 데이터를 제거할 수있다</li>
</ul>
<h2 id="25----모델-의존성">2.5.    모델 의존성</h2>
<p>모델 의존형 XAI와 모델 불문형 XAI</p>
<p>모델 의존형 XAI는 <span style = "color:blue">특정 모델을 설명하는 XAI로써 모델의 구조를 활용하여 설명할 수 있고</span></p>
<p>모델 불문형 XAI(model agnostic XAI)는 대상 모델의 제약이 없어 모델에 상관없이 어떤 데이터가 입력됐을 때 어떤 예측이 나오는지 관계성을 파악하도록 한다.</p>
<p>따라서 모델의 상관없이 일괄적으로 설명할 수 있지만, 모델의 구조를 사용하지 않기 때문에 모델 의존형 XAI보다는 합리적인 설명을 할 수 있는 가능성이 떨어지게 된다.</p>
<h1 id="3장-xai의-활용-방법">3장 XAI의 활용 방법</h1>
<h2 id="31-설명-범위별-활용-방법">3.1. 설명 범위별 활용 방법</h2>
<h3 id="국소설명local-explanation">국소설명(local explanation)</h3>
<p><strong>1. 신고 내용의 타당성 검증</strong>
Ex) 화물의 신고서를 AI가 검토한다고 했을 때, 우리는 화물에 대해 신고품목의 종류, 중량, 부피등의 데이터를 AI에게 제공할 수 있다. 이때 종류, 중량, 부피중에서 거절에 중요한 순서로 나열해서 손님에게 제공할 경우 거절을 설명할 수 있다.
각 손님마다 중요한 순서가 다르기 때문에, local explanation이다.</p>
<p><strong>2. 의도와 다른 학습 재검토</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7eb4e7a9-b007-481a-aedb-8e4c646f1b8c/image.png" alt=""></p>
<p>위에 사진을 보면 그림은 허스키인데 AI모델이 늑대로 잘못 분류한 상황이다. 이때, 그렇게 분류한 이유를 설명한 그림이 b인데 배경의 눈을보고 이 그림이 늑대라고 분류한 것이다. 
이는  <span style = "color:blue">데이터의 불균형에 의한 문제라고 볼 수 있고, 이것이 바로 ‘의도와 다른 학습’이다.</span>
또한, 올바르게 분류 혹은 예측을 수행했더라도 XAI를 통해 나온 그 이유가 도저히 말이 안되는 이유가 제시 된다면 바로 잡아야 한다</p>
<h3 id="전역-설명global-explanation">전역 설명(global explanation)</h3>
<p><strong>1.    AI 모델의 개선 운용</strong>
실제 시스템에 적용되는 AI 모델에는 지속 운용을 위한 유지보수가 필요하다.
구축할 당시에는 최적의 상태로 AI모델이 세팅이 되겠지만, 데이터의 경향(Trend)의 변화가 생기거나하면 정밀도에 문제가 생길 수 있다.
따라서 모델의 지속 운용을 위한 유지보수가 필요하게 되는데, 이러한 유지보수간에 모델의 예측을 설명할 방법이 없다면, 모델의 개선을 할 수가 없기 때문에 XAI를 활용하게 된다.</p>
<p><strong>2.    적대적 공격 검증</strong>
현재 AI에서 특히 우려가 되고 있는 문제중 하나가 적대적 공격(Adversarial Examples)이 있다.
적대적 공격 이란?
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/501910ba-3611-41c1-8659-7cdb9f9c26cc/image.png" alt="">
팬더의 이미지에 노이즈를 더하니깐 긴팔 원숭이로 인식하는 것을 볼 수 있다. 위와 같이 AI의 오인식을 유도하는 방법을 적대적 공격이라고 한다.
또다른 예로써 노이즈를 더함으로써 강아지를 물고기로 잘못 인식하는 사례가 있다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/598be9af-047f-4850-bdb5-7ef235268128/image.png" alt="">
위의 사진을 설명해보자면 우리는 파란색 박스의 강아지를 물고기로 예측하도록 하게 하기 위해서 노이즈를 더해서 물고기로 예측을 하도록 하니, 아래 빨간색 박스 위의 강아지들이 모두 물고기로 예측이 됐음을 볼 수 있다.</p>
<p>우리는 위와 같이 XAI를 통해 적대적 공격을 재현하고 파란색 박스의 이미지가 중요한 역할을 담당하고 있다는 사실을 알 수 있고, 이를 통해 적대적 공격에 대비할 수 있게 한다.</p>
<h1 id="다양한-xai-기술">다양한 XAI 기술</h1>
<h2 id="limelocally-interpretable-model-agnostic-explainations">LIME(Locally Interpretable Model-agnostic Explainations)</h2>
<p>👉🏻 LIME은 전체적인 모델의 예측에 대해 분석하지는 않는다. 어떠한 설명 대상 데이터 1건에 대해 AI모델의 예측에 기여한 Feature들의 기여도를 산출한다. local explanation</p>
<p>👉🏻 LIME은 Model Agnostic하다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b7e0c3a4-8d48-4ce9-b3b0-0a672e6f4500/image.png" alt="">
왼쪽 그림과 같이 positive인 부분과 negative인 부분의 경계는 매우 복잡해서 설명할 수 있는 가능성이 떨어진다. 이때, 우리는 설명 대상 데이터를 포함한 Local한 부분(오른쪽 영역)만 관찰하겠다는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/a18a8154-1e35-4023-9b4b-63982cd3c777/image.png" alt="">
왼쪽 그림과 같이 노란색 Point들을 다수 작성해서 우리의 AI 모델을 이용해 이 노란색 포인트들을 예측(위의 그림에서는 분류)를 수행한다. </p>
<p><strong>AIM: 우리의 목표를 다시한번 상기하자면 저 보라색 Point를 우리의 모델이 예측하는 결과가 왜 그렇게 나오는지 이유를 제시하는 것이 목표이다. -&gt; 이를 위해 선형모델을(surrogate model)을 구하는 것이 목표이다.(해석을 위한 대리모델 = surrogate Linear model)</strong></p>
<p>위와 같은 AIM때문에 우리는 Local한 영역을 잡았고, 임의의 point를 생성한것이다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/9b24e73b-6e8f-4ace-8b57-a47f82a9aacd/image.png" alt=""></p>
<p>우리는 위에서 언급한 surrogate model을 구하기 위해서 위와 같은 수식을 Loss Function으로 사용하게 됐다.
위에 오메가 Term은 regularization term으로써, Ridge 회귀를 사용한다</p>
<p>위의 수식을 이해하려면, L term이 의미하는 것을 이해해야하는데,
우리의 데이터 구조가 Feature1, Feature2에 대해서 각각이 연령, 거주지를 의미하고 설명 대상 데이터 x = (20대,서울) 이라고 해보자
이때,<span style = "color:red"> 설명 대상 데이터 근방에 있는 생성 데이터들의 Set을 의미하는 것이 바로 Z이고 </span>
여기서 나온 원소들을 z <span style = "color:red">이러한 z를 모델 g에 넣을 수 있도록 변화시킨( ex&gt; z=(20대, 부산) -&gt; z’=(1,0) ) 벡터가 바로 z’이다.</span>
따라서 해석을 해보자면 우리의 모델로 예측한 것과 surrogate 모델이 예측한 것의 차의 제곱이고, 그 앞에 곱하는<span style = "color:red"> $π_x (z)$ 는 생성한 데이터 z와 설명 데이터 x사이의 거리를 나타낸다.</span></p>
<p>위와 같은 Loss Function을 이용해서 우리는 surrogate model인 g를 구할 수 있게 됐고, <span style = "color:red">이는 Linear model이므로 회귀계수가 Feature에 대한 기여도가 되게 된다.</span></p>
<blockquote>
<p>기본적으로 XAI에서 Linear모델은 계수로써 설명이 가능하다는 것이 전제로 깔려있다.</p>
</blockquote>
<p><a href="https://myeonghak.github.io/xai/XAI-LIME(Local-Interpretable-Model-agnostic-Explanation)-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/">참고</a></p>
<h2 id="lime의-데이터-종류별-동작원리">LIME의 데이터 종류별 동작원리</h2>
<p>우리는 위에서 근방의 데이터를 통해 surrogate model을 만들었음을 알 수 있다. <span style = "color:red">따라서 근방의 데이터를 어떻게 생성하는지 위주로 설명하겠다.</span></p>
<h3 id="테이블-데이터-lime의-경우">테이블 데이터 LIME의 경우</h3>
<ul>
<li>테이블 데이터 같은 경우는 학습 데이터를 LIME에 사전에 입력하고 학습 데이터의 통계적인 계산 정보를 바탕으로 값을 생성하는데, <span style = "color:red">이때 Feature의 전체 도메인에 무작위로 데이터를 생성하고, 설명 대상 데이터와의 거리가 가까운 데이터를 중요시하도록 해서 실질적인 근방 데이터를 만들게 된다.</span></li>
</ul>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/1d7f490d-6baf-4e4a-89a5-d62623180334/image.png" alt=""></p>
<p>위 그림과 같이, 설명하고자 하는 데이터가 노란색 포인트이고 그 외의 검은색 포인트가 추출된 근방 데이터이다. <span style = "color:red">이중에서 가까운 데이터들에 가중치를 크게줘 (포인트의 크기를 키워서) 실질적인 근방데이터를 만들게 된다.</span> 이때 어디까지가 의미있는 이웃이냐? 라는 것을 정하는 것이 이슈인데, LIME은 현재 지수 평활 커널(exponential smoothing kernel)을 사용하여 이웃을 정의한다. 평활 커널은 두개의 데이터를 받아서 데이터간의 유사도(similarity)[실제 블로그에서는 근접성 측도 proximity measure 로 언급]를 반환하는 함수이다. 이때 커널 너비는 이웃의 크기를 결정하는데, 이 커널너비의 적절한 크기가 Issue가 된다.</p>
<p><span style = "color:red">** &rightarrow; 커널너비가 작으면 매우 근접해야 영향을 줄수 있고, 폭이 더 크면 멀리있는 인스턴스도 모델에 영향을 미친다.**
</span></p>
<h3 id="이미지-데이터-lime의-경우">이미지 데이터 LIME의 경우</h3>
<ul>
<li>이미지 데이터 같은 경우는 보통 픽셀 단위의 RGB 값을 사용하여 AI 모델에 입력하곤 한다. 하지만 픽셀 단위로 XAI를 적용하게 되면 계산양이 매우 방대해지고, 얻을 수 있는 설명의 결과도 픽셀 단위에선 유의미 하지 않다.
따라서, 이미지 데이터 LIME에서는 세그먼트 라는 영역으로 분할해 세그먼트마다의 모델의 판정 기여도를 산출한다.[책에 따라선 세그먼트가 super pixel로 언급이 돼있다] 이 세그먼트 영역에서는 동일한 정보를 가지고 있다고 간주한다.</li>
<li>근방 데이터의 생성은 세그먼트 단위에서 이미지를 삭제함으로써 생성하는데, 통상적으로 백색이나 흑색, 이미지의 평균값등으로 덧칠하여 해당 세그먼트의 특징을 무효화함으로써 삭제한 것으로 취급한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/d2923b2b-4f75-44a6-8bcf-e17012273469/image.png" alt="">
위의 이미지에서 비슷한 색상을 갖은 픽셀들을 연결해서 선을 구성하고 이해단위를 구분한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7e080a8d-2d54-416b-9dd5-7f1a2ff2c9c5/image.png" alt="">
위와 같이 구분을 시킨후 경우의 수를 따져서,
$x_i^{&#39;}$ : 슈퍼픽셀 마스킹 정보(슈퍼픽셀을 포함시키냐, 포함시키지 않냐)
$w_i$ : 슈퍼픽셀의 가중치(영향의 정도)</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/d65586e8-5de1-40b7-9478-e2478a53e32b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/2f11e408-2d82-4320-8864-d4e63f3483c5/image.png" alt=""></p>
<p>위의 그림에서 손실함수 L을 최소화 하는 슈퍼픽셀의 조합을 구한후 각 슈퍼픽셀에 대한 가중치를 사용해서 얼만큼의 중요도를 갖는지 파악할 수 있다.</p>
<h3 id="텍스트데이터-lime의-경우">텍스트데이터 LIME의 경우</h3>
<p><del>위에 두 종류의 데이터에 비해서는 이해의 정도가 그렇게 높지 않다.</del>
이 텍스트데이터의 경우에는 블랙박스 모델[설명대상모델]을 의사결정나무를 사용한다.
텍스트 데이터 LIME에서는 하나의 문장에서 일부 단어를 빼고 예측을 함으로써 각 단어가 미치는 기여도를 분석한다. 예를 들어서 유튜브의 댓글을 스팸인지 아닌지 분류하는 경우를 생각해보자.[이때 각 단어를 포함하면 1 빼면 0으로 마킹했다.]</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/36e5d976-e205-4776-9f95-312f7a9809d3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/95f6917e-a63c-4ff3-aad6-5d57f632c465/image.png" alt=""></p>
<p>위 식을 이용해서 각 단어를 포함시켰을때와 포함시키지 않았을때를 사용해 weight를 구해서 다음과 같이 특정 단어를 포함할 경우에 spam으로 분류할 확률을 제공한다. </p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/32a83abf-288e-4367-83c8-5d3fdb79b989/image.png" alt=""></p>
<h3 id="lime의-장단점">LIME의 장단점</h3>
<p>장점: 
설명 대상 모델의 종류에 제약이 없다[다른 XAI기술 대부분은 모델이 바뀌면 설명방법도 바뀌어야 한다.]<strong>{Model Agnostic}</strong>
단점:</p>
<ol>
<li>근방 데이터를 무작위로 생성하기 때문에 설명 결과가 매번 달라진다.</li>
</ol>
<p><strong>&rightarrow;    근방 데이터의 생성 수를 늘리면 결과의 불규칙성을 줄일 수 있다.</strong>
2.    하이퍼 파라미터를 조정해야한다.
<strong>&rightarrow; 위에서 언급했듯이 커널크기를 휴리스틱하게 조절해야한다.</strong>
3.    정확하게 설명하지 못하는 경우가 있다.
<strong>&rightarrow; 데이터 구조나 모델 구조상 local한 설명을 잘 하지 못하는 경우가 있다. 하이퍼파라미터를 조절해도 여의치 않다면 다른 방법을 검토!</strong></p>
<h2 id="shapley-value">Shapley Value</h2>
<p>SHAP을 이해하기 위해서는 Shapley Value에 대해서 알아야 한다.
Shapley value는 게임이론에서 나왔다. </p>
<p><span style = "color:red">다만, 어떻게 하면 “기여도에 따라” 공정하게 보상을 나눌까? 를 한번 생각해보면 좋겠다.</span> 물론 n으로 나누는 것도 좋을텐데 이는 바람직하지는 않다. 노력을 한것과 안한것과 보상이 같다면 억울해지는 사람이 있기 때문이다. 따라서 몇가지 바람직한 성질들을 정의 하였는데 다음과 같은 것들이 있다.</p>
<p>여기서 상금을 기여도라고 해석</p>
<p><strong>[한눈에 보기 1]</strong>
<span style = "color:blue">
<strong>Efficiency</strong> – 참가자들의 리워드의 합 = 총 리워드
<strong>Symmetry</strong> – 두플레이어의 기여하는바가 같다면(꼈을 때 예측값이 같다면) 기여도 또한 같음
<strong>Dummy player</strong> – 어떤 플레이어를 끼고 안끼고 결과가 똑같다면, 그 플레이어의 기여도는0
<strong>Linearity</strong> -  기여도는 Linear한 성질이 있음
</span></p>
<h3 id="전체합리성efficiency">전체합리성(efficiency)</h3>
<p>&rightarrow; 분배된 보상(기여도)의 합은 총 보상의 합과 일치한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/723d61d3-b07c-466a-831a-ef98756f1a1c/image.png" alt=""></p>
<h3 id="대칭성symmetry">대칭성(symmetry)</h3>
<p>&rightarrow; 두 플레이어의 기여도가 같다면 두 플레이어가 가져야 할 상금도 같아야한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/09451844-b1f0-420a-af76-128591e7b8d9/image.png" alt=""></p>
<h3 id="위장-플레이어dummy-player">위장 플레이어(Dummy Player)</h3>
<p>&rightarrow; 위장 플레이어(Dummy Player)에게는 보상X
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/8cfb0aef-7a1e-40c0-8b76-4364f88ec094/image.png" alt="">
V가 보상이라고 했을 때, S는 참여를 했다고 한 플레이어들의 집합이고 i는 기여를 하지 않았다고 의심이 되는 플레이어라고 하자. i가 받는 보상은 $SU{i}$가 받는 보상에서 S가 받는 보상을 뺀것과 같을 것이라고 예상된다. 이때, i는 기여를 하지 않았으므로 두 보상은 같게 되고 따라서 $v ^{i} (s)=0$, 즉 i가 받는 보상은 0이 된다.</p>
<h3 id="가법성linearity">가법성(Linearity)</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/263770ab-18ac-4f55-8af4-1730b01eb4c8/image.png" alt="">
수식으로는 다음과 같다.
$ϕ<em>v (i)+ϕ_w (i)=ϕ</em>{v+w} (i)$</p>
<p>위의 4가지 성질을 만족하게 기여도 ϕ 를 측정한 값이 바로 Shapley Value이다. 우리는 이제 Shapley Value(기여도)를 정의해 보겠다.</p>
<p><strong><span style = "color:blue">
위의 4가지 공리를 만족하게 기여도 $ϕ$ 를 측정한 값이 바로 Shapley Value이다.</span></strong></p>
<h3 id="example">Example</h3>
<p>책속에 예시를 토대로 Shapley Value에 대해서 공부해보자.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/483a2e02-a295-4a7f-92b7-e933e96c1222/image.png" alt=""></p>
<p>위 그림과 같이 player 1,2[ General하게는 Feature라고 생각] 할때 player가 참여하고 참여하지 않음에 따른 보상의 정도차이가 있다. 이때, 우리는 위에서 언급한 Shapley Value의 공리에 맞게 사용해서 보상을 나누어 줄 것이다.
Shaley Value의 정의는 다음과 같이 된다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/a716a063-5c7b-4409-89e4-1016de18dd54/image.png" alt=""></p>
<p>식의 뒷 부분은 i가 참여하고 참여하지 않았을 때의 Reward 차이이다[i의주변기여도] 이를 토대로 우리는 i가 미치는 기여도인 $ϕ_i$를 측정하는 것이 목표이다.그렇다면 player1의 기여도를 알아보자
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/92b0b4c3-38d2-4092-ae40-c46cdcabed4a/image.png" alt=""></p>
<p>N은 각 Featuer들의 전체 집합이다. 
위의 예시를 토대로 생각해보면 {player1,player2}이다. 
S는 N에서 측정하고자 하는 녀석을 제외한 부분집합들이다. 우리는 d(S)를 통해 가중평균을 계산하는데, 
이때 확률을 사용한다.[확률의 합은 1이므로]
이에 대한 이해가 가는 설명이 없기 때문에 나의 의견을 쓰자면
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b1fb0e3c-4ae9-498e-8a24-abc9e57fe2e7/image.png" alt="">
위의
$d(s)$를 수정하면 위와 같은 식이 되고, 이를 해석해보면 i를 뽑고, 나머지중에 내가 선택한 S집합을 뽑을 확률이다. </p>
<h2 id="shap-shapley-additive-explanation">SHAP (SHapley Additive exPlanation)</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e4708c03-1294-4d33-ba3d-47dd2bc44fd0/image.png" alt="">
Black Box모델인 f가 있고 이를 바탕으로 한 예측이 있다. 이때, 좀 <span style="color:blue">더 단순화된 입력 x’을 우리가 추정하고자 하는 모델 g에 넣음으로써, surrogate model g를 찾아 가야한다.</span></p>
<h3 id="definition1">Definition1</h3>
<p><strong>Definition1&gt;</strong> <span style="color:blue"><strong>Additive Feature attribution method class</strong></span>
Additive Feature attribution method class는 다음을 만족하는 이진 변수에 대한 선형 Explanation model g를 갖는다.(이때, g는 유일하다는 보장이 없다)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b5d4b0c2-8afd-4aaa-a597-b50197c29d21/image.png" alt=""></p>
<p>각 $z’$은 0 또는 1의 값을 갖고, M은 단순화된 입력 Feature의 개수이다. And $ϕ_i \in R$</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/a0824538-d0ba-42c7-a43f-df26de898cba/image.png" alt=""></p>
<p>논문에서는 4개의 설명 방법론이 위에서 정의한 Additive Feature attribution method에 포함된다는 것을 보인다.
e.g. LIME, DeepLIFT, Layer-Wise Relevance Propagation, Classic Shapley Value Estimation</p>
<p>이 논문에서는 <span style="color:blue">오직 하나의 해를 갖기 위해 가져야 할 조건 3가지</span>를 다음과 같이 제시한다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b9637f8e-2855-4aa6-a8f1-ee5ee021e1bb/image.png" alt="">
한마디로 $ϕ$ 가 Shapley Value의 경우에는 지금부터 언급할 공리들을 만족한다는 말이다.</p>
<h3 id="local-accuracy">Local accuracy</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/9c073277-30d4-4a98-bd50-e5eba6b5fd0f/image.png" alt="">
Original model f를 해석이 쉬운 모델 $g(x’)$을 도입해서 근사하는데, $f(x)=g(x’)$이면 설명력이 높아지면서 예측값과 일치되는 상황이므로 아주 이상적인 상황이다.</p>
<h3 id="missingness">Missingness</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/76acccdd-11e5-4787-92d3-64f1d5684274/image.png" alt="">
어떤 단순화 된 Feature값이 0이면 그 Feature는 기여도 또한 0이다.(If~Then)</p>
<h3 id="consistency">Consistency</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/0e6ce7db-e617-4f6b-97bd-acb7f9084000/image.png" alt=""></p>
<p>어떤 모델 f’에서 i의 영향이 f에서의 i의 영향보다 크다면 기여도 역시 마찬가지다.
(영향이 클수록 기여도도 크다)</p>
<ul>
<li><strong>Local accuracy</strong> : Local explanation model로 근사 가능</li>
<li><strong>Missingness</strong> : Feature값이 0이면 기여도 또한 0</li>
<li><strong>Consistency</strong> : i feature가 있고 없고의 차이가 더 큰 모델에서의 기여도(ϕ)가 더큼</li>
</ul>
<p>위에 3가지 property와 정의1을 만족시킬 때, 다음과 같은 정리를 따른다.
<span style="color:blue">[우리는 unique한 설명 모델 g를 결정할 수 있다.]</span></p>
<h3 id="theorem-1">Theorem 1</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/efcb2f1f-e823-4f30-a026-5c88349a5ecd/image.png" alt="">
<span style="color:blue">
이때, |z’|은 0이 아닌 entry의 개수이고 z’은 x’에서 0이 아닌 원소들의 집합의 부분집합이다.</span></p>
<p><strong>NOTE</strong>
    Theorem1의 방정식을 만족하는 $ϕ_i$ 가 바로 Shapley Value형태이다.
    또한 Shapley value는 언급한 Axiom 1,2,3을 모두 만족한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b30b833c-c9a5-446d-8340-bb1d8977ef57/image.png" alt=""></p>
<p>이제 드디어 <span style="color:blue">SHAP (SHapley Additive exPlanation) Values</span> 을 정의해보도록 하자.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/05bfded6-aa7c-423c-9592-820272b6fda5/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/925d2979-3bed-4214-b70f-05922e2ee6bb/image.png" alt="">
한가지 Recall해볼 사실은 SHAP values는 왼쪽 수식에서 빨간색 박스 관계를 갖고 있다는 것이다. 이때, 우리가 정의를 하는 것이 바로 하늘색 박스의 관계이다.<br>이때, 우리는 하늘색 점선박스의 의미를 알면 된다.
우리가 만약에 보험료를 측정해야하는 DataScientist라고 해보자. 이때 우리는 John에게 보험료가 왜 그렇게 측정됐을지 알려주어야 한다. 이때, 만약, 우리가 모델에 대한 정보를 모른다고 가정했을 때, $E[f(z)]$를 보험료로 측정할 수 있겠다. 이는 뭐 평균 보험료가 될수도 있고, 여러 상황이 가능할 것이다. 이를 Base로 해서 우리는 우리의 모델을 사용해서 측정한 John의 보험료를 설명하여야 한다. 그럴때 조건을 붙여가면 SHAP values만큼 보험료가 오르기도 줄어나가기도 할 것이다. 이때, 최종적으로 조건을 다 붙이면 우리는 SHAP values로 보험료의 측정 process를 설명 할 수 있다.
<strong>&rightarrow; 이것이 SHAP values가 하는 일이다.</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/8e50be4b-b18c-4cca-b87d-5bac5ddfcf85/image.png" alt=""></p>
<p>우리는 현재 선형적인 모델을 보고 있지만, 만약에 모델에 비선형성이 추가되거나, 각변수가 서로 dependent한 상황에서는 피처가 확장에 추가되는 순서가 중요하며, 가능한 모든 순서에 걸쳐 $\phi$ 값의 평균을 구하여 SHAP 값을 생성한다.</p>
<p>그렇지만 부분집합의 개수가 $2^n$이라는 시간복잡도를 갖기 때문에, SHAP value를 실제로 찾기란 어렵다는 이슈가 있다.
<a href="https://www.youtube.com/watch?v=-taOhqkiuIo&amp;t=445">동영상 출처</a></p>
<h3 id="shap의-근사치를-위한-방법kernel-shap-tree-shap">SHAP의 근사치를 위한 방법(Kernel SHAP, Tree SHAP)</h3>
<p>이를 위해서 저자들은 Kernel SHAP과 딥러닝 모델에 특화된 SHAP의 게산알고리즘인 Deep SHAP, 그리고 Linear SHAP등을 제안했다. 여기서는 Kernel SHAP과 Tree SHAP을 알아보겠다.</p>
<h4 id="kernel-shaplinear-lime--shapley-values">Kernel SHAP(Linear LIME + Shapley values)</h4>
<p>&rightarrow; KernelSHAP은 관측치 x에 대해서 각 특성값의 예측 기여도를 추정한다.</p>
<p>먼저 원활한 이해를 위해서, Notation을 정리해보자.
$x$ : 설명하고자 하는 모델 f에 들어갈 데이터 Vector
$x’$: $x$를 단순화한 Vector
$z’$: $x’$에서 feature의 결측치를 포함한 Vector[LIME에서 주변값]
<span style="color:blue">
저자들은 LIME의 Loss 방정식을 조정함으로써 surrogate model의 계수가 Shapley value가 되도록 다음과 같은 kernel을 제안하였다.</span>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7b295075-9b20-42f4-bbdb-2350cd5ad4e9/image.png" alt=""></p>
<p>이때, $|z’|$이 0또는 M이 되면 $π_{x^{&#39;}}(z^{&#39;})$ 이 Infinite로 튀는 것을 주목해야한다. 실제로, 우리는 $|z’|$이 0또는 M이 되지 않도록 제약을 걸어서 이러한 상황을 피한다.
또한 여기서 Z는 학습할 데이터이다. 위의 정의한대로 g를 구하면 된다.</p>
<p><span style="color:blue">Kernel SHAP은 모델의 형태를 가정하지 않으므로 임의의 모델에 적용할 수 있다.(similarly LIME)</span></p>
<p><span style="color:blue">Kernel SHAP은 속도가 느리기 때문에, 많은 인스턴스에 대해 Shapley Value를 계산하려는 경우 사용할 수 없다.</span></p>
<h4 id="tree-shap">Tree SHAP</h4>
<p>Tree SHAP은 랜덤 포레스트나 기본 학습기를 의사결정나무(Decision Tree)를 사용하는 앙상블 모형의 경우 나무구조를 이용해서 좀 더 쉽게 SHAP Value를 구할 수 있도록 개발된 것이 Tree SHAP이다.
Tree SHAP은 별도의 데이터 없이 Value값을 구할 수 있는데, 
Value값 $f_S (x_S)$을 다음과 같이 정의한다.</p>
<p><strong>$E[f(x)│x_S] =(x_S가 속하는 leaf node의 score값) * (해당 노드에 속하는 데이터 비중)$</strong></p>
<p>이때, 각 트리마다 위에 해당되는 값을 구해서 다 더하여서 최종값을 산출하면 된다. 그 이후 Shapley Value를 구하는 방식대로 기여도를 구하면 된다. Tree SHAP은 기존에 $2^n$의 시간 복잡도를 갖던 Tree기반 앙상블 모델에 한해서 $D^2$ [트리의 최대깊이]로 시간복잡도를 상식선으로 줄일 수 있다.</p>
<p>Tree SHAP은 조건부 평균을 Value로 사용하기 때문에, SHAP Value가 0이 아니지만 실제로 개별 에측값 계산시 사용되지 않는 경우가 있다. </p>
<p><a href="https://arxiv.org/pdf/1705.07874.pdf">논문</a>
<a href="https://velog.io/@tobigs_xai/2%EC%A3%BC%EC%B0%A8-SHAP-SHapley-Additive-exPlanation">블로그 출처1</a>
[블로그 출처2]
(<a href="https://moondol-ai.tistory.com/378">https://moondol-ai.tistory.com/378</a>)
[블로그 출처3]
(<a href="https://kicarussays.tistory.com/32">https://kicarussays.tistory.com/32</a>)
[블로그 출처4]
(<a href="https://zephyrus1111.tistory.com/271">https://zephyrus1111.tistory.com/271</a>)</p>
<p><strong>&lt;참고&gt;</strong></p>
<ol>
<li><p>z’ 데이터 randomly 생성 그림
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/8dd47651-41eb-44ba-b073-00dcbb00d74f/image.png" alt="">
위의 그림을 설명하자면, 우리는 h_x를 원래의 Feature value로 mapping하는 map으로써 사용을 하는데, 이때 1을 갖는 값은 원래의 값으로 mapping이 되고 0을 갖는 값은 데이터의 랜덤한 특성값을 샘플링 하여 매핑 된다.</p>
</li>
<li><p>TreeSHAP 계산 방법
[출처] (<a href="https://zephyrus1111.tistory.com/271">https://zephyrus1111.tistory.com/271</a>)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e70377a5-62b5-408a-a6f7-956a3f58c969/image.png" alt=""></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Are Transformers Effective for Time Series Forecasting?]]></title>
            <link>https://velog.io/@leesungjoon-net/Are-Transformers-Effective-for-Time-Series-Forecasting</link>
            <guid>https://velog.io/@leesungjoon-net/Are-Transformers-Effective-for-Time-Series-Forecasting</guid>
            <pubDate>Mon, 04 Sep 2023 10:21:19 GMT</pubDate>
            <description><![CDATA[<p>여태까지 했던 주제(Informer TFT)와 매우 상반되는 주제이다. 
사실 이전까지 했던 Transformer 기반의 TimeSeriesForecasting은 Attention에 기반을 두면서, LTSF에 강점이 있었다.
이번 포스팅에서는 이러한 기존의 Transformer 기반에 맞춰져 있던 TimeSeries Forecasting에 대한 관점을 어떻게 바꿨을지를 확인하면서 보면 좋을 것 같다.</p>
<blockquote>
<p>이 논문의 난이도는 직관적으로 이해가 가도록 구성해놔서 이해하기 좋았다.</p>
</blockquote>
<h1 id="abstract">Abstract</h1>
<p>최근에, LTSF task를 위한 많은 Transformer 기반에 모델들이 나왔다
과거 몇 년 동안에 Performance 향상에도 불구하고 우리는 이 work에 대한 연구들이 과연 진짜 효과가 있는지 질문을 던진다
구체적으로, Transformers는 틀림없이(arguably) long sequence에서 의미적인 상관관계를 추출하기 위해 가장 성공적인 solution이다 하지만, time-series modeling에서 우리는 연속적인 포인트들의 순서집합에서 temporal relation을 추출한다.</p>
<p><span style = "color:blue">Positional encoding을 employing하고 transformers에서 sub series를 embed 한 토큰들을 상용하는 것은 몇 가지 순서 정보 보존을 가능케 하는 반면에, 순서를 고려하지 않는 (Permutation-Invariant) self-attention mechanism의 속성은 필연적으로(inevitably) temporal information loss를 일으킨다.
</span>
우리 주장의 유효성을 보이기 위해서 우리는 LTSF-Linear이라고 불리는 비교를 위한 simple one-layer linear models의 집합을 소개한다 
9가지의 실생활 데이터에서 우리의 LTSF-Linear은 복잡한 transformer기반의 LTSF모델들 보다 훌륭한 성능을 냈고 몇몇은 큰 차이(20%~50%)가 났다
더욱이, 우리는 LTSF모델의 다양한 구성요소들이 그들의 temporal relation 추출능력에 미치는 영향을 알아보기 위해서 포괄적이고 경험적인 studies를 수행한다 
우리는 이런 놀라운 발견이 LTSF task에 대해서 새로운 연구 방향을 열어주길 기대한다</p>
<h1 id="introduction">Introduction</h1>
<p>Time series는 ubiquitous하다 오늘날의 data-driven world에서 주어진 historical data에서 time series forecasting(TSF)는 다양한 분야에서 적용할 수 있는 long-standing task이다
Example&gt; traffic flow estimation, energy management, financial investment
과거 몇 십년간 TSF solution 들은 traditional statistical methods(e.g. ARIMA)와 machine learning techniques(e.g. GBRT) 로부터 deep learning-based solutions(e.g. Recurrent Neural Net-works, Temporal Convolutional Networks)로의 Progression을 겪었다
Transformer는 NLP, speech recognition, computer vision등 다양한 분야에서 뛰어난 성능을 보여주면서 틀림없이 가장 성공적인 sequence modeling architecture로 자리매김했다
 최근에 time series analysis에 대해 transformer base solutions가 많이 나왔다
Most notable models</p>
<ul>
<li>LogTrans [16] (NeurIPS 2019),</li>
<li>Informer [30] (AAAI 2021 Best paper), </li>
<li>Autoformer [28] (NeurIPS 2021), </li>
<li>Pyraformer [18] (ICLR 2022 Oral), </li>
<li>Triformer [5] (IJCAI 2022)</li>
<li>FEDformer [31] (ICML 2022)</li>
</ul>
<p>Transformers의 main working power는 multi-head self-attention mechanism으로부터 온다 이는 long sequence에서 요소들 간에 의미적인 상관관계를 뽑아내는 능력이 우수 하다
하지만 self-attention은 permutation-invariant하다. <span style = "color:blue">다양한 type의 positional encoding techniques를 사용하는 것은 몇몇 순서정보를 보존할 수 있는 반면에 self-attention을 적용한 이후에 몇몇 temporal information loss는 필연적으로 발생한다</span>
이는 NLP와 같은 의미가 풍부한 application에 대해서는 그리 심각한 문제가 아니다 
(e.g. the semantic meaning of a sentence is largely preserved even if we reorder some words in it)
하지만, time series data를 분석할 때는 많은 데이터에서 그 자체로 주로 의미가 부재한다. 그리고 우리는 연속적인 points 사이에서 temporal changes를 모델링 하는데 관심이 있다.
다시 말하자면 <span style = "color:blue">NLP와 달리 순서 그 자체가 time series에서는 critical한 역할을 한다</span>
결과적으로, 우리는 다음의 intriguing(흥미로운) 질문에 마주한다: 
Are Transformers really effective for long-term time series forecasting?
더욱이, 존재하는 Transformer기반의 LTSF solutions는 그들의 실험에 있는 traditional method보다 뛰어난 예측 정확도 향상을 보였다.
모든 비교대상(non-transformer)는 autoregressive 또는 iterated multi-step(IMS) forecasting방식을 사용했다 이는 LTSF문제에 대해 significant error accumulation effect로부터 발생했다. 따라서 이번 paper에서 우리는 transformer 기반의 LTSF solution과 direct multi-step(DMS) forecasting strategies의 진짜 성능을 확인하기 위해 도전한다 </p>
<p><span style = "color:blue">Not all time series are predictable, let alone long-term forecasting (e.g., for chaotic systems).</span>
우리는 long-term forecasting이 상대적으로 trend와 periodicity가 명확한 time-series에 대해 알맞다고 가정한다
Linear model들은 이미 이러한 정보를 추출할 수 있기 때문에, 우리는 비교를 위한 새로운 baseline으로써 LTSF-Linear로 불리는 간단한 모델을 소개한다
LTSF-Linear은 미래의 time series를 직접적으로 forecast하기 위해서 과거의 time series를 하나의 layer를 갖는 linear모델과 함께 선형회귀를 한다</p>
<p>우리는 기존의 transformers에 주장과 달리 그들의 대부분이 long sequences로부터 temporal relation을 추출하는데 실패한 것을 확인했다
(i.e. the forecasting errors are not reduced(sometimes even increased) with the increase of look-back window sizes)-&gt; 참고하는 과거 데이터의 수를 늘렸는데 forecasting error가 줄어들기는 커녕 늘어나기도 했음
마침내, 우리는 다양한 Ablation studies를 그들 안에 있는 다양한 design elements의 영향을 연구하기 위해서 현재 존재하는 transformer base의 TSF solutions 에 수행했다  </p>
<h1 id="contributions">Contributions</h1>
<ul>
<li>LTSF task에서 Transformer boom에 도전하는 첫번째 work임</li>
<li>우리의 주장을 확인하기 위해서 매우 간단한 linear model인 LTSF-linear을 소개하고 우리는 transformer 기반의 LTSF solution을 9개의 bench-marks에 대해 비교한다 
LTSF-Linear은 LTSF problem에 대해 새로운 기준이 된다</li>
<li>우리는 포괄적이고 경험적인 study들을 이미 존재하는 transformer 기반의 solution에 여러 측면에 대해 ablation study를 수행한다, </li>
</ul>
<ol>
<li>Long inputs을 모델링 하는 것의 능력</li>
<li>Time series order의 민감도</li>
<li>Positional encoding과 sub-series embedding의 영향</li>
<li>효과적인 비교
이러한 발견들은 이 분야의 미래 연구에 대해 benefit이 될 것이다</li>
</ol>
<p>위의 기여들과 함께 
우리는 time series에 대한 적어도 현재 존재하는 LTSF를 위한transformer의 temporal modeling 능력들이 과장됐다고 결론 내렸다
동시에 LTSF-Linear가 더 좋은 prediction accuracy를 갖음을 알았다, 그것은 단순히 long term time series forecasting 문제의 challenging에 미래 연구분야에 대한 단순한 baseline을 제공한다</p>
<h1 id="preliminaries-tsf-problem-formulation">Preliminaries: TSF Problem Formulation</h1>
<p>C개의 변수들을 포함하는 time series에대해, 주어진 historical data $χ=$${X_1^t,..,X_C^t}$$<em>{(t=1)}^L$, where L is the look-back window size and $X_i^t$ 는 i 번째 변수의 t time step을 의미한다.
Time series forecasting 은 다음을 예측하는 것이다 다음은 T future time steps에 대한 value이다
$\hat χ=$${\hat X_1^t,..,\hat X_C^t}$$</em>{(t=L+1)}^{L+T}$
T&gt;1일 때, iterated multi-step(IMS) forecasting을 적용하는 모델은 single-step을 forecasting하고 그 값을 multi-step prediction을 얻기 위해서 적용한다.
대안으로 direct multi-step(DMS) forecasting은 직접적으로 multi step forecasting 객체를 한번에 최적화한다
<span style = "color:blue">DMS forecasting 결과와 비교해서 IMS prediction 값들은 autoregressive한 추정 절차 덕분에 더 작은 분산을 갖지만 그들은 필연적으로 error accumulation effects가 생긴다</span></p>
<p>결과적으로, <span style = "color:blue">IMS forecasting은 높은 정확도를 갖는 single-step forecaster가 있고 예측범위가 짧을 때 선호된다.</span>(예측범위가 짧으면 error accumulation effects가 줄어들기 때문에)
이와 반대로, <span style = "color:blue">DMS forecasting은 unbiased한 single-step forecasting model을 얻기 어렵거나 예측범위가 클 때 더 정확한 예측을 생성한다</span></p>
<h2 id="transformer-based-ltsf-solutions">Transformer-Based LTSF Solutions</h2>
<p>Transformer기반의 모델들은 multi-head self-attention의 효용성 덕분에 NLP와 Vision과 같은 많은 AI task에서 높은 성능을 달성했다. 이는 Transformer기반의 time-series modeling에 많은 연구가 이뤄지게 되는 역할을 했다. 특히, 많은 연구가 LTSF task에 노력을 기울였다
Transformer model이 워낙 Long-range dependency를 잘 Capture하기 때문에 그들의 대부분은 덜연구된 long-term forecasting problem에 집중했다(T&gt;&gt;1)
Vanilla Transformer를 LTSF task에 적용하면 quadratic한 time/memory complexity와 autoregressive decoder design에 의해서 error accumulation이 생겼고 이 문제를 극복한 모델이 Informer라는 모델이다 
그 이후에 더 많은 Transformer variants(변형체)은 performance나 모델의 효율성을 향상시키기 위해서 다양한 time series features을 그들의 모델안으로 도입한다
우리는 존재하는 Transformer 기반의 LTSF solution들을 figure 1에 요약했다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/03616e10-092f-44ab-ac78-aaf156aa1dc7/image.png" alt=""></p>
<p>게다가, Autoformer는 처음으로 seasonal-trend decomposition을 각각의 neural block뒤에 적용한다.
seasonal-trend decomposition은 time series analysis에서 raw data를 더욱 predictable 하게 만드는 standard method이다. 구체적으로, 그들은 moving average kernel을 input sequence에 Trend-Cyclical component를 추출하기 위해서 사용한다. 
Original sequence와 Trend component의 차이는 seasonal component에 의존한다.
FEDformer는 다양한 kernel size를 가진 moving average kernel에 의해 추출된 trend components를 혼합하기 위해서 전문가 의견과의 혼합을 제안한다</p>
<p><span style = "color:blue">Input embedding strategies: Transformer에서 self-attention layer는 time series의 positional information을 보존할 수 없다.</span>
하지만 <span style = "color:blue">local positional information(i.e. time series의 순서)는 중요하다.</span>
게다가 계층적인(hierarchical) timestamps(week, month, year)과 agnostic timestamps(holidays and events)와 같은 global temporal information 또한 유익하다.
Time-series inputs의 temporal context를 강화하기 위해서, SOTA transformer based methods에서 실용적인 design은 몇 가지 embedding들을 추가한다(e.g. fixed positional encoding[Transformer], channel projection embedding[informer], input sequence안에 learnable temporal embeddings[informer])
더욱이, temporal convolution layer또는 learnable time-stamps와 함께한 temporal embeddings이 소개됐다</p>
<h2 id="self-attention-schemes">self-attention schemes</h2>
<p>Self-attention schemes: Transformer는 paired elements사이에 의미적인 의존성을 추출하기 위해서 self-attention mechanism에 의존한다
Vanilla transformer의 Quadratic한 time and memory complexity를 줄임으로써, 최근에 works는 효율성에 대한 두가지 전략을 제안한다.</p>
<ol>
<li>LogTrans 와 Pyraformer에서는 명시적으로 self-attention scheme 안에 Sparsity bias를 소개한다, LogTrans는 computational complexity를 O(LlogL)로 줄이기 위해서 Logsparse mask를 사용한다 반면에 Pyraformer는 O(L)수준의 time and memory complexity와 함께 계층적으로 multi-scale을 갖는 temporal dependencies를 잘 capture하기 위해서 pyramidal attention 채택한다</li>
<li>Informer와 FEDformer는 low-rank property를 self-attention matrix에서 사용한다 Informer는 Complexity를 O(LlogL)로 낮추기 위해서 ProbSparse self-attention과 self-attention distilling operation을 제안한다 그리고 FEDformer는 Fourier enhanced block과 wavelet enhanced block을 Random selection과 함께 디자인하여 O(L)의 complexity를 달성했다
최근에, Autoformer는 original self-attention layer를 대체하기 위해서 series-wise auto-correlation mechanism을 디자인 한다</li>
</ol>
<h2 id="decoder">Decoder</h2>
<p>Decoders: Vanilla Transformer decoder는 autoregressive한 방법으로 sequence의 output을 낸다 이는 slow inference speed 와 error accumulation effects를 갖는다, especially for long-term predictions
Informer는 DMS forecasting을 위한 generative-style decoder를 디자인한다. 다른 변형된Transformer도 비슷한 DMS strategies를 사용한다. 
예를 들어 Pyraformer는 Spatio-temporal axes로 concatenating한 fully-connected layer를 decoder로써 사용한다
Autoformer는 두가지 trend-cyclical components 와 stacked 된 auto-correlation mechanism 으로부터 구해진 seasonal components를 final prediction을 얻기 위해 더한다 
FEDformer는 final results를 decode하기 위해 제안된 frequency attention block과 함께 decomposition scheme을 사용한다
<span style = "color:blue">Transformer 모델들의 전제는 paired elements사이에 의미적인 상관관계가 있다는 것이다 그리고 self-attention mechanism은 그 자체로 순서를 고려하지 않고 Transformer models의 temporal relations modeling 능력은 input tokens와 관계된 positional encodings에 크게 의존한다</span>
Time series안에 있는 raw 수치 데이터를 고려하면(e.g. stock prices or electricity values), There are hardly any point-wise semantic correlations between them.
Time series modeling에서 우리는 주로 point들 사이에 temporal relation에 흥미가 있다 그리고 짝지어진 관계 대신에 이들 구성요소의 순서는 중요한 역할을 한다
Positional encoding과 sub-series가 embedding된 tokens를 사용하는 것은 몇몇 ordering information의 보존을 가능케하는 반면에, self-attention에 순서를 고려하지 않는 속성은 필연적으로 temporal information loss를 일으킨다 
위와 같은 관찰 때문에 우리는 Transformer base의 LTSF solution의 효용성을 revisit(재고하다)하는 것에 관심이 있다</p>
<h1 id="embarrassingly-simple-baseline">Embarrassingly simple Baseline</h1>
<p>이미 존재하는 Transformer 기반의 LTSF solution(T&gt;&gt;1)들의 실험에서 모든 비교되는 baseline(non-Transformer)들은 IMS forecasting technique들을 사용한다, 이들은 이미 error accumulation effects로부터 큰 영향을 받는 것으로 알려졌다
우리는 Transformer 기반의 solution들의 성능향상은 그 solution들에게 쓰이는 DMS strategy때문이라고 가정한다 -&gt; (내 생각) 이게 동기가 돼서 그럴 바엔 그냥 Linear regression을 써버리자!
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/36d17c17-89c8-4a59-8781-2a09e58f57dd/image.png" alt=""></p>
<p>우리는이 가정을 확인하기위해서, 비교하기 위한 baseline으로써 temporal linear layer를 통해 LTSF-Linear이라고 불리는 가장 간단한 DMS model을 만들 것이다<br>LTSF-Linear의 기본이 되는 방정식은 직접적으로 future prediction에 대한 historical time series를 weighted sum operation을 통해 회귀를 진행한다</p>
<p>Mathematical expression
$\hat X_i=WX_i$, Where $W∈R^{T×L}$
W는 temporal axis를 따른 linear layer이다 $\hat X_i$와 $X_i$은 각각의 i번째 variates에 대한 prediction과 input이다</p>
<blockquote>
<p>Note&gt;
LTSF-Linear은 여러 variates에 걸쳐서 weights를 share하고, 어떠한 spatial correlations도 모델링 하지 않는다(spatial correlations=variate간의 relation?)
LTSF-Linear은 linear models의 집합이다. Vanilla Linear은 하나의 layer를 갖는 linear model이다. 다른 영역(e.g. finance, traffic, and energy domains)에 걸쳐 Time series를 핸들링하기 위해서, 우리는 두가지 preprocessing methods와 함께 두가지 변형(DLinear, NLinear)을 소개한다</p>
</blockquote>
<h1 id="dlinear">DLinear</h1>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e03c9ed5-90aa-48e8-aa65-4d883c712cda/image.png" alt=""></p>
<p>구체적으로, DLinear은 Autoformer과 FEDformer에서 사용하는 Decomposition scheme과 linear layers의 결합이다 
먼저 raw data input을 moving average kernel에 의해 trend와 remainder(seasonal) component로 decompose 시킨다
그 이후 one-layer linear layers를 각각의 component에 적용한다, 그리고 우리는 예측을 얻기 위해서 두가지의 features를 더한다
명시적으로 trend를 handling 함으로써, Data안에 있는 Trend가 clear 할 때, DLinear은 Vanilla Linear의 성능을 강화한다</p>
<h1 id="nlinear">NLinear</h1>
<p>반면에, LTSF-Linear의 성능을 높이기 위해서, dataset안에 distribution shift가 있을 때, NLinear는 먼저 input을 sequence의 마지막 값으로 뺀다
그 이후, 그 input은 linear layer를 통과하고 그 빠진 부분은 final prediction을 만들기 전에 다시 더해준다 
이런 빼고 더하는 과정은 input sequence에 대한 simple normalization이다 </p>
<h1 id="experiments">Experiments</h1>
<h2 id="experimental-settings">Experimental settings</h2>
<p>Dataset. 우리는 흔하게 사용하는 9개의 real-world datasets에 대해 추가적인 experiments를 수행한다</p>
<ul>
<li>ETT (Electricity Transformer Temperature) [30] (ETTh1, ETTh2, ETTm1, ETTm2),</li>
<li>Traffic, </li>
<li>electricity, </li>
<li>Weather, </li>
<li>ILI, </li>
<li>Exchange Rate [15].
위에 모두 multivariate time series이다 우리는 Appendix에 data descriptions를 남겨 놓는다</li>
</ul>
<p>Evaluation metric. Previous works에 따라, 우리는 MSE와 MAE를 성능을 비교할 core metrics로 사용한다</p>
<p>Compared methods. 우리는 5가지의 Transformer 기반의 methods를 포함한다: FEDformer, Autoformer, Informer, Pyraformer and LogTrans
게다가 우리는 단순한 DMS method도 포함한다: Closest Repeat, 이는 단순히 그냥 look-back window안에 있는 마지막 value를 반복한다 
FEDformer의 두가지 변형들이 있기 때문에, 우리는 더 정확한 accuracy를 갖고 있는 FEDformer-f via Fourier transform 와 비교한다</p>
<h2 id="comparison-with-transformers">Comparison with Transformers</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/0ded2f0e-d55b-41c1-8bd6-c86da8d707fa/image.png" alt=""></p>
<h3 id="quantitative-results">Quantitative results</h3>
<p>Quantitative results: Table2에서, 우리는 이전 work의 experimental setting을 따라서 9가지의 실험 데이터에 대해 모든 언급된 transformer들을 평가해 봤다</p>
<p>놀랍게도, LTSF-Linear의 성능은 은 variates 사이에 correlations를 모델링 하지도 않았는데 SOTA인 FEDformer를 대부분의 case에 대해 multivariate forecasting에서 20퍼센트에서 50퍼센트 정도 능가했다</p>
<p>다른 different time series benchmarks에 대해, NLinear과 DLinear은 distribution shift와 trend-seasonality features를 다루는 데에 우월성을 보인다</p>
<p>우리는 또한 ETT datasets으로 univariate forecasting에 대해서도 실험해봤는데 여전히 큰 차이로 LTSF-Linear가 Transformer base의 LTSF solutions 보다 뛰어난 성능을 보인다</p>
<p>FEDformer는 ETTh1에서 경쟁력 있는 forecasting accuracy를 달성했다. 이는 FEDformer가 classical time series analysis techniques(e.g. Frequency processing)를 사용하고 있기 때문에 그렇다, 이는 time series 안에 inductive bias와 temporal feature extraction의 능력을 가지고 왔다 </p>
<p>요약하자면 이러한 결과들은 기존에 Transformer기반의 LTSF solutions가 존재하는 9가지의 benchmarks에 대해 효과적이지 않고 반면에 LTSF-Linear은 powerful baseline이 될 수 있다 는 것을 보여준다</p>
<p>다른 흥미로운 관찰할 점은 심지어 naïve Repeat method(Closest Repeat)는 long-term seasonal data(e.g. Electricity and Traffic)을 예측할 때는 나쁜 결과를 보이지만 그것은 놀랍게도 모든 Transformer base method 보다 Exchange-Rate에서 뛰어난 성능을 보인다(around 45%)
환율-&gt; 고려할 data가 많음; 또한 naïve 한 메소드가 잘 먹힐 수 있는 경제관련 지표임</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/0297001a-8553-4db8-bb6d-8ad2b7eb12ad/image.png" alt=""></p>
<p><span style = "color:blue">이는 주로 Transformer-based solutions에 잘못된 trend 예측에 의해 발생한다, 이는 training data 안에 있는 갑작스럽게 변화하는 noise들에 모델이 과대적합을 해서 큰 정확도 저하가 발생한 것 같다(see Figure 3(b))
반면에 Repeat은 bias를 갖지 않는다</span></p>
<blockquote>
<p>이것이 DLinear/NLinear가 시계열 특성을 잘 반영하는 이유(모델의 파라미터 개수)</p>
</blockquote>
<h3 id="qualitative-results">Qualitative results</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/79397dc9-ea3f-4d89-819d-17f0f8805dad/image.png" alt=""></p>
<p>[Input length L=96이고 output length T=192인 모델의 예측 plot]
Fig3에서 보듯이, 우리는 세가지 선택된 Time series datasets에 대해서 Transformer-based solutions와 LTSF-Linear의 예측 결과를 plot 한다: 
Electricity (Sequence 1951, Variate 36), Exchange-Rate (Sequence 676, Variate 3), ETTh2 ( Sequence 1241, Variate 2)
위의 dataset들은 다른 temporal patterns를 갖는다 </p>
<p>Input length가 96 steps이고 output horizon이 336 steps일 때 Transformer[28,30,31]는 Electricity와 ETTh2에서 future data의 scale과 bias를 잡아내는 데에 실패했다
더욱이 그들은 Exchange-Rate와 같은 비 주기적인 data에서 적절한 trend를 예측하기 어렵다 이런 현상은 LTSF task에 대해 transformer base solution들이 부적절하다는 것을 보여준다.</p>
<h1 id="ablation-study">Ablation Study</h1>
<h2 id="more-analyses-on-ltsf-transformers">More Analyses on LTSF-Transformers</h2>
<blockquote>
<p><strong>Can existing LTSF-Transformers extract temporal relations well from longer input sequences?</strong></p>
</blockquote>
<h3 id="input-data의-개수를-조절">Input data의 개수를 조절</h3>
<p>Look-back window size는 우리가 historical data로부터 얼마나 배울 수 있는지를 결정하기 때문에 forecasting accuracy에 크게 영향을 미친다
<span style = "color:blue">일반적으로 말하는 점은, 뛰어난 temporal relation extraction 능력을 갖는 더 강력한 TSF model은 look-back window sizes가 커지면 더 좋은 결과를 낼 수 있어야 한다</span></p>
<p>Input Look-back window 크기의 영향을 알아보기 위해 우리는 input size를 {24, 48, 72, 96, 120, 144, 168, 192, 336, 504, 672, 720} 까지 다양하게 해서 720개의 long term output을 내는 실험을 수행한다 
Figure 4는 두가지 데이터셋에 대한 MSE results를 보여준다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/72b03d6a-7f0f-4a8c-81f0-ad6d07d29de1/image.png" alt=""></p>
<p>이전 연구들[27,30]로부터 관찰된 것과 비슷하게, existing Transformer-based model의 performance는 악화 되거나 look-back window가 커졌음에도 stable한 상태를 유지한다
대조적으로 모든 LTSF-Linear의 Performances는 look-back window size의 증가와 함께 증가했다.
따라서, 만약 더 긴 sequence가 주어진다면 existing solution들은 temporal information을 추출하는 것 대신에 temporal noises를 overfit하는 경향이 있다
그리고 대부분의 Transformer에 대해서 input size는 96이 정확히 알맞다</p>
<h3 id="what-can-be-learned-for-long-term-forecasting">What can be learned for long-term forecasting?</h3>
<p><strong>&rightarrow; long-term time series forecasting에서 size는 갖되 바라보는 window의 위치를 다르게 해서 성능을 측정</strong></p>
<p>Look-back window안에 있는 temporal dynamics가 short-term time series forecasting의 forecasting accuracy에 크게 영향을 주는 반면에, 우리는 long-term forecasting은 model이 trend와 periodicity를 잘 capture할 수 있는지에 의존한다고 가정한다
다시 말하자면, <span style = "color:blue">forecasting horizon이 더 커질수록 look-back window가 그 자체로 갖는 영향은 줄어든다</span></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/dc8834af-458c-487f-92e9-8ec3c4a4ef74/image.png" alt=""></p>
<p>위의 가정을 확인하기 위해서 Table 3에서 우리는 미래의 720 time steps에 대해 두가지의 서로 다른 look-back windows 로부터 forecasting accuracy를 비교한다</p>
<p>(1)    The original input L=96 (called Close)
(2)    The far input L=96 (called Far) 이는 original 96 step보다 이전 step을 의미한다
Experimental results로부터, SOTA의 성능을 갖는 Transformer의 성능차이가 얼마 나지 않는 것을 볼 수 있다, 이는 이 모델들이 인접한 time series sequence로부터 단순히 비슷한 temporal information을 capture하는 것을 알 수 있다(= window가 close 하건 Far 하건 모델의 성능의 주류는 모델이 trend와 periodicity를 얼마나 잘 캡쳐 할 수 있느냐 에 달려있다)</p>
<p>Dataset의 본래 갖추어진 특징들(periodicity trend)을 capturing하는 것은 일반적으로 많은 수의 parameters가 필요하지 않다.
많은 파라미터들을 사용하는 것은 overfitting을 일으킬 것이다, 이는 왜 LTSF-Linear가 Transformer base methods보다 더 좋은 성능을 내는지에 대한 부분적인 이유이다</p>
<h3 id="are-the-self-attention-scheme-effective-for-ltsf">Are the self-attention scheme effective for LTSF?</h3>
<p>*<em>&rightarrow; Existing solutions안에 들어있는 complex design 들을 빼 보면서 성능 판단 *</em></p>
<p>우리는 이런 이미 존재하는 transformer안에 complex designs(e.g. Informer)가 필수적인지 아닌지를 확인한다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/a7c89b21-c26a-4342-ac4e-544d7ecd25bd/image.png" alt=""></p>
<p>Table4에서, 우리는 점진적으로 Informer에서 Linear로 변화한다.
먼저, 한 self-attention layer를 weights가 dynamically하게 변화하는 fully connected layer로 생각될 수 있기 때문에 우리는 self-attention layer를 linear layer로 대체한다, 이를 Att.-Linear로 부른다.</p>
<p>다음으로, 우리는 Informer에서 embedding layers와 linear layers만 남기기 위해서 informer 안에 있는 다른 보조적인 장치(e.g. FFN) 들을 폐기한다 이를 Embed+ Linear 로 부른다</p>
<p><span style = "color:blue">마지막으로, 우리는 하나의 linear layer로 단순화시킨다. 놀랍게도, Informer의 performance는    적어도 이미 존재하는 LTSF benchmarks에 대해서 simplification이 진행되면서 점점 좋아졌다 이는 self-attention 도식과 다른 복잡한 모듈들의 불필요성을 의미한다</span></p>
<blockquote>
<p>&rightarrow; 몇 가지 데이터에 대해서만 판단하는 것은 일반화하기에 무리가 있다고 생각함</p>
</blockquote>
<h3 id="can-existing-ltsf--transformers-preserve-temporal-order-well">Can existing LTSF- Transformers preserve temporal order well?</h3>
<p><strong>&rightarrow; Input의 순서를 섞어서 넣어보면서 과연 실제로 existing transformers가 순서를 capture할 수 있는지 확인[얼마나 데미지를 입는지를 통해서]</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/322c83f3-9e98-4083-9cf4-5beb8c27dde2/image.png" alt="">
<span style = "color:blue">Self-attention은 내재적으로 순서가 보존되지 않는다(i.e. regardless of the order).</span>
하지만, time series forecasting에서, sequence order는 자주 핵심적인 역할을 한다. 우리는 심지어(even with) positional과 temporal embeddings를 논하지만, 존재하는 Transformer base의 methods는 여전히 temporal information loss의 문제를 갖는다.
Table 5에서 우리는 embedding strategies 전에 raw input을 섞는다. 두가지 shuffling strategies가 보여진다: 
Shuf.는 모든 input sequences를 랜덤하게 섞는다 
Half-Ex.는 input sequence의 첫번째 절반을 두번째 절반과 교환한다
흥미롭게도, Exchange Rate에서 심지어 input sequence가 랜덤하게 섞였을 때조차 모든 Transformer 기반의 methods의 성능이 original setting과의 비교에서 변동(fluctuate)되지 않았다. 반대로, LTSF-Liner의 성능은 크게 damage를 입었다.
<span style = "color:blue">
이는 서로 다른 positional 과 temporal embeddings를 갖는 LTSF-Transformers가 꽤 제한된 temporal relations를 보존하는 것과 LTSF-Transformers가 noisy한 financial data에 과대적합 되는 경향이 있다(be prone to)는 것을 암시한다.</span>
반면에 LTSF-Linear은 적은 파라미터로 과대적합을 피하고 순서가 자연스럽게 모델링 할 수 있다는 것을 암시한다.</p>
<p>ETTh1 dataset에 대해, FEDformer과 Autoformer는 그들의 모델들 안에 있는 time series inductive bias를 소개한다. </p>
<p>이런 time series inductive bias는 dataset이 꽤나 clear한 temporal patterns(e.g. periodicity)를 갖을 때 특정한 temporal information을 추출할 수 있다</p>
<p>따라서 input 데이터의 순서를 완전히 섞었을 때 각각의 성능은 73.28%와 56.91%가 저하되는 것을 볼 수 있다(이는 전체 순서정보를 잃었다고 본다)
추가로, Informer는 여전히 성능저하가 덜한데 이는 temporal inductive bias[Sequential, Temporal Invariance]가 없기 때문이다.<span style = "color:blue">
전반적으로 LTSF-Linear의 평균 성능 저하가 Transformer-based methods보다 모든 케이스에서 크다 이는 existing Transformers가 temporal order를 상대적으로 잘 보존하지 않는 것을 의미한다</span></p>
<h3 id="how-effective-are-different-embedding-strategies">How effective are different embedding strategies?</h3>
<p><strong>&rightarrow; Embedding을 안 해보면서 Embedding이 얼마나 효과가 있는지 확인</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/74e7c4cc-93f7-4bc9-841d-42ec4453baae/image.png" alt="">
<strong>우리는 Transformer-based methods에서 사용하는 position과 timestamp embeddings의 이점을 연구한다.</strong></p>
<p>In Table 6에서 positional embeddings 없이 (wo/Pos) Informer의 forecasting errors는 크게 증가한다.</p>
<p>Timestamp embeddings 없이 (wo/Temp) Informer의 성능은 forecasting lengths가 증가하기 때문에 점진적으로 damage를 입을 것이다.
Informer는 각각의 token에 대해 single time step을 사용하기 때문에 토큰들에 대해 temporal information을 알려줘야 한다</p>
<p>각 토큰에게 single time step을 사용하는 것 대신에, FEDformer와 Autoformer은 temporal information을 embedding하기 위해서 timestamps의 sequence를 입력해준다
그렇기 때문에, 그들은 고정된 positional embedding없이 비교할 만하거나 더 좋은 성능을 이뤄 낼 수 있다. </p>
<p>하지만, timestamp embeddings 없이(wo/Pos.-Temp.) Autoformer의 성능은 빠르게 감소하는데 global temporal information의 손실 때문이다 </p>
<p>대신에, temporal inductive bias를 introduce하기 위해 제안된 Frequency-enhanced module 덕분에 FEDformer는 position/timestamp embeddings를 제거하는 것으로부터 덜 영향을 받는다</p>
<h3 id="is-training-data-size-a-limiting-factor-for-existing-ltsf-transformers">Is training data size a limiting factor for existing LTSF-Transformers?</h3>
<p><strong>&rightarrow; Training data size를 조절해보면서 성능 확인</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/013b1abf-ad90-4ff7-a3a8-0304e766d09c/image.png" alt=""></p>
<p>몇몇은 Transformer base solution의 poor performance가 benchmark datasets의 작은 size때문이라고 논할지도 모르겠다.
Computer vision이나 NLP와는 다르게 TSF는 수집된 time series에 대해 수행된다, 그리고 이는 training data size를 크게 만들기 어렵게 만든다.
사실, training data의 size는 실제로 모델 성능에 큰 영향을 미치는 점은 인정한다<br>따라서 우리는 full dataset(17544*0.7 hours)[named Ori]에 대해 training한 모델의 성능을 그보다 좀 짧은 dataset(8760hours, i.e. 1years)[named Short]와 비교하면서 Traffic에대한 실험을 수행한다</p>
<p><strong>뜻밖으로, Table7은 prediction error가 모든 forecast 케이스에 대해서 더 짧은 데이터가 더 낮음을 보인다.</strong></p>
<p>몇몇은 Transformer base solution의 poor performance가 benchmark datasets의 작은 size때문이라고 논할지도 모르겠다.
Computer vision이나 NLP와는 다르게 TSF는 수집된 time series에 대해 수행된다, 그리고 이는 training data size를 크게 만들기 어렵게 만든다.
사실, training data의 size는 실제로 모델 성능에 큰 영향을 미치는 점은 인정한다<br>따라서 우리는 full dataset(17544*0.7 hours)[named Ori]에 대해 training한 모델의 성능을 그보다 좀 짧은 dataset(8760hours, i.e. 1years)[named Short]와 비교하면서 Traffic에대한 실험을 수행한다
<span style = "color:blue">
뜻밖으로, Table7은 prediction error가 모든 forecast 케이스에 대해서 더 짧은 데이터가 더 낮음을 보인다.
이는 ori의 whole-year data가 더 길지만 short data가 더 Clear한 temporal features를 유지하고 있기 때문일 것이다.</span>
우리는 training 할 때 무조건 더 작은 data를 사용해야 된다고 결론 내릴 수 없는 반면에 더 작은 data를 사용했지만 성능이 좋은 점은 training data scale이 Autoformer와 FEDformer의 성능에 대해 performance를 제한하는 이유가 아님을 보인다(-&gt; clear한 temporal features가 중요하다)</p>
<h3 id="is-efficiency-really-a-top-level-priority정말로-효율성이-최우선-순위이냐">Is efficiency really a top-level priority(정말로 효율성이 최우선 순위이냐)</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e3834ac5-67cf-4c6b-91f0-0cc1baa1cb2d/image.png" alt=""></p>
<p>존재하는 LTSF-transformers는 Vanilla Transformer의 O(L^2 )의 복잡도는 LTSF problem에 대해 사용할 수 없다고 말한다
비록 그들이 이론적인 시간과 memory complexity를 O(L^2 )에서 O(L) 로 향상 시킬 수 있음을 증명했지만, 그들은 두가지 점에 대해서 불명확했다
<span style = "color:blue"></p>
<p>1) the actual inference time and memory cost on devices are improved.
2) the memory issue is unacceptable and urgent for today’s GPU (e.g., an NVIDIA Titan XP here)
( memory issue가 과연 오늘날의 GPU에 대해 긴급한 issue인가)
 </span>
Table8에서 우리는 average practical efficiencies를 비교한다.
흥미롭게도, Autoformer에 구현된 DMS decoder를 바꾼 vanilla transformer와 비교했는데, 대부분의 Transformer의 variants와 비슷하거나 심지어 더 나쁜 time과 parameters 추론을 초래했다.
이런 후속조치들(follow-ups)은 추가적인 design elements를 끼워 넣는데 이런 작업은 practical costs를 높게 만든다 더욱이 vanilla transformer의 memory cost는 output length L=720임에도 수용할 만하다, 이는 적어도 존재하는 datasets에 대해서 memory-efficient transformer 개발의 중요성을 약화시킨다</p>
<h1 id="future-work">Future work</h1>
<p>LTSF-Linear은 제한된 능력을 가진 모델이다 그리고 이 모델은 단순하면서도 경쟁력 있는 baseline이다
예를 들어 하나의 layer를 가진 linear network는 change points에 의해 발생하는 temporal dynamics를 capture하기 어렵다[25]
결과적으로, 우리는 새로운 모델 디자인들, data processing, 그리고 LTSF problem challenging을 가로막는 benchmarks에 대해 강한 potential 이 있다고 믿는다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Temporal Fusion Transformers for Interpretable Multi-horizon Time Series Forecasting]]></title>
            <link>https://velog.io/@leesungjoon-net/Temporal-Fusion-Transformers-for-Interpretable-Multi-horizon-Time-Series-Forecasting</link>
            <guid>https://velog.io/@leesungjoon-net/Temporal-Fusion-Transformers-for-Interpretable-Multi-horizon-Time-Series-Forecasting</guid>
            <pubDate>Sun, 03 Sep 2023 13:45:03 GMT</pubDate>
            <description><![CDATA[<h1 id="abstract">Abstract</h1>
<p>Multi-Horizon Forecasting은 보통 정적인 변수, 알고 있는 미래의 input, 다양한 Covariates, 과거에 대해서만 관찰된 exogenous Time Series까지 이와 같이 다양한 Input들이 복잡하게 섞인 형태의 input을 포함해서 Forecasting한다. 하지만 이때 이러한 Input들이 Target과 어떤 상호작용을 할지에 대해서는 사전정보가 없이 진행한다.
몇몇 Black-Box인 deep learning 모델들이 제안됐지만 이들은 모델에서 이런 다양한 Input들이 어떻게 사용되는지를 밝히지 않았다.
이 Paper에서 우리는 Temporal Fusion Transformer(TFT)를 소개한다
우리의 TFT는 novel(새로운) attention을 base로 한 architecture인데 Multi-horizon forecasting에서 뛰어난 성능 과 함께 temporal dynamics에 대한 Interpretable한 insights를 제공한다.</p>
<p>다양한 Scales에서 Temporal relationships를 배우기 위해서 TFT는 local processing을 위한Recurrent layers과 long-term dependency를 위한 Interpretable self-attention을 사용한다
TFT는 특별한 components(GRN)를 서로 관련 있는 Feature selection을 위해 활용하고 불필요한 component를 막기위해 gate layer(GLU)를 활용한다 
이는 다양한 시나리오에 대해 high performance를 가능케 한다</p>
<h1 id="introduction">Introduction</h1>
<p>Multi-horizon Forecasting (i.e. the prediction of variables-of-interest at multiple future time steps) 은 중요한 문제이다.
One-step prediction과 대조적으로 multi-horizon forecast는 user에게 미래의 여러 step에 대해 그들이 어떤 action들을 취해야 할지를 알려주면서 전체 Path에 대한 추정을 제공한다.
Multi-horizon forecasting은 real-world application (retail, health care, economic)들에서 impactful하다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/625b02e8-a6dc-4937-9fd6-813fe9b15ab2/image.png" alt="">
Practical Multi-horizon forecasting application은 fig1과 같이 미래에 대한 알려진 정보(e.g. 다가올 주말), 다른 exogenous time series(e.g. 역대 손님 방문한 횟수), static metadata(e.g. 상점의 위치)를 포함하는 다양한 data source에 접근한다-without any prior knowledge on how they interact
이렇게 그들이 서로 미치는 영향에 대한 적은 정보를 갖고 있는 data source의 이질성은 multi-horizon time series forecasting에서 challenging 하다.</p>
<p>Deep neural network는 traditional한 time series model보다 더 좋은 performance를 보여주면서 multi-horizon forecasting에 사용된다
많은 RNN base모델이 나왔는데 최근에는 과거에 관련이 깊은 time step들의 선택을 잘 하는 transformer 기반의 모델들이 많이 나왔다 하지만 이들은 multi-horizon forecasting에서 흔하게 보여지는 다양한 type의 input들을 고려하는 데에는 실패했다. <strong>또한 이들은 모든 input 외생변수의 미래가 알려질 것이라고 가정하거나 혹은 중요한 static covariates를 다른 time-dependent feature에 붙여서 쓰는 등 경시한다.</strong></p>
<p>우리는 suitable inductive biases들과 함께 네트워크를 디자인함으로써 multi-horizon forecasting에 대한 비슷한 성능을 얻어낼 수 있음을 보일 것이다
게다가 우리는 common multi horizon forecasting input의 이종성을 신경쓰지 않는다.
현재 대부분의 architecture가 forecast가 많은 파라미터 사이에 복잡한 비선형적인 관계에 의해 control되는 black-box model들이다 
Model architecture가 black box일 때 이는 모델이 어떻게 예측과정에 도달하는지에 대한 설명을 어렵게 만들고 이는 user들이 모델의 output을 신뢰하는데 큰 어려움으로 작용한다
불행하게도, 흔하게 사용하는 DNN의 설명 method(LIME SHAP)들은 time-series에 적용하기에는 잘 맞지 않는다
이러한 post-hoc approach 들은 poor explanation quality를 이끌 것이다.
&rightarrow;Post-hoc method는 input feature들의 time ordering을 고려하지 않기 때문에
반면에 transformer와 같이 몇 가지 attention base architecture는 sequential data에 대한 내재된 해석가능성을 제안한다
하지만 Multi-horizon forecasting Task에 Transformer를 적용하는데 무리인 이유는 multi-horizon forecasting은 language나 speech와 반대로 다양한 type의 input feature를 포함한다.</p>
<p>Transformer는 관련이 있는 Time step에 대해서 insight를 제공할 수 있지만 그들은 특정 time step에 대해서 서로 다른 데이터 사이에 중요성을 구분할 수 없다.</p>
<p>따라서 우리는 multi-horizon forecasting에서의 높은 성능을 위해 데이터의 이종성(heterogeneity)을 해결할 새로운 method가 필요하다, 새로운 method들은 또한 forecast interpretable을 세우기 위해서라도 필요하다</p>
<p>SOTA보다 큰 성능 향상을 얻기 위해서, 우리는 여러 개의 주요한 idea들을 소개한다 
(1)    네트워크의 다른 부분 들에서 사용하기 위한 context vector들을 encode하는 static covariate encoders
(2)    모델 전반에 걸친 Gating mechanisms 및 상관없는 input들의 기여를 최소화하기 위한 sample-dependent variable의 선택( variable selection에 자세한 설명 )
(3)    알려지고 관찰된 input들을 locally process하기 위한 seq2seq layer
(4)    dataset안에 Long-term dependencies를 학습하기 위한 Temporal self-attention decoder</p>
<p>이런 특화된 component들의 사용은 interpretability를 가능케한다.
특히 우리는 TFT가 세가지의 가치 있는 interpretability의 사용을 가능케 함을 보여줄 것이다</p>
<p>HELPING USERS IDENTIFY
(1)    prediction problem에 대해 전역적으로 중요한 variable
(2)    일관된 temporal patterns
(3)    중요한 events</p>
<h1 id="related-work">Related Work</h1>
<h2 id="dnns-for-multi-horizon-forecasting">DNNs for Multi-horizon Forecasting</h2>
<p>Traditional multi-horizon forecasting method와 비슷하게, 최근 deep learning method들은 autoregressive model을 사용한 iterated approaches 또는 seq2seq model을 베이스로 하는 direct method로 구분될 수 있다
Iterated approaches는 one-step ahead prediction model을 활용한다 multi-step predictions 은 재귀적으로 prediction을 future의 input으로 feeding함으로써 얻어진다 DeepAR, Deep State-Space Models(DSSM)등이 이러한 접근방식을 사용한다
그들의 Simplicity에도 불구하고 이런 iterative method 들은 Target을 제외한 모든 변수의 value들이 forecast time에서 알고 있어야 하는 가정에 의존한다 하지만 실제로는 time-varying input들이 많고 이들은 사전에 알려져 있지 않다
반대로, direct method들은 각각의 time step에서 미리 define한 multiple horizon에 대해 forecast를 생성하게 training된다
그들의 architecture들은 보통 seq2seq모델들에 의존한다 (e.g. 과거의 input들을 summary하기 위한 LSTM encoder와 future prediction들을 생성하기 위한 다양한 method를 사용, MQRNN)
LSTM base의 iterative method보다 더 좋은 수행을 보임에도 불구하고 interpretability는 direct methods들의 challenging으로 남아있다</p>
<h2 id="time-series-interpretability-with-attention">Time Series Interpretability with Attention</h2>
<p>최근에 Attention mechanism은 LSTM 과 Transformer 기반의 architecture를 사용하면서 interpretability motivation과 함께 Time series에 적용됐다.
하지만 이들은 static covariates의 importance에 대한 고려가 없었다.
TFT alleviates this by using separate encoder-decoder attention for static features at each time step on top of the self-attention to determine the contribution time-varying inputs. </p>
<h2 id="instance-wise-variable-importance-with-dnns">Instance-wise Variable Importance with DNNs</h2>
<p>Instance(i.e. sample)별로 다양한 importance가 post-hoc explanation method들과 Inherently-Interpretable modeling approaches에 의해 관찰될 수 있다 
Post-hoc explanation method들은 pretrained black box 모델에 적용되고 자주 distilling into surrogate interpretable model 또는 decomposing into feature attribution에 기반한다 
그들은 input의 time ordering을 고려(take into account)하도록 design 되지 않아서 복잡한 time series data에 사용하는 것은 제한된다
Inherently-Interpretable modeling approaches는 feature selection에 대한 구성요소를 직접적으로 모델 architecture안에 build한다. 
Time series forecasting에 대해 Inherently-Interpretable modeling approaches은 time-dependent variable의 기여를 명시적으로 정량화 하는 것에 장점이 있다.</p>
<p>Temporal importance와 variable selection을 결합한 method들은 이미 고려됐었다. 이 method들은각각으로부터 계산된 attention weights(VSN 우측 확인)에 기반해서 single contribution coefficient를 계산한다</p>
<p>하지만, 한 스텝 앞 forecasts modeling의 Shortcoming에 더하여 existing method들은 또한 attention weight 들의 <strong>특정한 sample 에 대한 interpretation에 집중한다는 것이다(각각의 시점이 서로에게 얼마나 영향을 미치는지)</strong>- 이는 global temporal dynamics에 대한 insights를 제공하지 않는다</p>
<p>이와 대조돼서 sec7에서 <strong>TFT는 global temporal relationship들을 분석하는 게 가능하다는 것 과 그리고 TFT는 user들에게 전체 dataset에 대해서 모델의 global behaviors를 해석하는 것을 가능케 한다는 것을 보여준다</strong>– specifically in the identification of any persistent patterns(e.g. seasonality or lag effects) and regimes(제도) present</p>
<blockquote>
<p><strong>Review&gt;</strong>
Abstract/Introduction/Related work에 대한 review
먼저 Multi-horizon forecasting에 대해서 현재까지 나온 모델들이 갖는 단점을 설명  한다 Multi-horizon forecasting에 관해서 현재까지 나온 Transformer기반의 모델들은 여러 데이터를 받아들이는 Multi-horizon forecasting에 대해 효과적이지 않고 Transformer 기반의 모델들은 오직 Temporal relationship에만 집중 돼있다 하지만 이 논문에서 제안하는 TFT는 특정 time step에서 여러 데이터들이 Target에 미치는 영향에 관한 insight를 제공하고 또한 기존의 Transformer 기반에 모델들과는 다르게 Interpretable self-attention과정에서 각각의 temporal relationship에만 집중하는 것이 아니라 우리 모델은 global temporal dynamics에 관한 insight를 제공할 수 있다 이러한 Interpretability로 기존의 black-model인 모델들과는 다르게 user들을 설득할 수 있고, 시계열에서 잘 맞지 않는 post-hoc method 대신해서 Target과 변수사이에 관계를 설명했다
이러한 Interpretability를 챙기면서도 SOTA성능을 달성한 것이 이 모델의 장점이다</p>
</blockquote>
<h2 id="multi-horizon-forecasting">Multi-horizon Forecasting</h2>
<p>주어진 time series dataset에 I라는 고유한 객체가 있다고 하자 (e.g. health care 분야에 각 환자)
이러한 각 entity i 는 static covariate 집합 $s_i\in\mathbb{R}^{{m}<em>{s}}$와 inputs $X</em>{i,t}\in\R^{m_x}$ 와 scalar target인 ${y}_{i,t}\in\R$ (for $t\in\ {[0,T}_i]$) 관계돼 있다.</p>
<p>Time-dependent input features는 두개의 category로 나눠진다 ${X}<em>{i,t}=[z</em>{i,t}^T , x_{i,t}^T ]^T$
<strong>observed input $z_{i,t}^T\in\mathbb{R}^{m_z}$</strong>: 이는 각 step마다 측정되고 그 이후는 모르는 상태이고
<strong>known Input $x_{i,t}\in\mathbb{R}^{m_z}$</strong>∶ 이는 미리 결정된다</p>
<p>많은 경우에, prediction intervals를 제공하는 것은 decision을 최적화하고 risk를 관리하는데 있어서 유용할 수 있다( lower bound와 upper bound를 제공함에 있어서 ) 
우리는 lower bound와 upper bound를 구하기 위해서 quantile regression을 우리의 multi-horizon forecasting setting 에 적용한다 각각의 quantile forecast는 다음과 같은 형태를 갖는다 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/9a8a4882-275d-4a0c-8491-83e672c2d1b4/image.png" alt=""></p>
<p>$\hat y_{i,t+τ} (q,t,τ)$는 t시점에서 ${\tau}$ step 앞 예측의 q- sample quantile이고 $f_q (.)$ 은 prediction model이다. 우리는 t로부터 k시점 이전 정보까지 사용한다</p>
<p>다른 direct methods와 마찬가지로 우리는 동시에 $τ<em>{max}$ time steps(i.e. $τ∈{1,..,$ $τ</em>{max}$}에 대해 output forecasts를 낸다.
우리는 forecast start time t까지 target, known inputs(observed input, predetermined input)를 사용하면서 모든 과거정보를 포함한다 
$y_{i,t-k:t}$=${y_{i,t-k},..,y_{i,t} } /z_{i,t-k:t}={z_{i,t-k},..,z_{i,t} }$  :  target/ observed inputs until the t
$x_{i,t-k:t+τ}={x_{i,t-k},..,x_{i,t+τ} }$ : Known inputs across the entire range</p>
<h1 id="model-architecture">Model Architecture</h1>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/bdc6dac2-e6e8-4f6c-8fcc-79bad6018a64/image.png" alt="">
TFT의 메인 구성요소는 다음과 같다
<strong>1.    Gating mechanisms:</strong> 이를 통해 architecture의 사용하지 않는 구성요소들을 Skip 한다
따라서 우리는 충분한 양의 데이터셋과 적절한 모델의 깊이 그리고 network에 복잡도를 챙길 수 있다 
<strong>2.    Variable selection networks:</strong> 매 time step마다 관련 있는 input variable을 선택한다
<strong>3.    Static covariate encoders:</strong> static feature들을 context vector의 encoding을 통해 network에 합친다 
<strong>4.    Temporal processing:</strong> Observed Input과 Known Input 모두에 대해 장기 단기 시간관계를 학습한다 Local Processing을 위해 seq2seq layer를 사용하고, Interpretable Multi-head attention을 통해 장기 의존성을 알아낸다
<strong>5.    Prediction Intervals:</strong> 각각의 prediction horizon에서 target value의 범위를 결정할 수 있도록 하기 위해서 quantile forecasts를 사용한다</p>
<h2 id="1----gating-mechanismgrn-gated-residual-network">1.    Gating Mechanism(GRN: Gated Residual Network)</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/8ea9d984-94c8-4d8a-b8ea-dd1c77253b35/image.png" alt="">
Exogenous inputs과 targets의 정확한 관계는 사전에 알려져 있지 않는다. 이는 어떤 variable들이 서로 관련이 있을지 예상하기 어렵게 만든다</p>
<h3 id="비선형성의-정도를-부여해주는-grn">비선형성의 정도를 부여해주는 GRN</h3>
<p>또한 필요한 비선형 처리의 정도를 결정하기 힘들고 <strong>단순한 모델들이 훨씬 효과적일 수 있는 작거나 잡음이 심한 데이터셋이 존재하기도 한다.</strong></p>
<p>이러한 motivation에 의해 
<strong>모델에게 필요한 곳에만 non-linear processing을 적용하는 유연성을 주기 위해,</strong> 우리는 Gated Residual Network(GRN)을 제안한다 </p>
<br>
GRN은 초기input값인 a와 선택적 context vector c를 받고 다음을 생성한다


<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/37a059e3-cd86-43b2-8c4c-d33c4c55907c/image.png" alt="">
$η<em>1∈R^{d</em>{model}}$ $η<em>2∈R^{d</em>{model}}$ 는 모두 중간층에 해당하고 layer normalization을 사용했고 오메가는 weight sharing을 나타내는 index이다 </p>
<p>$η<em>1$이후 외생변수들을 반영한 이 $\eta_1$을 얼마나 반영할지 GLU로 Gating 한다. 
$η_2$는 input에 비선형성과 외생변수의 영향을 부과해주는 역할을 수행한다
$W</em>{2,ω} a + W_{3,ω} c+ b_{2,ω} &gt;&gt; 0$ 일 때 ELU는 identity function으로 행동하고 
$W_{2,ω} a + W_{3,ω} c+ b_{2,ω} &lt;&lt; 0$ 일 때 ELU는 (거의)constant output을 낸다 </p>
<h4 id="glugating-layer-unit">GLU(Gating Layer Unit)</h4>
<p>우리는 GLU[모델 architecture의 gate를 의미]라는 gating layer를 architecture의 각부분에 사용함으로써 주어진 데이터셋[어떤 layer의 output]에 대해 architecture의 필요하지 않는 부분을 막는 유연성을 준다
GLU는 다음과 같다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/178af5a7-78b4-49e4-b36d-53e4c10b355e/image.png" alt=""></p>
<p>where
$W_{(.)}∈R^{d_{model} X d_{model}}$ , $b_{(.)} ∈R^{d_{model}}$ 는 각각 weight와 biases이다
⊙은 element-wise Hadamard product이다.
$γ∈R^{d_{model}}$ 인 Input
$\sigma$ = sigmoid function
<font color = purple>
GLU는 <strong>TFT에게</strong> ‘GRN이 original input a에 기여하는 정도’를 control하게 허용한다[a에 비선형성을 추가할지 말지 control + a에 외생변수의 영향을 얼마나 반영할지 control] – 필요하다면 nonlinear contribution을 막기 위해서 GLU output이 거의 0에 가깝게 만들 수 있다 이로써 layer전체를 skip하는 효과를 낸다 </font></p>
<blockquote>
<p>전적으로 모델에게 모든 것을 맡기는 구조이다.</p>
</blockquote>
<p>만약 context vector가 없다면 GRN은 context input을 0으로 취급한다 </p>
<h2 id="2----temporal-variable-selection-networks">2.    Temporal Variable Selection Networks</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/ce7dec73-6122-41ef-a1f8-fe31bec018f7/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/a48a65d8-8ad8-4d9c-8f56-1555ce71ed3b/image.png" alt=""></p>
<p>우리가 $m_χ$ 개의 data를 갖고 잇다고 가정하자 우리는 t시점에서의 variable selection을 통해 입력데이터를 encoding하고 싶은 상황이다. 각각의 data는 data의 종류에 따라 encoding 방식이 다를 것이고, 각각의 방식에 따라 이를 같은 크기의 벡터로 encoding을 시킨다 이를 여기선 $ξ_t^{(j)}$ 로 denote한다 이를 GRN에 통과시킴으로써 비선형성을 부과한 $\tilde ξ _t^{(j)}$로 만든다
총 $m_χ$개의 data의 t시점에 대해서 위와 같은 과정을 거친 후 이 각각의 data의 중요성을 판단하는 과정을 데이터를 Flatten시킨 $Ξ_t$ 와 static한 데이터의 context vector인 $c_s$를 GRN에 통과시킴으로써 비선형성을 부과하고 이때 output에 영향을 크게 미치는 data에 대해 높은 가중치를 주기를 기대한다 이후 Softmax를 통과시켜서 variable selection weights 인 일종의 score를 부과하고 이를 각각 곱하고 summation시켜서 최종적인 input을 만들어낸다  </p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/83012e17-12b4-4c7d-b58b-37f0776dd91d/image.png" alt=""></p>
<p>다양한 variables[Time series data]가 사용가능한 반면, 그들의 relevance와 구체적인 output에 대한 기여는 보통 알려져 있지 않다.</p>
<p>TFT는 static covariates와 time-dependent covariates를 둘 다 적용한 variable selection networks를 사용함으로써 instance(sample)[=각각의 time-step] 별로 variable selection을 제공한다
<strong>어떤 variable이 prediction problem에서 가장 중요한지 insights를 제공해주는 것[variable selection weight를 통해] 뿐만 아니라, variable selection은 TFT에게 예측 성능에 악영향을 미치는 불필요한 noisy input들을 제거할 수 있게 한다</strong></p>
<p>대부분의 실제 시계열 데이터셋에는 예측과 관련 없는 값들이 많으므로, 변수 선택은 모델의 성능향상에 큰 도움이 된다</p>
<blockquote>
<p>Categorical Variables에 대해서는 Entity Embedding을, Continuous Variables에 대해서는 Linear Transformation을 진행한다 – 이는 subsequent layer에 각각의 input variable을 d_model-dimensional 벡터로 변환하는 것이다</p>
</blockquote>
<p><strong>Repeat</strong>
모든 Static, past and future input들은 서로 다른 variable selection networks를 사용하고 이는 fig2에서 다른 색깔로 구분돼 있다 
$ξ<em>t^{(j)}∈R^{d</em>{model}}$ 를 시점 t에서 j번째 variable의 변환된 input이라고 denote 하자 {pronounce xi}
$Ξ_t=[ ξ_t^{(1)^T} ),..  ,ξ_t^{(m_x )^T } ]^T$ 는 시점 t에서 모든 input들의 Flatten된 vector이다.
Variable selection weights는 $Ξ_t$ 그리고 external context vector $c_s$를 GRN과 Softmax layer에 feeding을 함으로써 생성된다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/1ae00e9c-d0c9-4c1f-972e-3fd633cca16f/image.png" alt=""></p>
<p>Where
$v_{χ<em>t}∈R^{m_χ}$ 는 variable selection weights의 vector이다
Static한 데이터의 context vector $c_s$ 는 static covariate 인코더에서 얻어진다
우리는 각 시점에서 비 선형적인 processing을 GRN에 $ξ_t^{(j)}$를 feeding 함으로써 구한다
<font color = red>
<strong>Note</strong>
모든 variable은 모든 시점 t에 대해 가중치를 공유하는 그들 자신만의
$GRN</em>{ξ(j)}$ 을 갖는다[오메가의 역할: 이렇게 한 데이터셋에 대해 시점과 상관없이 같은 가중치를 같게 함으로써 시간이 지남에 따라 어떤 데이터가 Target에 미치는 전체적인 영향력을 반영 가능하다 (내의견)] 이러한 Processed feature는 그들의 variable selection weights를 곱하고 더한다 
</font></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/ab83b11a-e975-4efd-abbd-e06b9d9a94b1/image.png" alt=""></p>
<h2 id="3----static-covariate-encoders">3.    Static Covariate Encoders</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b3092355-e99e-4910-9b75-07e48f7192f6/image.png" alt="">
다른 time series forecasting architecture들과 달리, TFT는 정적인 메타데이터(데이터를 위한 데이터)로부터 정보를 합치기 위해 신중하게 디자인됐다
네 가지의 서로 다른 different context vectors, $c_s,c_e, c_c,c_h$를 만들기 위해서 서로 다른 GRN encoders를 사용한다 </p>
<ol>
<li><p>Variable selection에 사용하는 context vector인 $c_s$</p>
</li>
<li><p>local processing of temporal features에 사용하는 $c_c,c_h$ context vectors </p>
</li>
<li><p>Enriching of temporal features with static information에 사용하는 $c_e$ context vector 가 있다 </p>
</li>
</ol>
<p>예로써, $ζ$를 static variable selection network의 output이라 하자, temporal variable selection에 대한 contexts는 다음과 같이 encoding 된다 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d12d3576-c3a0-45b2-82c9-480ce77a5bd0/image.png" alt=""></p>
<h2 id="4----interpretable-multi-head-attention">4.    Interpretable Multi-head Attention</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/8b3cdc2d-0b58-4480-b252-2d80e27589e0/image.png" alt="">
TFT는 long-term dependency를 잘 capture하기 위해서 self-attention을 도입했다
우리는 attention의 explainability를 강화하기 위해서 transformer에서 사용하는 multi-head attention으로부터 약간 수정을 거쳤다
<strong>General한 self-attention&gt;</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/97978df6-3634-4598-9411-ab3ebe9b06a4/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f3048945-0583-49bf-9235-b2be4f3f81f8/image.png" alt=""></p>
<p>Standard attention mechanism의 learning하는 능력을 향상시키기 위해서 multi-head attention mechanism을 적용시켰다 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/18ba89d1-9b4c-4edc-b628-ef01dd030b3b/image.png" alt="">
<strong>각 head에서 다른 value들이 사용된다는 점을 고려하면, attention weight는 단독으로 특정 feature의 중요성을 나타낼 수 없다.</strong> 이러한 점 때문에 우리는 multi-head attention을 value를 공유하는 방향으로 수정하고 모든 head에 대해서 additive aggregation을 적용하고 평균을 취해주는 과정을 거친다 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/abf537e7-07d8-4c7c-929a-12a38a969e1d/image.png" alt="">
Where
$W_V∈R^{d_{model} X d_V}$는 모든 head에 걸쳐 공유되는 value weights이다 
$W_H∈R^{d_{attn} X d_{model}}$ 은 final linear mapping으로 사용된다</p>
<p>우리는 이를 Combined matrix $\tilde A(Q,K)$ 로의 attention weights에 대한 simple ensemble로 해석할 수 있다
A(Q,K) 와 비교했을 때 우리는 Value 별로 Attention score에 대해 효과적으로 설명할 수 있다 따라서 효과적인 방식으로 representation capacity를 향상시켰다고 할 수 있다</p>
<h2 id="5----temporal-fusion-decoder">5.    Temporal Fusion Decoder</h2>
<p>Temporal fusion decoder는 dataset에서 보여지는 temporal relationship을 배우기 위해서 아래와 같은 layers를 거친다 </p>
<h3 id="51----locality-enhancement-with-sequence-to-sequence-layerseq2seq-layer로-지역성-강화">5.1    Locality Enhancement with sequence-to-sequence layer(seq2seq layer로 지역성 강화)</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/1e6f8c2a-f696-4649-8089-1e67e41be4fe/image.png" alt=""></p>
<p><font color = red> Locality: 입력에서 각 sample간의 관계가 서로 가까운 요소들에 존재한다는 의미이다
Translation Invariance: 입력과 동일하게 계속해서 관계가 유지된다는 것을 말한다.
</font></p>
<p>시계열 데이터에서 주변 value들 사이의 관계는 매우 중요한데
따라서 attention-based architecture에서 Local context를 활용하는 것은 Performance 향상을 이끌 수 있다.(informer에서 1-D convolutional network)</p>
<HR>
[12] S. Li, et al., Enhancing the locality and breaking the memory bottleneck of transformer on time series forecasting, in: NeurIPS, 2019.
<HR>

<p>예를 들어, [12]에서는 지역성 강화를 위해 single convolutional layer를 채택한다 – extracting local patterns using the same filter across all time.</p>
<p>하지만, 이는 observed input들이 존재할 때 과거의 input 변수의 개수와 미래의 input변수의 개수가 다르기 때문에 적절하지 않을 수 있다.</p>
<blockquote>
<p>나의 해석
하나의 합성곱 신경망으로 Locality를 강화 시킬때, 미래에 입력받는 입력은 입력이 과거와 다르게 될 수 있는데, 이때의 입력값에 과거부터 사용한 합성곱 신경망의 가중치를 사용하는 것은 적절하지 않을 수 있다.</p>
</blockquote>
<p>이러한 점 때문에 우리는 이런 개수의 차이를 자연스럽게 handle할 수 있는 seq2seq모델의 적용을 제안한다 -  $\tilde ξ<em>{t-k:t}$  가 encoder에 feeding되고  $\tilde ξ</em>{t+1:t+τ_{max}}$ 가 decoder에 feeding 된다.
그러면 이는 uniform 한 temporal feature들의 집합을 생성한다 이는 temporal fusion decoder에 input으로써 serving된다 
Denote (pronounce pi)
$ϕ(t,n) ∈ { ϕ(t,-k),..  ,ϕ(t,τ_max )   }$
n is position index.</p>
<p>이런 LSTM cell series를 적용하는 것은 Inputs의 시간 순서에 대해 적절한 inductive bias 를 주면서 <font color = red>(Sequential &amp; Temporal Invariance의 Relational Inductive Biases를 갖는다. Sequential이란 입력이 시계열의 특징을 갖는다고 가정하며, Temporal Invariance는 동일한 순서로 입력이 들어오면 출력 순서도 동일하다는 것을 말한다.) </font></p>
<blockquote>
<p><strong>Inductive Bias는 보지 못한 데이터에 대해서도 귀납적 추론이 가능하도록 하는 알고리즘이 가지고 있는 특징.</strong><br>
Ex&gt; CNN의 Locality&amp; Translation Invariance
 여기서, Localitiy는 입력에서 각 Entities간의 관계가 서로 가까운 요소들에 존재한다는 것을 의미한다. 그리고 Translation Invariance란 입력과 동일하게 계속해서 관계가 유지된다는 것을 말한다. 이는 무엇을 의미할까? 어떤 특징을 가지는 요소들이 서로 모여있는지가 중요한 문제에서 좋은 성능을 보여준다는 것을 의미한다. 이러한 이유에서 CNN이 이미지 관련 문제에서 강점을 보이는 것이다.<br>
Ex&gt; RNN의 Sequential &amp; Temporal Invariance
RNN은 시간의 개념을 사용하는 것이다. RNN에서는 CNN의 Locality &amp; Translation Invariance와 유사한 개념으로 Sequential &amp; Temporal Invariance의 Relational Inductive Biases를 갖는다. Sequential이란 입력이 시계열의 특징을 갖는다고 가정하며, Temporal Invariance는 동일한 순서로 입력이 들어오면 출력도 동일하다는 것을 말한다.
  ** <font size =5>이러한 가정들의 장점은 가정이 맞는 경우 좋은 성능을 보여준다는 것이다. 하지만, 가정이 맞지 않는 경우에는 매우 약한 모습을 보여준다.</font> **
<a href="https://re-code-cord.tistory.com/entry/Inductive-Bias%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C">출처</a></p>
</blockquote>
<p>더욱이 local processing에 영향을 미치는 static metadata를 고려하기 위해서 $c_c,c_h$ context vector를 각각 cell state와 hidden state의 초기값으로 사용한다 
또한 우리는 gated skip connection을 이 layer위에 적용한다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/71b76159-38ee-443f-a600-0cc8d9aa0e03/image.png" alt=""></p>
<p>Gate를 통해서 영향을 받지 않은 값에 Gating 하여 흘려보내준다.(Likely, Residual Connection)</p>
<h2 id="52----static-enrichment-layer">5.2    Static Enrichment Layer</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/8bd7ebb8-da1f-4115-a57a-2da24e62bf1c/image.png" alt=""></p>
<p>Static covariates는 자주 큰 영향력을 갖고 있어서 temporal dynamics에 큰 영향을 미친다 [e.g. 시간에 따른 disease risk에서 특정 유전자의 영향] 
우리는 static metadata와 함께 temporal feature를 강화하는 static enrichment layer를 소개한다
주어진 position index n에 대해 static enrichment는 다음과 같은 형태를 갖는다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e44a1256-e116-4cbe-a381-9a039739797a/image.png" alt="">
이때 $GRN_θ$의 가중치는 전체 layer에 걸쳐 공유되고, $c_e$는 static covariate encoder로부터 구해진context vector이다</p>
<h2 id="53----temporal-self-attention-layer">5.3.    Temporal Self-Attention Layer</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/ffad33a1-eed9-4d7f-8540-cd613396bbea/image.png" alt=""></p>
<p>  Static enrichment이후에 우리는 self-attention을 적용한다 
먼저 모든 Static-enrichment output을 하나의 single matrix로 Group화 한다 – $i.e. Θ(t) = [θ(t,-k),..,θ(t,τ)]^T$ 
그리고 interpretable multi-head attention을 각각의 forecast time에 적용한다(With $N=τ_{max}+k+1$)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/5b0c8a13-8ce8-4f02-ab3d-77fe8ee776cb/image.png" alt=""></p>
<p>$B(t) = [β(t,-k),..,β(t,τ<em>max )]^T$ 이다
$d_V = d</em>{attn}=d_{model}/m_H$  는 선택되며, $m_H$ 는 head의 개수이다</p>
<p><strong>Decoder masking은 각각의 temporal dimension 이전의 feature들에 대해서만 참여할 수 있는 것을 보장하기위해 적용한다</strong>
게다가 masking을 통해 <strong>causal information</strong>을 유지하면서, TFT가 RNN base architecture가 학습하기 어려운 long range dependency를 학습할 수 있게 만들어줬다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/6f35b87d-e254-4293-81e4-58f5cd2707ac/image.png" alt=""></p>
<blockquote>
<p><font color = blue>위 그림은 실제로 forecast를 하는 것에 대한 그림이다 따라서 아래의 GLU를 forecast time에만 적용을 했고 이를 통해 생각해 볼 수 있는 것은 training과정에서는 Masked Interpretable Multi-head Attention을 적용해서 나오는 output을 $t+τ<em>{max}$까지 만들어서 가중치를 training시키고 실제로 forecast할 때는 나오는 output을 $τ</em>{max}$ 개만큼만 사용하여 forecasting 한다
</font></p>
</blockquote>
<p>Self-attention layer다음으로 추가적인 gating layer를 적용함으로써 training이 가능하게 했다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/38703d1f-158e-4a64-9eb9-ea1294aea4a3/image.png" alt=""></p>
<h2 id="54-----position-wise-feed-forward-layer">5.4.     Position-wise Feed-forward Layer</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/39ea83ea-54f1-4a05-951c-9f3604663f90/image.png" alt="">
우리는 self-attention layer의 outputs에 추가적인 non-linear processing을 적용한다 
Static enrichment layer와 비슷하게, 이는 GRN의 사용으로 만들어진다:
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d24888aa-ffce-4a04-9a4b-96f30e2c356e/image.png" alt="">
$GRN_ψ$의 가중치는 전체 layer에 걸쳐서 공유된다. 또한 우리는 gated residual connection을 적용하는데 이는 전체 transformer block을 건너 뛰어서 연결된다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3c180292-0ae9-49e2-b536-3e38d9f600be/image.png" alt="">
이렇게 residual connection을 함으로써 decoder를 거친 값을 얼마나 반영할지 정해준다.</p>
<p>&rightarrow; Temporal fusion decoder를 거치지 않을 경우는 그냥 time-series의 seq2seq 모델임</p>
<h2 id="55quantile-outputs">5.5.Quantile Outputs</h2>
<p>TFT는 Prediction Intervals를 생성한다.
이는 매 time step에서 다양한 percentiles(10,50,90)에 대한 동시 예측을 통해서 얻어진다
Quantile forecasts는 temporal fusion decoder의 output으로부터 linear transformation을 사용해서 생성된다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c38b6e78-3c6b-4d25-a26b-dafefb0960c0/image.png" alt="">
Where
W_q∈R^(1 X d), b_q∈R 는 특정한 quantile q에 대한 계수들
Note
Forecasts are only generated for horizons in the future – i.e. 〖τ∈{1,..,τ〗_max}</p>
<h1 id="loss-function">Loss function</h1>
<p>TFT는 jointly minimizing the quantile loss에 의해 training된다<br><img src="https://velog.velcdn.com/images/leesungjoon-net/post/6127979d-2dc7-4093-a7cf-a4a1a2b146ed/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/515a811c-8f12-4761-b6f0-cb4c569a69d9/image.png" alt="">
  $t-\tau$까지는 예측하고자하는 target의 정보를 사용한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b6926817-89dc-496b-8b2c-7bb61c543d0b/image.png" alt="">
$L(Ω,W)$의 목적은 t시점과 우리가 정한 quantile 들의 집합인 Q의 각 quantile에 따라 t시점을 예측하는데 tau에 따라 다음을 $\hat y(q,t-τ,τ)$ 예측하고 이들의 quantile loss를 구하고 평균을 한 후 $y_t$의 데이터셋을 바꿔가면서 summation후에 평균을 한다 
우리는 q-Risk를 사용하는데 이는 entire forecasting horizon에 걸쳐 normalized한 quantile loss식이다(weighted quantile loss)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/ee7370dc-ea90-4bd1-ba8d-883bc287bd3e/image.png" alt=""></p>
<h1 id="interpretability-use-cases">Interpretability use cases</h1>
<p>우리 모델의 Performance benefits를 확립한 이후, we next demonstrate how our model design allows for analysis of its individual components to interpret the general relationships it has learned 우리는 3가지의 interpretability use cases를 보여줄 것이다
(1)    예측에 들어가는 input variable 각각의 중요성을 examining
(2)    Persistent temporal patterns를 visualizing
(3)    Temporal dynamics안에 중대한 변화를 이끄는 any regimes(제도) 또는 사건들을 identifying</p>
<h2 id="analyzing-variable-importance">Analyzing Variable Importance</h2>
<p>우리는 먼저 variable selection weights를 분석함으로써 variable importance를 알 수 있다.
구체적으로, 전체 test set에 걸쳐 각각의 variable에 대해 selection weights를 모으고 이렇게 모은 variable selection weights의 percentile들을 기록한다
Retail dataset은 이용가능한 input types(i.e. static metadata, known inputs, observed inputs and the target)를 모두 포함하고 있기 때문에, 우리는 Table3에서 그것들의 variable importance analysis에 대한 결과를 Table3에서 보인다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d334467f-250c-45e8-a7e4-c3d57db253ff/image.png" alt=""></p>
<ul>
<li>Static covariates에 대해서는 variable 독특하게 다른 객체들을 확인하는 variable이 large weight를 갖는다(Item Num, Store Num)</li>
<li>Past inputs에 대해서는 target의 과거 values가 예상대로 critical 했다</li>
<li>Future inputs에 대해서는 promotion periods와 national holidays가 가장 큰 영향력을 지녔다</li>
</ul>
<p>Table3에서 결과는 TFT가 직관적으로 예측에서 중요한 역할을 하는 key inputs를 추출하는 것을 보인다</p>
<h2 id="persistent-temporal-patterns">persistent temporal patterns</h2>
<p>persistent temporal patterns의 분석은 주어진 데이터에 나타나는 time-dependent relationships를 이해하기위해서 자주 핵심이 된다
예를 들어 lag models는 영향이 있기까지 필요한 시간을 연구하기 위해 자주 채택된다</p>
<ul>
<li>Such as 정부의 공공지출 증가가 국민총생산(Gross National Product)의 중가에 미치는 영향</li>
</ul>
<p>Seasonality models 또한 흔히 경제 분야에서 흥미 있는 target의 주기성 패턴과 cycle의 길이를 알아보기 위해서 사용된다</p>
<p>&rightarrow;    이전까지 Persistent temporal pattern을 알아보기 위한 방법들</p>
<p>실용적인 견해로부터, 모델 설계자들은 forecasting model의 성능을 더욱 향상시키기 위해서 아래와 같은 insights를 사용할 수 있다
– 예를 들어 만약 attention peaks가 lookback window의 시작에서 관찰 된다면 더 많은 history를 포함하기 위해서 lookback window(=receptive field[ in paper ])를 증가시키거나 seasonal effects를 직접적으로 포함하기 위해서 feature engineering을 할 수 있다</p>
<p>이와 같이, temporal fusion decoder의 self-attention layer에 존재하는 attention weights를 사용하여 우리는 similar persistent patterns를 확인하는 method를 제시한다 
-&gt; interpretability self-attention</p>
<p>Eq.14와 19을 결합하여, 우리는 self-attention layer가 각각의 forecast time t에서 attention weights의 행렬을 포함하는 것을 본다 – i.e. $\tilde A(ϕ(t),ϕ(t)).$</p>
<p> <img src="https://velog.velcdn.com/images/leesungjoon-net/post/e2dd6aff-bf9b-4b61-b205-2d5223e49971/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/0e0d0122-d414-40a1-9320-84bd9b92fc07/image.png" alt=""></p>
<p>각 forecast horizon $τ$ 에서 Multi-head attention outputs(i.e. $β(t, τ)$)는 각각의 position n에서 더 낮은 level의 feature들의 attention-weighted sum으로 표현할 수 있다
  <img src="https://velog.velcdn.com/images/leesungjoon-net/post/5a86bc29-efe1-48b7-8388-b883a07e5163/image.png" alt="">
Where $α(t,n,τ)$ 는 $\tilde A(ϕ(t),ϕ(t))$ 의 $(τ,n)$번째의 element[즉, n번째 key와 $\tau$번째 query사이의 유사도 score] 그리고 $\tildeθ(t,n)$은 $\tilde Θ(t)= Θ(t) W_V$의 n번째 row이다</p>
<p>&rightarrow;    결론: </p>
<ol>
<li>TFT의 Variable selection이 직관적으로 예측에서 중요한 역할을 하는 feature들을 뽑아낼 수 있다</li>
<li>TFT의 interpretability self-attention이 예측에 미치는 기여도를 측정함으로써 similar persistent pattern을 확인 할 수 있다  </li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting]]></title>
            <link>https://velog.io/@leesungjoon-net/Informer-Beyond-Efficient-Transformer-for-Long-Sequence-Time-Series-Forecasting</link>
            <guid>https://velog.io/@leesungjoon-net/Informer-Beyond-Efficient-Transformer-for-Long-Sequence-Time-Series-Forecasting</guid>
            <pubDate>Fri, 01 Sep 2023 07:50:12 GMT</pubDate>
            <description><![CDATA[<p>22년 11월에 읽었던 논문을 거의 1년이 지나가서야 블로그에 업로드 하게 됐다. 이미 word로 정리는 해뒀지만 때를 놓쳤다가 복습할겸해서 업로드를 한다.
<del>이 논문 말고도 쌓여있는 논문이 너무 많다.</del></p>
<h2 id="abstract">Abstract</h2>
<p>Long Sequence Time-Series Forecasting(LSTF)는 모델의 높은 예측능력을 요구한다. 과거와 현재를 효과적으로 Coupling 하는 능력을 요구하고 최근의 연구인 Transformer는 이 측면에 대해서 잠재력을 보여줬다 
하지만 바로 LSTF에 적용하기에는 몇가지 Transformer에 관한 문제들이 있는데 </p>
<ol>
<li>Quadratic 한 Time Complexity</li>
<li>High memory usage</li>
<li>encoder-decoder architecture 내재된 한계</li>
</ol>
<p>모델은 3가지의 특성을 지니고 있는데</p>
<p>1.Self-attention에서 ProbSparse를 사용해서 time complexity O(L log L)와 memory usage를 낮췄음에도 Transformer와 비교했을때 sequence의 dependency 부분에서 비슷한 성능을 냈다.</p>
<p>2.Self-attention에서 dominating한 attention을 강조했다.</p>
<p>3.Generative style decoder 로써 long time-series sequence를 한번의 forward operation을 통해 예측한다 </p>
<h2 id="introduction">Introduction</h2>
<p>Time-series forecasting은 여러 domain에 걸쳐 critical한 요소이다.
우리는 많은 양의 과거에 대한 Time series Data를 LSTF(Long Sequence Timeseries Forecasting)를 위해 사용할 수 있다.
하지만, 현존하는 방법론들은 대부분 short-term 문제를 풀기 위해 고안된 것이 많다. Short-term예측이라고 하면 48개 이하의 시점에 대한 예측을 말한다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/daa5d0d3-1479-4ea8-9d96-8eb18ad489b6/image.png" alt="">
(a), Figure는 LSTF가 short sequence prediction보다 더 많은 period를 커버할 수 있음을 보여주고
(b), Figure는 현존하는 모델들이 LSTF에 대한 Performance가 떨어짐을 보여준다</p>
<p>-&gt;초당 예측길이가 sequence length가 길어지면 길어질수록 계속해서 떨어지고 있고, MSE Score또한 지속적으로 올라감을 볼 수 있다</p>
<p>LSTF에대한 Major Challenge는 Long Sequence에 대한 수요를 충족시키기 위해 예측능력을 강화 하는 것에 있다. 다음과 같은 것을 요구하는데
(a)    뛰어난 long-range alignment ability
(=과거 데이터를 얼마나 반영할 수 있느냐)
(b)    Long sequence input과 output에 대한 효율적인 계산</p>
<ul>
<li>최근에 Transformer 모델은 Long-range dependency capturing 하는 것에 대해서 매우 뛰어난 Performance를 보여줬다</li>
<li>Transformer의 self-attention mechanism은 Recurrent한 구조를 사용하지 않기 때문에 maximum path length가 O(1)[Theoretical Shortest]이 된다<font color = red>
Maximum path length: 특정 시점의 Token을 과거 시점의 Token과 비교하고 싶을 때 필요한 계산 횟수이다 RNN의 경우 특정 token이 매 RNN cell에서 들어가기 때문에 a시점에서의 토큰과 과거 시점 b사이의 토큰을 비교하고 싶으면 a-b만큼의 연산이 필요했지만 Transformer는 하나의 Matrix를 사용했기 때문에 self attention에서 필요한 계산이 한번뿐이다</font>

</li>
</ul>
<p>이로써 Transformer는 LSTF문제에서 훌륭한 잠재력을 보여준다 
하지만 LSTF는 위에 (b)에 관련한 문제 때문에 Training을 할 때 10여개의 GPU와 큰 deploying cost에 의해  Real-word LSTF에서는  사용하기 힘들다
따라서 이 paper에선 Transformer의 높은 예측 성능을 유지하면서도 Time complexity와 memory usage를 효율적이게 만들 수 있는 방법이 없을까?” 에 대한 답을 구할 것이다</p>
<p>Vanilla Transformation은 LSTF 문제를 푸는데 다음과 같은 3가지의 중요한 한계점이 있다</p>
<ol>
<li>The quadratic computation of self-attention(quadratic 한 연산)
: self-attention mechanism에서 기본 구성 요소인 dot-product는 각각의 layer마다 $0(L^2)$  의 time complexity and memory usage를 발생시킨다    <br></li>
<li>The memory bottleneck in stacking layers for long inputs(layer를 stack 하는데 있어서 memory bottleneck이 생김)
: J개의 encoder/decoder layer를 쌓음으로써 전체 memory usage가 $0(J⋅L^2)$ 로 되고 이는 long sequence inputs를 받아들이는데 있어서 모델 확장성(Scalability)의 limit이 된다.</li>
</ol>
<p><strong>Scalability: 데이터의 크기가 커져도 모델이 잘 작동할 수 있는 능력</strong><br>
3. The speed plunge in predicting long outputs(long output을 예측하는데 있어 속도가 급락한다)
: Vanilla Transformer의 Dynamic Decoding은 step-by-step으로 추정을 하는데 이거는 RNN base model만큼이나 느리다</p>
<p>구조는 다음과 같고 논문에 마지막에서 자세히 설명하겠다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f13db185-92e3-42cd-91a5-2530a3c785fc/image.png" alt=""></p>
<h2 id="preliminary">Preliminary</h2>
<p>LSTF problem definition
우리는 먼저 LSTF problem를 정의하겠다.
Input:  $χ^t=$ {$x_1^t,⋯,x_{L_x}^t | x_i^t ϵR^{ⅆ<em>x}$}
Output: $Y^t=${$y_1^t,⋯,y</em>{L_y}^t | y_i^t ϵR^{d_y}$}
LSTF problem는 이전의 연구들(Cho et al. 2014; Sutskever, Vinyals, and Le 2014) 보다 output의 길이인 $L_y$가 더 길 때로 정의한다
그리고 feature dimension 이 univariate한 Case로 제한하지 않는다 ($d_y$ ≥ 1) </p>
<p><strong>Encoder Decoder architecture</strong>
많은 모델들은 encode 과정에서 input이 hidden state를 통해 output으로 decoding되는 구조로 고안됐다 
그 추론과정은 “dynamic decoding”이라고 불리는 step-by-step 과정을 포함한다 이는 이전의 hidden state와 이전의 output을 통해 현시점의 새로운 hidden state를 계산하고 현 시점의 sequence를 예측하는 것을 말한다</p>
<p><strong>Input Representation</strong>
Uniform input representation은 time-series input의 global positional context와 local temporal context를 잘 반영할 수 있게 해준다 
<strong>Appendix B&gt; The Uniform Input Representation</strong>
Vanilla transformer는 local positional context로 time stamp를 찍어준다
하지만 Long Sequence Timeseries Forecasting문제에서 long-range dependence를 capture하는 능력은 hierarchical(계층적) time stamp(week,month and year) 나 agnostic time stamp(ex. Christ mas) 같은 global information이 필요하다
여기서 문제는 global information은 canonical(일반적인)self-attention에 활용되지 않고, 그로 인해 발생하는 encoder, decoder 사이에 query-key mismatch가 forecasting performance에 degradation을 가져온다</p>
<p>우리는 이런 문제를 완화시키기(to mitigate) 위해 uniform input representation을 제안한다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/16d9c3b1-42b6-43eb-9e03-e1062467526c/image.png" alt=""></p>
<p>Local time stamp는 다음과 같이 positional embedding할 수 있다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3734462c-b91c-416e-ae66-251c4f198b62/image.png" alt=""></p>
<p>Where <img src="https://velog.velcdn.com/images/leesungjoon-net/post/02e5da1e-f9b7-4de4-bc68-5f5d977e7edb/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/dee1b831-93e7-4ccb-8f06-7674714b21f2/image.png" alt="">
<a href="https://github.com/Doheon/TimeSeriesForecast-Informer/blob/main/models/embed.py">Github</a></p>
<p>또한 우리는 시계열 데이터 Input scalar의 dimension을 1-D convolutional filters(kernel width=3,stride=1) 를 통해 projection 시켜서 사용한다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b5cb87e1-02c2-40f5-8ad3-56420384f55f/image.png" alt="">
<a href="https://pseudo-lab.github.io/Tutorial-Book/chapters/time-series/Ch5-CNN-LSTM.html">출처</a></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/0ec2168e-137f-4115-b1d4-bbe5ac0831ff/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/1299b500-0d52-4555-997b-b5208fd76c95/image.png" alt="">
따라서 우리는 Scalar x를 convolution network를 통해 512차원의 벡터로 바꿨다(by padding)</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e2fe64f5-8e84-47f8-9a14-fb84278d1bc5/image.png" alt="">
Where ⅈ∈{1,⋯,L_x }, and alpha is the factor balancing the magnitude between the scalar projection and local/global embeddings. 우리는 sequence input이 normalizing 됐다면 alpha=1을 추천한다</p>
<h2 id="methodology">Methodology</h2>
<p>우리가 제안하는 Informer는 encoder-decoder architecture를 사용한다
<strong>Efficient Self-attention Mechanism</strong>
일반적인 Self-attention은 다음과 같이 정의된다</p>
<blockquote>
<p>Transofmer review
$A(Q,K,V) = Softmax(QK’/sqrt(d))V ( ‘=transpose )$
$Where, QϵR^{L_Q Xd}, KϵR^{L_K Xd}, VϵR^{L_V Xd}$ and d is input dimension<br>
i번째 query의 attention은 다음과 같이 kernel function(여기서는 dot-product로 정의)을 통해 확률형태로 정의된다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f167ac7c-7616-4d7f-aa92-8ad1b57ec344/image.png" alt="">
(원래 self attention을 하는 과정을 가중평균의 관점에서 해석한 식)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d56b4931-0e12-4d0c-8f9f-6c6e19e6a464/image.png" alt=""></p>
</blockquote>
<p>self-attention을 계산할 때는 Quadratic한( O(L_Q L_K )  ) time dot-product computation와 memory usage가 필요하다.
&rightarrow;이는 예측능력을 향상시키는 데에 있어 주된 문제점이다</p>
<p>attention-score는 Sparsity(희소성)을 갖는다( 여기서 Sparsity는 의미 있는 값이 몇가지 없고 나머지는 다 0에 가까운 값이라는 의미)
따라서 이전의 연구자들은 Forecasting Performance의 변함이 거의 없이 어떻게 하면 좋은 attention score만  잘 선택할 수 있을까 고민을 했다 
하지만 그들은 모든 multi-head self-attention에 같은 방식을 사용함으로써 추가적인 개선을 해내지 못했고 heuristic한 method를 사용했다
<font color = blue>
Sparsity한 self-attention score는 long tail distribution형태인데 이는 몇가지의 dot-product pairs만 major attention에 기여를 하고 다른 pairs들은 trivial한 attention(별 의미가 없는 attention)을 갖는다 이는 곧 어떻게 그들을 구분할 수 있는지에 대한 질문으로 이어진다</font>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7cd97ddd-5d47-4b82-88eb-32dc2208945c/image.png" alt=""></p>
<blockquote>
<p>XAI를 공부할때 attention score를 attribution score로 볼 수 있음을 확인했다. 추후 XAI에 대해서 또 따로 올리겠다(word 50pg 정도 분량이라 시간이 좀 필요하다)</p>
</blockquote>
<p><strong>Query Sparsity Measurement</strong>
위에서 본 Eq.(1)은 i번째 query의 attention 계산 과정을 설명하고 있다
우리는 dominant한 attention score를 가지는 query-key pair는 attention score의 분포가 uniform distribution($q(k_j|q_i)=1/L_k$)와 떨어져 있을 것임을 알 수있다</p>
<p><strong>Time Series는 매우 많은 시점들이 하나의 시점에 영향을 주고 있다고 생각할 수 있다.</strong> 물론 자기자신과의 관계성도 높게 나올 것 이지만 이외에도 관련 있는 것이 매우 많을 것이고 따라서 대부분의 시점에 대해서는 관계성이 낮게 나올테지만 특정시점에 대해서는 관계성이 높게 나올 것이다</p>
<p>우리는 이런 분포 p , q사이의 Likeness를 측정하는 방법으로 KL divergence를 사용 할 것이다.<a href="https://velog.io/@leesungjoon-net/%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC%EC%99%80-%ED%81%AC%EB%A1%9C%EC%8A%A4%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC-KL-Divergence">KLDIVERGENCE MY BLOG</a>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/750f9eef-cb6c-47af-80ce-85fd824ce314/image.png" alt="">
우리는 여기서 상수를 drop해서 i-th query’s sparsity measurement를 다음과 같이 쓸 수 있다(Query가 얼마나 Sparse한지 측정하는 지표 M)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/0c4a3429-9480-4322-b212-e075c017ac18/image.png" alt=""></p>
<blockquote>
<p>식 유도 (q = 정답분포, p =  예측분포)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c2e21f34-90cf-4be3-a6e5-8c0823e314e7/image.png" alt=""></p>
</blockquote>
<p><strong>ProbSparse Self-attention</strong>
위에서 계산한 query’s sparsity measurement에서 top <strong>u</strong>개<strong>[예측분포와 정답 분포사이의 유사도가 잘 맞지 않는 것들]</strong>의 query들을 포함하는 matrix를 $\bar Q$ Sparse Matrix라고 하고 ProbSparse Self-attention은 다음과 같이 계산한다
 <img src="https://velog.velcdn.com/images/leesungjoon-net/post/d0dea33c-9871-45b0-aaa0-8dc2ff26f185/image.png" alt=""></p>
<p>이때 $u = c ∘ln(L_Q)$ 이고 이때 c는 constant sampling factor로써 우리가 조절하는 조절자(hyperparameter)이다</p>
<p>ProbSparse Self-attention을 계산함으로써 우리는 $O(ln(L_Q))$ 만큼의 쿼리에 대해서만 dot-product연산만 하면 되고 $O(L_Kln(L_Q))$ 의 memory를 사용한다 
Multi-head의 관점에서 각각의 head에 대해서 다른 query-key pairs를 생성하고 결과에서 정보손실을 피하게 된다.
하지만 모든 query에 대해 query’s sparsity measurement( $M(q_i,K)$)를 계산하기 위해서는 우리는
각각의 dot-product pairs의 계산이 필요하다 이는 Quadratic한 계산비용($O(L_K⁡*L_Q)$)이 필요하다
게다가 Log-Sum-Exp(LSE) operation은 수치적인 안정성 문제가 있다
이것이 동기가 돼서 우리는 효과적으로 query’s sparsity measurement를 얻기 위해 경험적인 근사방법(empirical approximation)을 제안한다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/2606b581-3d54-4677-8d9a-6db8decff4b7/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/107b2996-32aa-4c40-ab06-af16f575c23d/image.png" alt="">
Lemma1에 의해서 M의 최대 최솟값을 제한하고 아래의 M(bar)를 query’s sparsity measurement 경험적인 근사값으로 사용한다
Proposition1은 M(bar)가 M을 대표할 수 있음을 보이고 동시에 모든 query에 key를 계산한 것과 모든 query의 Sampling된 key를 통해 계산한 query’s sparsity measurement(M) 계산 결과(순서)가 동일함을 나타낸다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/84a29124-c270-4e71-8737-f1233414a1b4/image.png" alt=""></p>
<ul>
<li>$\bar M$은 Max에서 Mean을 빼는 것이기 때문에 파란색 분포가 빨간색 분포보다 크다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/337fa8c6-d714-4b92-baef-1578e0be8c5d/image.png" alt=""></li>
</ul>
<p>$\bar M$를 얻기 위해서 $O(L_k L_Q)$ 만큼의 연산이 필요했지만 이는 Key를 $ln L_K$만큼 random하게 뽑아서 모든 Q와의 계산으로 Sample Score를 얻음으로써 해결한다 따라서 $O(L_Q ln L_K)$의 복잡도로 $\bar M$를 계산한다 그후 Top-u개의 query를 뽑아 $\bar Q$ 를 얻어낸다
아래는 ProbSparse self-attention의 알고리즘을 나타낸다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/4564ef3d-c881-46ec-ae05-bf2dddc890c8/image.png" alt=""></p>
<p>위 알고리즘을 통해 우리는
$ln ⁡L_k$ 개만큼의 Key를 뽑아서  $\bar K$ 를 만들고 이 Key(bar)와 Query들의 pair의 개수 $U=L_Q  ln⁡L_k$
이렇게 sampling된 key 이용해서 $\bar M$ 를 계산하는 것을 알 수있다
우리는 $\bar M$를 사용하면서 안에 있는 max-operator가 zero value에 대해 덜 민감하고 수치적으로 안정시켰다 (LSE를 사용하지 않았기 때문)</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/24a55281-1db7-464b-b925-3b649e9b9e60/image.png" alt=""></p>
<h2 id="encoder-allowing-for-processing-longer-sequential-inputs-under-the-memory-usage-limitation">Encoder: Allowing for Processing Longer Sequential Inputs under the Memory Usage Limitation</h2>
<p>Encoder는 long sequence input에 대해 robust한 long-range dependency를 추출하도록 디자인됐다.
Input representation과정이후 우리는 Scalar는 Conv1d Time stamp(global/local)는 LinearLayer를 통과하여 이를 더함으로써 t번째 Sequence input $χ^t$ 를 matrix 형태인 $X_{ⅇn}^t∈R^{L_x×ⅆ_{model}}$ 로 바뀌었다 </p>
<p>다시 설명하면 위의 그림에서 확인할 수 있듯이 아까 input representation과정에서 우리의 Input scalar $x^t$ 를 1-D convolutional filter(kernel width=3, stride=1)인 필터로 $u^t$ (d_model dimension=512) 로 바꿨다</p>
<p>이를 우리가 train 하고 싶은 시간 간격 t=50(설명을 위해 내가 설정한 시간)에 대해서 실행하면 50x512(L_x×ⅆ<em>{model}) 크기의 행렬로 바뀔 것이다
또 우리는 Local time stamp와 global time stamp를 각각 encoding과정을 통해서 L_x×ⅆ_model 의 크기로 되고 이들을 더하는 과정을 거쳐서 우리는 입력 데이터 행렬 x</em>{en}로 만든다</p>
<h3 id="self-attention-distilling">Self-attention Distilling</h3>
<ul>
<li>(보라색 파란색 초록색 그림에 해당하는 설명)</li>
</ul>
<p>ProbSparse self-attention mechanism의 자연스러운 결과로써 encoder의 feature map은 value V의 combination을 갖는다 
우리는 distilling operation의 convolution과정을 통해 특정 시간을 평활화(smoothing)하는 과정 뒤에 maxpooling과정을 통해 대표값을 하나 뽑는 과정을 거칠 것이다 이과정에서 Input의 시간차원$(L_x)$를 많이 깎는다
우리의 j 번째 layer에서 j+1번째 layer로 가는 distilling procedure는 다음과 같다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/77cf7a41-0e1b-496d-b968-b8b08ab7082d/image.png" alt="">
$[⋅]_{AB}$는 Attention block을 나타내고 이는 Multi-head ProbSparse self attention과 필요한 작업들을 포함하고 있다 </p>
<blockquote>
<p>Attention작업 도식화
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/85645d1f-07d5-4926-8430-25ce3399784f/image.png" alt="">
&lt;수정&gt;
섞는다는 표현은 반은 맞고 반은 틀린 표현인데 Training이 가능한 가중치를 곱해줌으로써 중요한 정보와 덜 중요한 정보들의 가중치를 조절하면서 최적의 정보를 갖는 행을 만들어 내겠다는 의미이다</p>
</blockquote>
<p>Where Conv1d(⋅) 는 1-D convolutional filters(kernel width=3, padding=1,padding_mode=circular) 을 time dimension 에 대해서 실시하고 ELU(⋅) activation function을 거친다
<strong>Conv1d를 통해 각 Feature별로 Time Series의 흐름을 뽑아내는 작업을 거친다(Smoothing 같은 과정)</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d17a6455-cb3d-461c-a990-50cb9145bd5b/image.png" alt="">
이후 maxpooling(kernel_size=3, stride=2)를 통해서 ProbSparse self-attention을 거쳐서 나온 output의 각 Feature별로 주요한 정보흐름을 Capture해낸다
이후 같은 과정 반복한다 그러면 우리의 총 메모리 사용량은
$0((2-ε)LlogL$)으로 줄어들고 이는 self-attention computation complexity에 해당하는 메모리 LlogL이 $2-\epsilon$만큼 필요하다는 것이다 -&gt; J개의 stacking layer에 대한 memory bottleneck 문제를 해결한 것이다( = Layer를 쌓아도 문제가 없다는 의미)
$cf. (1+1/2+1/4+1/8+⋯)≈(2-ε)$
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7359b6d6-9633-4303-b088-0de0ef464746/image.png" alt=""></p>
<blockquote>
<p>위의 과정의 도식화
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d9c40761-4fc4-45f9-9a10-062c9b90d6ae/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f2ed6d62-6b10-471c-ba8c-144bab3ece5f/image.png" alt=""></p>
</blockquote>
<h3 id="multi-encoder">Multi Encoder</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/bed8866a-8c4b-4268-953f-d2e0c16ed08a/image.png" alt=""></p>
<p>Distilling operation의 robustness를 강화하기 위해서 우리는 마지막 시점으로부터 Input의 크기를 절반만큼 줄인 main stack의 replicas를 만들고 layer를 하나 줄임으로써 output dimension을 맞춰 주었다
이후 이렇게 만든 모든 stack들의 output을 concatenate시켜서 encoder의 final hidden representation을 만들어 낸다
<font color = red>
이렇게 Multi Encoder를 쓰는 것은 Residual Connection과 비슷한 개념이라고 생각하면 된다 
우리가 만약에 하나의 Encoder만 쓰게 되면 입력데이터가 Encoding과정을 거친 후 어떤 편향을 갖고 Decoder에 입력 될 수 있다 따라서 우리는 Layer를 하나 덜 쓴 Encoder의 Output을 내서 깊은 Layer의 Feature Map을 붙여서 사용함으로써 더 깊은 Layer를 사용한 Encoding의 결과값의 편향이 영향을 크게 미치지 못하도록 조절해주는 영향을 한다
Concat을 시켜서 Decoder에 입력하면 시점이 꼬이지 않나? 라는 질문에는 시점정보 또한 하나의 숫자로 벡터안에 더해져 있으니 W_k, W_v라는 가중치가 이들의 시점이 꼬이지 않도록 잘 학습할 것을 기대한다
</font></p>
<blockquote>
<p>원문 
To enhance the robustness of the distilling operation, we build replicas of the main stack with halving inputs, and progressively decrease the number of self-attention distilling layers by dropping one layer at a time, like a pyramid in Fig.(2), such that their output dimension is aligned. Thus, we concatenate all the stacks’ outputs and have the final hidden representation of encoder</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/9ed412fb-a1c9-468b-a47e-3149c64b3cd4/image.png" alt=""></p>
<h2 id="decoder-generating-long-sequential-outputs-through-one-forward-procedure">Decoder: Generating Long Sequential Outputs Through One Forward Procedure</h2>
<blockquote>
<p>One Forward Procedure이 중요하다.
Generative Inference는 Reculsively하게 결과를 생성하는 것이 아니고 한번에 Forward로 결과를 만들어내는 것을 말한다.</p>
</blockquote>
<p>Informer의 decoder는 Standard decoder 구조를 사용한다
그리고 이 decoder는 두개의 동일한 multi head attention layer의 stack으로 구성됐다
하지만 우리는 generative inference를 쓰고 있는데 이는 long prediction에서 speed plunge(급락)현상을 개선시켜준다 
우리는 decoder에 다음과 같은 벡터들을 feed시킨다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/df88ffcc-b3c6-4049-9771-4143a80a686a/image.png" alt=""></p>
<p>Where $X_{token}^t\in\mathbb{R}^{L_{token}\times d_{model}}$ 은 start token이고 
$X_0^t\in\mathbb{R}^{L_y\times d_{model}}$는 target sequence에 대한 placeholder, scalar는 0으로 set되고 시간정보만 가지고 있다</p>
<h3 id="masked-multi-head-probsparse-self-attention">Masked Multi-head ProbSparse Self-attention</h3>
<p>Decoder에서는 Masked multi-head attention에 ProbSparse self-attention이 적용 된다 
이는 특정시점의 예측을 미래시점 정보의 참여로부터 막는 역할을 한다
이후 multi-head attention을 거친 이후에 fully connected layer을 통과해서 최종 output을 얻는다</p>
<h3 id="generative-inference">Generative Inference</h3>
<p>Start token(sos)는 NLP의 dynamic decoding에서 효과적으로 적용된다 우리는 이 대신에
$L_{token}$ 길이의 sequence를 input sequence안에서 뽑아서 사용한다
예를 들어 168 point의 예측을 만든다면 우리는 target sequence 전에 알려진 5일을 start token으로 사용한다
따라서 decoder의 입력되는 값은 
다음과 같다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/63f77728-7039-475f-a114-43e9ff714c0d/image.png" alt=""></p>
<h3 id="decoder-process">Decoder Process</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/ac106df3-53bc-42ce-b37a-7f4d50354203/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/99aaffe6-935e-4e72-8d48-2e5cca4fb6ff/image.png" alt=""></p>
<blockquote>
<p>ATS: Attention Score
ATV: Attention Vector</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/3b98fbfd-0a56-4592-8625-c0d81d6747c9/image.png" alt=""></p>
<blockquote>
<p> Key와 Value는 Encoder의 hidden output</p>
</blockquote>
<blockquote>
<p>전체 구조
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/a11e4b78-8496-4c7c-8edb-08b3a2407510/image.png" alt=""></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/0492cb5d-1c56-4f0c-b4e2-ddeea0cfe187/image.png" alt=""></p>
<p>이렇게 만든 M.M.P.S output은 우리가 알고 싶은 것과 관계한 정보(이전 전체시점 정보)가 담겨져 있음
이를 Key와의 대조과정을 거치고 Value를 곱한다
<font color = red>여기서 Key의 각 행은 전체시간에 대한 어떤 흐름을 담고 있고 이 키와 Query(최근 시점 정보)를 대조한다</font></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[엔트로피와 크로스엔트로피 KL-Divergence]]></title>
            <link>https://velog.io/@leesungjoon-net/%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC%EC%99%80-%ED%81%AC%EB%A1%9C%EC%8A%A4%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC-KL-Divergence</link>
            <guid>https://velog.io/@leesungjoon-net/%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC%EC%99%80-%ED%81%AC%EB%A1%9C%EC%8A%A4%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC-KL-Divergence</guid>
            <pubDate>Thu, 31 Aug 2023 08:17:13 GMT</pubDate>
            <description><![CDATA[<h1 id="entropy">Entropy</h1>
<p>엔트로피는 불확실성의 정도이다. 즉, 확률과 연관된 개념으로써
엔트로피가 높다는 것은 미래의 사건이 뭐가 나올지 불확실한정도가 크다는 것이고 낮다는 것은 미래의 사건이 뭐가 나올지 비교적 확실하다는 것이다.</p>
<p>엔트로피는 확률분포와 연관해서 기억하면 좋을 것이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2a2d4cb1-835c-4e2f-9317-3e1b1fe9554e/image.png" alt="">
위의 두 확률분포에 대해서 우리는 빨간색 점의 사건이 일어날 확률은 비교적 높은 것을 알 수 있다. 그렇다면 우리가 당신에게 정규분포에 해당하는 사건들 중에서 어떤 사건이 일어나는데 5만원을 걸래? 라고 한다면 당신은 빨간색점의 사건이 일어나는데 돈을 걸겠다고 할 것이다. </p>
<p>왜냐? 좀 더 일어날 확률이 높으니까 자 그렇다면 반대로 노란색 점의 사건이 있는 확률분포를 확인해보자. 우리는 당신에게 똑같이 파란색 분포(Uniform Distribution)에 해당하는 사건들중에 어떤 사건이 일어나는데 5만원을 걸래? 라고 한다면 당신은 선뜻 노란색 사건이 일어나는데 돈을 걸겠다고 하지 않을 것이다. 왜냐하면 &quot;불확실한 정도&quot;가 높으니까.</p>
<p>이러한 방식으로 엔트로피를 이해하면 좋다 따라서 <strong>엔트로피가 높다는 것은 불확실한 정도가 높다는 것이고</strong> 이는 곧 Uniform Distribution에 가까운 확률분포라는 것이다.</p>
<p>반대로 <strong>엔트로피가 낮다는 것은 불확실한 정도가 낮다는 것이다.</strong></p>
<p>위의 예시에서는 불확실한 정도에 대한 관점에서 엔트로피를 설명했다. 그렇다면 정보이론의 관점에서 엔트로피를 생각해보자.</p>
<p>자, 만약에 내가 당신에게 문자를 보내는데 100자중에서 절반이 하트라고 해보자. 문자를 Bit로 표현한다고 하면 하트를 어떻게 표현해야지 가장 메모리를 적게 사용할까?
&rightarrow; 바로 0이다.
자 그렇다면 이제 확률이 높으면 높을수록 표현하는 Bit의 갯수를 줄이면 메모리를 적게 사용할 것 같다는 느낌이 든다.  이를 표현한 것이 바로 아래의 엔트로피 식이고, 그렇다면 엔트로피는 또 다르게 표현할 수 있을 것이다.</p>
<blockquote>
<p><font color = blue>정보를 다양하게 표현할 수 있는데 그중에 Lower Bound(하한)의 정보의 양</font></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/4c5ef690-7124-4e9a-a7e8-99a2aa51b67e/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/42b9e0f4-e126-4399-8d9c-83ce3dbc3633/image.png" alt=""></p>
<blockquote>
<p><font color = blue>$-log_2(x)$의 그래프로써 y축을 정보의 양이라고 생각한다면 확률이 높아지면 높아질수록(덜 불확실할수록) 더 적은 정보의 양으로 표현한다고 생각하자.</font></p>
</blockquote>
<h1 id="crossentropy">CrossEntropy</h1>
<p>크로스 엔트로피는 한마디로 말하자면 다음과 같다.
&quot;틀릴 수 있는 정보를 가지고 추정한 엔트로피&quot;</p>
<p>우리가 만약에 어떤 사건들이 일어날 확률분포를 예측했다고 하자. 이 분포를 이용해서 구한 엔트로피를 크로스 엔트로피라고 한다. 
&quot;즉 내가 예측한 분포로 정보를 표현했을때 실제로 표현되는 정보의 양&quot; 으로 이해하면 좋을 것 같다.</p>
<blockquote>
<p>CrossEntropy를 이해하는데 불확실성의 개념을 연결하는데는 쉽지 않은 것같다.</p>
</blockquote>
<p>크로스엔트로피를 구하는 식은 다음과 같다.
$log$안에 들어있는 것$(p(x))$ 가 내가 예측한 분포이다.</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/d7268756-8348-4bde-8c0c-88e02c43d293/image.png" alt=""></p>
<h1 id="kl-divergence">KL-Divergence</h1>
<p>KL-Divergence는 Entropy를 이용해서 두 분포 사이의 차이를 측정하는데 쓰이는 측정지표이다 단순하게 CrossEntropy에서 실제 Entropy를 빼는 것으로 두 분포사이의 차이를 측정한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3cc422b6-ca23-4269-8b1b-61efedd67ff9/image.png" alt=""></p>
<blockquote>
<p>우리는 Loss Function으로 Cross Entropy를 이용해서 모델을 학습시키곤 하는데, 그 이유는 위에서 말했듯이 Entropy가 최소이므로 Cross Entropy를 최소로 만드는 것은 정답 확률분포에 다가가도록 만드는 것과 같은 것이다.</p>
</blockquote>
<p>참고&gt;<a href="https://www.youtube.com/watch?v=z1k8HVU4Mxc">유튜브</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[pytorch-forecasting SMAPE]]></title>
            <link>https://velog.io/@leesungjoon-net/pytorch-forecasting-SMAPE</link>
            <guid>https://velog.io/@leesungjoon-net/pytorch-forecasting-SMAPE</guid>
            <pubDate>Tue, 29 Aug 2023 17:26:38 GMT</pubDate>
            <description><![CDATA[<p>최근에 다른 실험을 하던 도중에 결과가 내예상대로 안나오는 부분을 발견하고 코드를 유심히 살펴보았는데, 이전에 작성한 코드들에서도 똑같은 문제가 발생했을 거라는 생각이 들어서 해당 문법을 살펴본 결과 역시나 그랬다.. 이미 교수님께 결과 전송을 마치고 같이 분석도 한 상황이라서 교수님께 죄송하고 믿고 싶지 않았다. 그러면 어떤 내용일지 공유를 해보겠다.</p>
<h2 id="pytorch-forecasting의-smape">pytorch-forecasting의 SMAPE</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/89b293ef-af26-4b2b-bbc9-3e2855f22db3/image.png" alt="">
우선 내가 발생한 오류는 loss를 구하는데에 있어서 발생했는데, 이전에 contest에서도 비슷한 오류를 발견했었는데, contest는 Interval 예측이라서 오류가 가시적으로 나왔다. 그래서 발견이 늦었는데, 우선 위의 사진을 보면 통상적으로 아는 SMAPE가 나와 있음을 확인할 수 있다.
나는 loss를 구하기 위해서 out Tensor와 Target Tensor의 size를 통일 시켰는데 따라서, loss가 잘못 계산 될거라는 생각 자체를 하지를 않았다.
그래서 설마하고 out과 Target Tensor의 size를 바꾸기 전과 바꾸고 나서의 loss를 찍어봤는데,
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/860be2d7-d7b3-45c6-9475-ae4910c15406/image.png" alt="">
위와 같이 loss가 달라지는 것을 확인할 수 있었다. loss의 중요성은 contest에서 얼마전 깨달은 만큼 이것이 심각한 성능이상을 초래할 수 있다는 것을 직감하고 서둘러 document를 확인했다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e3cf0d22-5d42-4c8e-b769-4812adb043f8/image.png" alt="">
SMAPE의 y_pred에 <code>to_prediction</code>이라는 클래스 메소드가 적용된것을 확인할 수 있는데 이것은 만약에 3차원[일반적으로 시계열에서 Tensor는 다음과 같이 구성돼있다.(Batch Size,Sample Length, Feature_dimension)] Prediction을 받게 되면 <code>y_pred = y_pred[...,0]</code> 즉 마지막 차원의 첫번째 원소를 y_pred로써 사용하는 것을 볼 수 있는데, 이는 결론적으로 prediction의 차원을 하나 줄이는 셈이 된다. 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/913cbae6-749a-4873-8a2e-8d6e54a90905/image.png" alt="">
결국 위와같이 label과 output간의 size가 mismatch된 상태로 SMAPE값을 계산하게 하여서 문제가 발생하게 된다.</p>
<blockquote>
<p><strong>reduction</strong>이 어떻게 작동하는지 확인해봤다
<a href="https://pytorch-forecasting.readthedocs.io/en/v0.10.0/_modules/pytorch_forecasting/metrics.html">링크</a>
일단 outputs와 labels를 뺀 Tensor의 Size는 다음과 같다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/1262d027-67a1-4daf-9878-6c98dda86e29/image.png" alt="">
결국 SMAPE를 reduction(default = &#39;mean&#39;)을 하기전에 Tensor의 size는 위와 같이 31,31,1일텐데 이때 Batch의 첫번째 값들만을 평균내서 output으로 내는 것으로 보인다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/0294ffac-442f-4069-97c2-24e45a133851/image.png" alt="">
내가쓰는 <code>pytorch-forecasting</code>의 document version이 나오지 않아서 reduction이 어떻게 작용하는지는 확인하지 못했는데 일반적으로 reduction은 여러 loss를 하나의 loss로 바꾸는데에 관한 논의이기 때문에, 위의 예시처럼 사이즈가 달라지면 오류가 발생한다. </p>
</blockquote>
<h2 id="trouble-shooting">Trouble Shooting</h2>
<p>이 문제를 해결하기 위해서는 Target과 Prediction을 모두 2차원으로 바꾸면 깔끔하게 해결된다.
그이유는 위에 코드중에서 <code>y_pred.ndim==3</code>에 걸리지 않기 때문이다.</p>
<blockquote>
<p>혹은 그냥 SMAPE,RMSE,MAPE등의 LossFunction코드를 직접짜는게 나을 것이다..</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/bf97f068-cb70-4a57-b2f0-ede7cf626a6b/image.png" alt="">
위와 같이 깔끔하게 맞아 떨어지는 것을 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[pytorch-lr-finder]]></title>
            <link>https://velog.io/@leesungjoon-net/pytorch-lr-finder</link>
            <guid>https://velog.io/@leesungjoon-net/pytorch-lr-finder</guid>
            <pubDate>Mon, 28 Aug 2023 14:29:34 GMT</pubDate>
            <description><![CDATA[<h2 id="intro">Intro</h2>
<p>평소에 pytroch_forecasting Library를 쓰면 보통 pytorch_lightning과 결합하여서 써서, auto_lr_find를 이용해서 최적의 learning rate를 찾곤했다. 하지만 내가 직접 모델을 구현할때는 보통 pytorch_lightning을 사용하지 않고 손수 loss를 구한후 backward를 시키면서 모델을 훈련시키는데, 이 과정에서 초기 learning rate를 heuristic하게 찾아야 해서 좀 불편했다. 이러한 니즈를 해결하고자 검색해본결과 
<a href="https://github.com/davidtvs/pytorch-lr-finder">GitHub</a>
에 올라와있는 모듈의 README를 한번 공부해보고 실제로 사용해보겠다.</p>
<p>이 라이브러리는 <a href="https://arxiv.org/abs/1506.01186">Paper</a>에 자세히 기술된 learning rate range test(LRRT)의 파이토치 구현이다.</p>
<blockquote>
<p><strong>LRRT란?</strong>
learning rate range test는 최적 learning rate에 대한 가치있는 정보를 제공하는 테스트이다. 작은 learning rate로 시작하면 network가 수렴하기 시작하는데, 너무 작다면 수렴하지 않고 멈추는 현상이 발생할 것이다. 이러한 Trouble을 없애기 위해서 learning rate를 키우다보면, 결국에는 network가 발산해버릴 것이다.</p>
</blockquote>
<p>Typically하게 좋은 Static(정적인, Scheduler로 조정하지 않는) learning rate는 감소하는 loss curve에서 half정도의 수준일 수 있다. 아래의 plot에서는 0.002가 좋다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b91f9720-ead7-426a-bf40-ed7c2b075d9e/image.png" alt=""></p>
<p>위에 Paper에서 기술된 cyclical learning rate란 어떤 영역사이<code>(start_lr,end_lr)</code>에서 learning rate가 순회하는 것이다.
저자는 loss가 감소하기 시작하는 부분을 start_lr 더이상 감소하지 않는 부분을 end_lr로 설정하도록 조언한다.
위의 그림에서는 <code>start_lr =0.0002</code> and <code>end_lr=0.2</code>이다.</p>
<h2 id="implementation-details-and-usage">Implementation details and usage</h2>
<h3 id="fastai로부터-수정된-version">fastai로부터 수정된 version</h3>
<p>learning rate를 지수방식으로 증가시키고 train loss를 각 learning rate에 대해 계산한다.</p>
<pre><code>from torch_lr_finder import LRFinder

model = ...
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-7, weight_decay=1e-2)
lr_finder = LRFinder(model, optimizer, criterion, device=&quot;cuda&quot;)
lr_finder.range_test(trainloader, end_lr=100, num_iter=100)
lr_finder.plot() # to inspect the loss-learning rate graph
lr_finder.reset() # to reset the model and optimizer to their initial state</code></pre><h3 id="leslie-smiths의-접근">Leslie Smith&#39;s의 접근</h3>
<p>각각의 learning rate에 대해서 learning rate를 선형적으로 증가시키고 evaluation loss를 계산한다.
<code>lr_finder.plot()</code>은 learning rate에 따른 evaluation loss를 plot해준다. 이러한 Leslie의 접근은 evaluation loss를 사용한다는 점에서 더욱 발산하기 쉽기 때문에 더 정확한 그래프를 생산한다. <br>
<strong>하지만 이러한 접근은 시간적으로 test를 수행하는데 오래걸리고 특히나 evaluation dataset이 크다면 더욱 오래 걸린다는 단점이 있다.</strong>
아래의 코드를 확인해보면 trainloaderd와 동시에 val_loader를 제공한 것을 볼 수 있다.</p>
<pre><code>from torch_lr_finder import LRFinder

model = ...
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.1, weight_decay=1e-2)
lr_finder = LRFinder(model, optimizer, criterion, device=&quot;cuda&quot;)
lr_finder.range_test(trainloader, val_loader=val_loader, end_lr=1, num_iter=100, step_mode=&quot;linear&quot;)
lr_finder.plot(log_lr=False)
lr_finder.reset()</code></pre><blockquote>
<p><strong>NOTE</strong></p>
</blockquote>
<ul>
<li>LRFinder에 passing된 optimizer는 LRScheduler를 가져서는 안된다.</li>
<li><code>LRFinder.range_test()</code>는 모델의 weight와 optimizer의 parameter들을 변화시키는데, 이는 <code>LRFinder.reset()</code>으로 원래대로 복구 가능하다.</li>
<li>learning rate와 loss history는 lr_finder.history를 통해서 접근 가능하고 각각 <code>lr</code>과 <code>loss</code> key를 사용하면 된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Autograd]]></title>
            <link>https://velog.io/@leesungjoon-net/Autograd</link>
            <guid>https://velog.io/@leesungjoon-net/Autograd</guid>
            <pubDate>Tue, 22 Aug 2023 16:04:50 GMT</pubDate>
            <description><![CDATA[<p>최근에 특정 layer층의 가중치를 Masking하는 방법에 대해서 알아보고 있던 도중에
<a href="https://discuss.pytorch.org/t/how-could-you-manually-stop-backpropagation/115985">discussion</a>
을 확인하게 됐다. 이전에도 autograd가 gradient를 조정하는 역할을 하는 것을 알고는 있었는데, 정확히 알지는 못했기 때문에 이 기회에 정리해보고자 한다.
[tutorial]
(<a href="https://tutorials.pytorch.kr/beginner/blitz/autograd_tutorial.html">https://tutorials.pytorch.kr/beginner/blitz/autograd_tutorial.html</a>)
을 참고했다.</p>
<h1 id="autograd">AutoGrad?</h1>
<p>Autograd ; Automatic gradient calculating API</p>
<h2 id="autograd의-미분">AutoGrad의 미분</h2>
<p>우선 우리는 파이토치 tensor가 requires_grad라는 속성을 갖는 것을 알고 있다. 이것이 일종의 마킹의 역할로 Autograd에게 연산을 추적해야 한다고 알려준다.</p>
<pre><code>import torch

a = torch.tensor([2., 3.], requires_grad=True)
b = torch.tensor([6., 4.], requires_grad=True)</code></pre><p>이때, a와 b는 신경망의 매개변수(즉, 가중치)라고 하자.
a와 b를 통해서 새로운 텐서 Q를 만들자.</p>
<pre><code>Q = 3*a**3 - b**2</code></pre><p>이때, Q는 Error라고 해보자 우리는 backward()를 통해서 loss를 BackPropagation 시키는데, 이 과정에서 $\frac {dQ} {da}=9a^2$ 와 $\frac {dQ} {db}=-2b$를 구해야 한다.
현재 Q는 vector이기 때문에 중간 Layer라고 생각하고 전파되는 gradient($\frac {dQ} {dQ}$)를 제공해줘야 한다. 이를 backward()의 gradient 파라미터로 제공하면 된다.</p>
<blockquote>
<p>실제 Pytorch에서는 하나의 Loss Tensor를 계산하는 과정을 Computational Graph로 저장해두고 계산된 loss를 Backward 시키면서 loss Tensor의 <code>.grad</code>를 이전의 파라미터들의 편미분 값으로 계산해서 저장해 두는데, 여기서는 벡터로 나와서 loss를 산출해내는 과정이 없기 때문에 gradient 파라미터를 제공해 주어야 하는 것이다.</p>
</blockquote>
<pre><code>external_grad = torch.tensor([1., 1.])
Q.backward(gradient=external_grad)</code></pre><p><code>Q.backward()</code>를 통해 변화도는 a Tensor의 <code>a.grad</code>와 b Tensor의 <code>b.grad</code>에 저장된다.
다음과 같은 결과를 통해서 AutoGrad가 적절하게 BackPropagation을 시켰음을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7ae259f2-e44d-4e6b-9252-f36d14505142/image.png" alt=""></p>
<h2 id="autograd의-calculus">AutoGrad의 Calculus</h2>
<p>tutorial에서는 벡터함수에 대한 야코비안 행렬 J를 도입해서 AutoGrad의 역할을 설명한다.</p>
<blockquote>
<p>야코비안 행렬(Jacobian Maxtrix) ?
다변수 벡터 함수에서의 미분값으로써 생각하면 된다.
좀 더 쉽게 설명하자면 변수를 여러개 갖는 output을 벡터 형태로 내는 함수를 미분을 해서 행렬 형태로 만들어 놓은 것이다. 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/4151cba6-8c4b-42e5-a381-f38a57bb58d2/image.png" alt=""></p>
</blockquote>
<p>자, 우리는 이런 연쇄법칙과 야코비안 행렬의 곱을 통해 loss에 대한 각 middle층 가중치를 업데이트 해나갈 수 있는 것이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/26ddf7fd-b232-438b-94d6-ddf6dffc8f99/image.png" alt=""></p>
<h2 id="연산그래프computational-graph">연산그래프(Computational Graph)</h2>
<p>autograd는 텐서에 적용된 계산의 history를 Function 객체로 구성된 방향성 비순환 그래프(DAG; Directed Acyclic Graph)에 저장한다. 이 방향성 그래프의 leaf노드는 입력 텐서이고 root 노드는 결과 텐서이다. 이 그래프를 root 부터 추적하면 gradient를 계산할 수 있다.</p>
<pre><code>import torch

a = torch.tensor([2.0], requires_grad=True)
b = a ** 2
c = b * 3
d = c.mean()

print(d.grad_fn)</code></pre><p>다음과 같은 상황에서 <code>.grad_fn</code>은 pytorch에서 autograd를 위해 계산 그래프를 구성하는데 사용되는 속성으로써 위의 예시에서 <code>d.grad_fn</code>을 출력하면 <code>MeanBackward()</code>와 같이 연산의 타입을 나타내는 값이 될 것이다. 이렇게 d의 <code>.grad_fn</code>을 따라가면서 gradient를 계산하여 gradient를 쌓은 이후 연쇄법칙을 사용해서 이전의 연산들인 <code>c</code>,<code>b</code>,<code>a</code>를 찾아갈 수 있다.</p>
<p>DAG를 시각적으로 표현하면 다음과 같다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e09cc633-3ff9-47d1-91fc-09450859a2c9/image.png" alt=""></p>
<blockquote>
<p>DAG에서 제외하고자 하면 requires_Grad=False로 설정해두면 된다.</p>
</blockquote>
<blockquote>
<p>참고할점은 <code>.backward()</code>를 call하면 call하는 순간 autograd는 graph를 새로 만들기 시작한다는 것이다.</p>
</blockquote>
<blockquote>
<p>backward()의 retain_graph = True라는 파라미터는 DAG와 연결지어 생각해보면 backward를 한번수행하면 또 다시 backward를 수행할 수 없는데, 이때 그래프를 유지하게 해서 두가지 loss에 대해서 backward를 수행할 수 있게 된다.
<a href="https://hongl.tistory.com/158">링크</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 Heap 자료구조]]></title>
            <link>https://velog.io/@leesungjoon-net/%ED%8C%8C%EC%9D%B4%EC%8D%AC-Heap-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@leesungjoon-net/%ED%8C%8C%EC%9D%B4%EC%8D%AC-Heap-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Fri, 11 Aug 2023 08:53:20 GMT</pubDate>
            <description><![CDATA[<p>Heap에 관한 설명은 간략히 하고 heapq내장모듈을 사용하는 방법을 작성해보겠다.</p>
<h2 id="heap이란">Heap이란</h2>
<p><strong>heapq는 Min Heap 자료구조를 제공한다.</strong>
우선순위큐 Heap을 생각하면 된다. Heap의 주요 개념을 간략히 살펴보면 다음과 같다.
Heap자체는 우선순위큐를 구현하기 위한 자료구조이다.</p>
<blockquote>
<p><strong>우선순위 큐란?</strong>
이전의 큐는 FIFO로써 먼저 들어온 값이 먼저 나가는 구조의 자료형이였다. 그런데 우선순위 큐는 우선순위가 높은 값이 먼저 나갈 수 있도록 구현한 것이다. 
이를 구현하는데는 이진트리가 아닌 다른 방법도 있으며, 이진트리로 구현한 것이 바로 Heap이다. 
그렇다면, Min Heap과 Max Heap이 어떤 것일지는 예상이 간다. Min Heap은 더 작은 값에게 우선순위를 준다는 것이고 Max Heap은 더 큰 값에게 우선순위를 준다는 것이다.</p>
</blockquote>
<blockquote>
<p><strong>Heap의 insert와 remove</strong>
내가 학교에서 배운 Heap의 insert와 remove의 설명이 와닿아서 그 설명을 상기해서 설명해 보겠다.
먼저, <strong>Insert</strong>는 다음과 같이 설명한다.
&quot;회사의 신입 사원이 점점 승진해서 자신의 능력에 맞게 올라가는 형태&quot; &rightarrow; 이를 upheap이라고 한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7c68e7f2-e77a-47c5-8a6e-884dfa40be9b/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3fd0a62b-43d7-448d-8460-ab2a5516322c/image.png" alt="">
<strong>remove</strong>는 다음과 같이 설명한다.
&quot;말단직원이 사장의 자리를 차지한후 점점 강등당하는 것&quot;&rightarrow;이를 downheap이라고 한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/86e8f856-f2ef-4f4d-89d9-a787260a6ab7/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c99c054c-5a98-4535-97a5-35d1849d5e92/image.png" alt=""></p>
</blockquote>
<p><font color = blue>위와 같은 알고리즘을 이용해서 Heap 정렬을 구현할 수 있다.</font></p>
<hr>
heapq 모듈은 리스트를 힙처럼 다룰 수 있도록 도와준다.
리스트를 힙처럼 다룰 수 있도록 하기 때문에, 리스트와 별개의 자료구조가 아니다.

<h2 id="heapq모듈">heapq모듈</h2>
<h3 id="push">push</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/790ee2c4-ac1a-4278-8d1b-ca5d229a3c90/image.png" alt=""></p>
<p>위에서 말했듯이 파이썬에서 heap은 리스트와 다르지 않다.</p>
<blockquote>
<p>C언어에서도 Heap을 구현할때 배열을 이용한다.</p>
</blockquote>
<p>따라서 첫번째 인자로 heap으로 만들 리스트를 넣고 두번째로 입력할 값을 넣어준다.</p>
<h3 id="pop">pop</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/c8689e3a-17e3-46c9-8e14-2799ff9cd089/image.png" alt="">
heap을 heappop에 넣어줌으로써 높은 우선순위를 가지는 값을 pop해준다.</p>
<h3 id="최소값-peek하기">최소값 peek하기</h3>
<p>최소값을 살펴보기만 하기 위해서는 리스트와 다를바가 없기 떄문에 0번인덱스의 값을 살펴보면 된다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f1c7c6f3-be33-48c7-9e73-032ebf2816ea/image.png" alt=""></p>
<h3 id="두번째-인자에-tuple이-들어가는-경우">두번째 인자에 tuple이 들어가는 경우</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/16574dc2-f4d2-437d-9426-596df985a2aa/image.png" alt=""></p>
<p>만약 두번째 인자에 튜플이 들어가는 경우 튜플의 첫번쨰 인자를 우선적인 비교대상으로 삼고 비교하고 만약 같을 경우 두번째, 세번째 인자를 비교해서 우선순위를 따진다.
하지만 보이는 바와 같이 저장되는 값은 튜플이 저장되게 돼있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ARIMA의 extend와 append 메소드]]></title>
            <link>https://velog.io/@leesungjoon-net/ARIMA%EC%9D%98-extend%EC%99%80-append-%EB%A9%94%EC%86%8C%EB%93%9C</link>
            <guid>https://velog.io/@leesungjoon-net/ARIMA%EC%9D%98-extend%EC%99%80-append-%EB%A9%94%EC%86%8C%EB%93%9C</guid>
            <pubDate>Thu, 10 Aug 2023 15:01:53 GMT</pubDate>
            <description><![CDATA[<p>ARIMA의 Fit과정?(출처 statsmodels에서 제공하는 코드)
Statespace를 Default메소드로써 사용하고 이때, GLS(일반화된 최소제곱법)[데이터가 이분산성을 가짐] 사용하여 계수를 추정함. 이외에도, Yuler Walker Equation과 같은 것을 사용하여서 계수 추정이 가능하다.
 <img src="https://velog.velcdn.com/images/leesungjoon-net/post/013fcc1e-d499-4c92-9337-5847acda2e9c/image.png" alt=""></p>
<p>이러한 Fit과정을 거친후 나오는 ARIMAResults 클래스
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d6efbda5-4808-4cb1-b1ce-687661410378/image.png" alt="">
위에 첫번째 코드를 보면 ar.L1<em>1.2(2000번관측치)=1.1707(2001번 in-sample 예측값) 
두번째 코드를 보면 ar.L1</em>1.5(2001번관측치)=1.4634(2002번  out of sample 예측값)이다. 이때, extend 메소드는 두번째 코드와 같이 새로운 데이터에 대한 결과만을 리턴한다. 새로운 데이터와 original 데이터에 대한 결과를 얻기 위해서는 append 메소드를 사용해야한다.(append 사용)
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/9cac09c6-babc-4211-a28b-f2157ffe6e44/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ARIMA/SARIMA/SARIMAX]]></title>
            <link>https://velog.io/@leesungjoon-net/ARIMASARIMASARIMAX</link>
            <guid>https://velog.io/@leesungjoon-net/ARIMASARIMASARIMAX</guid>
            <pubDate>Thu, 10 Aug 2023 14:14:45 GMT</pubDate>
            <description><![CDATA[<p>수학적인 베이스는 한양대학교에서 오픈강의로 열린 곳을 참고 했습니다 <a href="https://www.youtube.com/watch?v=hCl8zTYM4So&amp;list=PLSN_PltQeOyjnE4AnJyQUlHXNwE_hVtKL">링크텍스트</a>
혹시나 질문이 있으시다면 <a href="mailto:dsd0919@naver.com">dsd0919@naver.com</a> 으로 메일 보내주시면
최대한 답변 드리겠습니다</p>
<h2 id="random-walk란">Random Walk란?</h2>
<p>시계열 데이터 $X_t$가 아래와 같은 모형을 따른다고 해보자
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e2f3bb2c-7566-4ca0-9db3-71937facecd3/image.png" alt=""></p>
<p>$Z_t$는 평균이 $\mu$이고 분산은 $\sigma^2$인 정규 분포를 따른다고 가정하자 $X_0$는 실수값으로 간주하자 </p>
<p>위 모델을 Random Walk 모형이라고 한다. 이유는 $Z_t$가 대칭 분포인 경우 이전 데이터 값인 $X_{t-1}$이 주어졌다고 할 때 그 다음 데이터 값이 $\mu$를 기준으로 앞으로 가거나 뒤로 갈 확률이 각각 50대 50이기 때문이다 </p>
<p>이때 다음 시점값이 이전시점과의 상관관계가 확실히 있으므로 $X_t$는 Stationary하지 않는다</p>
<h2 id="시계열의-정상성stationary란">시계열의 정상성(Stationary)란?</h2>
<p>시계열의 정상성이란 시계열 데이터가 시간에 흐름과 무관한 특징을 가지고 있다 따라서 시간에 따라서 변하는 추세와 계절성이 없어야 하고 시간과 상관없는 주기는 있어도 괜찮다 white noise시계열은 정상성을 나타내는 시계열이다 white noise에 대해 리뷰 해보자면 <strong>평균이 0이고 분산이 상수이며 자기상관관계가 없는 데이터를 white noise라고 한다.</strong></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/82cbe812-4571-43d3-bc15-657f0949b372/image.png" alt="">
a)    추세가 있고 수준이 변함
b)    정상성을 나타내는 시계열 후보
c)    추세가 있고 수준이 변함
d)    계절성이 보임
e)    추세가 있고 수준이 변함
f)    추세가 있고 수준이 변함
g)    언뜻 보면 계절성이 보이는거 같지만 날짜와 상관없이 스라소니의 먹이가 구하기 힘들어져서 개체수가 줄고 줄어들면 먹이 구하기가 용이해져서 개체수가 다시 늘어나는 식이다 따라서 정상 시계열 후보
h)    연말에 맥주생산량이 급격하게 늘어나는 계절성을 보인다
i)    분산이 늘어나고 추세가 있으며 수준이 변한다</p>
<hr>

<p><strong>약한 정상성</strong>을 수학적으로 더 엄밀하게 정의한다면 다음의 세 가지 조건을 만족해야 한다
    임의의 t에 대해서 $E\left(X_t\right)=\ \mu$
    임의의 t에 대해서 $Var\left(X_t\right)=\sigma^2&lt;\infty$
    임의의 t, h에 대하여 $Cov\left(X_{t+h},X_t\right)=\gamma(h)$
    3번에서 γ(h)는 자기공분산 함수 (Autocovariance Function, ACVF)라 불리우는데, <strong>공분산이 시점 t에 의존하지 않고, 시간의 차이인 h에만 의존함을 의미한다.</strong> </p>
<p>[$\ \rho\left(h\right)=\frac{\ \gamma\left(h\right)}{\gamma\left(0\right)}$] &lt;- Correlation 공식</p>
<p>예를 들어, A 주식이 정상성을 띤다고 가정합시다. 이 주가의 평균이 3천원이고, 임의의 시점을 t = 2020년 1월 3일이라 치면
    2020년 1월 3일의 주가의 평균이 μ=3천원
    2020년 1월 3일의 주가의 분산이 유한하며 (= 극단치로 터지지 않고)
    2020년 1월 3일의 주가와, 그로부터 5일 뒤인 2020년 1월 8일의 주가 간의 공분산이 γ(5)임을 의미한다.</p>
<hr>
**정상성이 중요한 이유**
**시계열의 평균과 분산이 일정해야 시계열 값을 예측할 수 있다.** 시계열 분석에서는 “우리가 구한 시계열 자료”가 어떤 시간에 따른 확률과정(stochastic process)[확률공간에서 정의되는 확률변수들의 모임]에서 실현된 값이라고 본다.
확률과정은 시간별로 표시된 확률 변수의 집합으로 정의가 되는데 각 시점 t에서의 값이 확률분포를 따른다고 보고, 이를 종합적으로 고려했을 때 시간 t에서의 값들이 어떤 확률 분포를 따를 때 확률 과정이라고 부를 수 있다
따라서 우리가 얻은 시계열 자료가 일정한 평균과 분산을 가진 확률 과정을 따른다고 가정해야만 시계열 예측을 할 수 있다.

<p><strong>예를 들어보자 만약에 우리가 예측을 하려고 하는 시점에서의 확률변수가 갑자기 평균과 분산이 다른 분포를 따른다고 가정해보자 그러면 이는 예측하기 쉬울까? 물론 아닐 것이다 따라서 예측을 수행함에 있어 정상성은 필수인 조건이다.</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/656f95d6-4162-48c3-b5fb-9a358543d99d/image.png" alt=""></p>
<blockquote>
</blockquote>
<p><strong>NonStationary인 데이터를 Stationary하게 만들기
차분(differencing)</strong>
우리는 정상성을 나타내지 않는 시계열을 정상성이 나타나게 할 수 있는데 그 방법이 바로 차분(differencing)이다 차분은 바로 옆에 있는 데이터와의 차이를 계산하는 것으로 시계열의 수준을 제거 함으로써 시계열의 변화를 일정하게 만드는데 도움이 된다
-&gt; 계절성 차분 1차 2차... 차분이 존재하지만 보통 1차 차분 이내에 해결 된다.
<strong>로그변환</strong>
<strong>우리는 로그변환을 통해 값의 변동이 큰경우(분산이 큰경우) 이런 지수적인 그래프를 선형적인 값으로 바꿔준다</strong>
따라서 로그변환을 통해 값의 분산을 일정하게 만든 후 차분을 통해 정상성을 만족시키도록 해서 정상성이 만족되게 한다 
이때, 로그의 차분값이 증가율의 근사값으로 알려져 있는데
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/07484cd7-f608-4782-bf92-0f3ec6086ea2/image.png" alt="">
이렇게 쓰면 해석상 이점이 있다
가령 GDP같은 지수적인 그래프에서 
“GDP의 로그의 차분값이 AR(1)과정을 따릅니다” 라는 말보다 
“GDP의 증가율이 AR(1) 과정을 따릅니다 가 더 잘 와닿는다</p>
<p>시계열 데이터가 Stationary한지 확인하는 방법</p>
<ul>
<li>ACF 그래프를 활용하는 법
정상성을 나타내지 않는 데이터는 ACF가 느리게 감소하지만, 정상성을 나타내는 시계열은 ACF가 비교적 빠르게 0으로 떨어질 것이다(Sharp drop off)</li>
<li>통계적 가설 검정을 이용하는 법(Augmented Dickey-Fuller(ADF test) / KPSS test)
ADF 검정은 시계열에 단위근(unit root)이 존재하는지의 여부를 검정함으로써 정상 시계열인지 여부를 판단한다.<strong>단위근이 존재하면 정상 시계열이 아니다</strong><blockquote>
</blockquote>
단위근이란 
AR(p) 모형이 정상성을 띠기 위한 조건은 특성 방정식의 모든 근의 절대값이 1보다 커야한다는 것이다 특성 방정식은 다음과 같이 쓸 수 있다
여기서 B는 후방이동 기호를 의미하고 By_t = y_t-1 이다 따라서 위의 식은 
를 y_t로 정리해서 얻어낸 식이다
만약 *<em>이 특성방정식의 근이 1인 것을 가지고 있다면 이때 단위근을 가지고 있다고 말한다 *</em>
단위근을 갖으면 시계열은 Non-Stationary하게 되는데 이를 AR(1)모형에 대해 설명해보겠다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/8874a973-a29f-4f19-904a-740bb14c3676/image.png" alt=""></li>
</ul>
<hr>

<h2 id="단위근-검정방법">단위근 검정방법</h2>
<p><strong>(1)ADF(Augumented Dickey Fuller test)</strong>
<a href="https://www.machinelearningplus.com/time-series/augmented-dickey-fuller-test/">Augmented Dickey-Fuller (ADF) Test - Must Read Guide - ML+ (machinelearningplus.com)</a>
ADF는 AR(p) 모형에서의 단위근 검정으로써 <strong>귀무가설은 단위근을 가진다는 것이고(Not stationary)</strong> 대립가설은 단위근을 가지지 않는다는 것이다 이때 검정통계량과 ADF의 디키-풀러 분포의 Critical Value를 이용해서 검정통계량과 CV를 비교해 귀무가설을 기각한다
파이썬에서는 from statsmodels.tsa.stattools import adfuller 로 구현 돼 있다
 <img src="https://velog.velcdn.com/images/leesungjoon-net/post/e888d315-a99e-4188-b980-0d408df26e7a/image.png" alt=""></p>
<p>Adf의 regression 파라미터는 4가지 옵션이 존재하는데 c, ct, ctt, n으로 구성돼있고 각각은 다음을 의미한다
c : constant (상수항만 존재)
ct: constant and trend(상수항과 추세 존재)
ctt: constant and linear and quardratic trend (상수항과 1차 2차 추세가 존재)
n: no constant, no trend (상수항과 추세가 둘다 존재하지 않음)
또한 adf는 AIC의 값을 최소로 하는 AR(p)값을 선택하고 위 예제에서는 p=6이다 또 p-value가 0.05 보다 작음을 확인 할 수 있지만 통계량이 크리티컬 발류보다 작은것을 확인해도 위의 예제는 귀무가설을 기각하고 정상 시계열임을 알 수 있다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/dcb07006-f3cb-4a03-a300-7fdacc18d39d/image.png" alt=""></p>
<p><strong>(2) KPSS Test **
KPSS Test는 ADF Test와 가설이 다르다
**KPSS의 귀무가설은 시계열이 정상시계열이다(stationary)</strong> 는 것이고 대립가설은 시계열이 정상시계열이지 않다는 것이다
우리는 <strong>KPSS test와 ADF test를 혼용해서 쓰면 안된다 KPSS test는 확정적 추세를 갖는 데이터에서의 stationarity를 확인하는 것이다</strong> KPSS test에서 regression = ct로 설정해준다면 우리는 데이터가 trend 주변에서 stationary함을 볼 수 있다
<a href="https://www.machinelearningplus.com/time-series/kpss-test-for-stationarity/#google_vignette">KPSS Test for Stationarity - Machine Learning Plus</a>
파이썬에서 KPSS를 사용하면 P값이 출력될 때 최대 10%에서 최소 1%로 출력이된다 그렇기 때문에 warning 메시지가 뜨고 실제 P값은 출력된 P값보다 더 큰 값이다라는 정보를 주게된다
[확실한 추세가 있는 데이터에 대해 log 변환으로 분산 조정후 kpss trend 주변에서 stationary인지 확인]
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/10b76d51-fdb6-4160-9aea-8bcd4a814f08/image.png" alt="">
통계량이 CV보다 작으므로 귀무가설 기각 불가
    Kpss trend 주변에서는 stationary하다
반대로 평균 근처에서 stationary인지 확인
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/990589a1-b427-48bc-9f40-22d9ce962b10/image.png" alt="">
통계량이 CV보다 크므로 귀무가설 기각
    일정한 상수에 대해서는 stationary하지 않는다.</p>
<hr>

<h2 id="ar모델auto-regressive-model-과-ma모델-moving-average-model">AR모델(Auto Regressive Model) 과 MA모델 (Moving Average Model)</h2>
<p>자기회귀 모델에서는, 변수의 과거 값의 선형 조합을 이용해 관심 있는 변수를 예측한다 자기회귀라는 단어에는 자기 자신에 대한 변수의 회귀라는 의미가 있다
따라서 차수 p의 자기회귀 모델(autoregressive model)은 다음과 같이 쓸 수 있다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/58eb0a77-d6cc-4815-911c-ad32af4c5f33/image.png" alt=""></p>
<h3 id="aar모델과-ma모델의-상호변환">a.AR모델과 MA모델의 상호변환</h3>
<p>우리는 위의 AR모델을 변형할 수 있는데
AR(1)모델부터 변형해보겠다
먼저 우리는 단위근을 갖지 않는다고 가정하자 
아래의  $\a_t = epsilon_t\$
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/70171278-e7a3-42cb-8f45-f00971db92e5/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d25d4a6e-a5a4-4e1b-926c-a625b0fd96ab/image.png" alt="">
따라서 우리는 t에서의 관측값을 이전시점들의 오차의 선형결합으로 표현할 수 있게 됐다
우리는 Causal 한 시스템에 대해 정의 할 수 있는데 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f988ddf6-8efb-460f-aec3-a1941baeec9d/image.png" alt="">
우리는 오차가 White noise임을 알기에 미래시점의 관측값과 현재시점 이전의 오차로 표현되는 X_t의 공분산이 0임을 알 수 있다 이렇게 미래의 시스템에 의존하지 않는 시스템을 Causal(인과성이 있는)한 시스템이라고 한다.
우린 이렇게 | pi |&lt;1 이면 AR(1) 모델이 Causal한 모델 즉 X_t가
이렇게 바뀜을 알 수 있다 이렇게 이전시점의 오차를 이용해서 목표 예상변수를 표현하는 모델을 이동평균모델 MA(q)라고 한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/fa1069ce-22a0-4152-95b6-dd9c833a3018/image.png" alt="">
따라서 우린 방금 AR(1) 모델을 MA(inf)모델로 바꾼 것이고 이를 반대로 MA(q)모델을 AR(inf) 모델로 바꿀 수 있다
MA(1)을 생각해보자
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/cc17d9b0-538a-44d8-9bb7-9b5e8282739f/image.png" alt="">
이때 e_t = y_t-y_t-1 이고 이를 재귀적으로 전개하면 우리는 e_t를 다음과 같이 쓸 수 있다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2cb1024a-f82d-4070-ac6c-7033ce19d1b6/image.png" alt="">
마찬가지로 |Theta|&lt;1의 조건을 만족해야 한다</p>
<h3 id="bar모델과-ma모델을-상호변환-할-수-있는-매개변수의-계수조건-찾기">b.AR모델과 MA모델을 상호변환 할 수 있는 매개변수의 계수조건 찾기</h3>
<p>위에선 | Pi |&lt;1 이었고 아래에선 |Theta| &lt; 1이다 이 조건에 대해서 자세히 알아보고자 AR(1)을 후방연산자를 사용해서 전개해보고 AR(2)에 대해서도 전개해보겠다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d09cb298-cbee-43ab-92d9-62521eb5d442/image.png" alt="">
1/1-(pi*B) -&gt; piB 가 공비로 갖고있는 무한등비급수라고 생각 할 수 있다
이점을 이용해서 AR(2)를 전개해 보겠다</p>
<p>** AR(2)**
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/dc3bf7de-fbff-4a82-9422-68ae8e9094bc/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/cc2edf99-5c6d-410c-9722-5c6b8f7d096c/image.png" alt=""></p>
<p>이런식으로 매개변수의 계수에 대한 조건을 세울 수 있고 조건을 만족하면 AR(p)모델이 Causal하게 표현됨을 알 수 있다 또한 X_t가 Causal함이 밝혀지면 우리는 이를 통해 MA모델의 매개변수를 찾아 낼 수 있다 예를 들어보자</p>
<p>c.    AR(p) 모델이 Causal 함이 밝혀졌을 때 MA(inf) 모델의 매개변수의 계수 찾기
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/6fc342b7-c29b-4365-a8ae-84a6adfdab06/image.png" alt="">
물론 AR모델의 계수는 우리가 갖고 있는 시계열의 회귀분석으로부터 예측 할 것이다
위 모델의 특성 방정식을 구하고 AR(2) 조건을 확인하면 X_t가 Causal하다는걸 알 수 있고 </p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/113a6bc3-de02-4158-8118-5f93b90872a9/image.png" alt="">
이렇게 작성 할 수있고 이를
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/548a21e6-5752-4147-9b10-2219568fc27c/image.png" alt="">
이 방정식에 대입하고
곱해서 a_t가 되도록하는 pi_1,pi_2, .. 을 구할 수 있다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/a6d67e85-0e7a-4803-b3f2-5a0dcbd5234f/image.png" alt="">
pi_1 = 1 , 이를 0.89-pi_1+pi_2에 대입해서 pi_2를 찾을 수있다</p>
<p>우리는 AR(2)의 조건을 살펴보았는데 MA(2) 조건에 대해서도 알아보자
<strong>MA(2)</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7c53aa64-10f7-4cc1-85c8-e8043f00305b/image.png" alt="">
이를 정리하면
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/89ac2942-5b87-46ed-acd3-95fa401ef139/image.png" alt="">
위와 같은 조건이 나온다</p>
<p>P와 q가 커질수록 더 복잡한 조건이 생긴다.</p>
<h3 id="dar모델의-매개변수를-찾기-위한-yuler-walker-equation">d.AR모델의 매개변수를 찾기 위한 Yuler-Walker Equation</h3>
<blockquote>
<p>이는 word파일을 참고하자.</p>
</blockquote>
<h3 id="f----arimaautoregressive-integrated-moving-average">f.    ARIMA(AutoRegressive Integrated Moving Average)</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/f0c1556a-e94a-4b0d-ade5-251888c7aae1/image.png" alt=""></p>
<p>y’_t는 차분을 구한 시계열이고 우변은 AR모델과 MA모델의 합으로 적혀 있다 이것을 ARIMA(p,d,q)모델 이라고 하는데 p는 AR의 차수 d는 1차차분이 포함된 정도 q는 이동평균의 차수를 의미한다
ARIMA 모델의 d로인해 우리는 추세가 있는 데이터를 다룰 수 있다
우리는 위에서 자기회귀와 이동 평균 모델에서 invertibility조건을 알아봤는데 이는 ARIMA 모델에서도 똑같이 적용된다
지금까지 알아본 많은 모델은 ARIMA모델의 특수한 경우이다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/5a15fd54-ebf1-4416-8820-4c233ee3b95e/image.png" alt=""></p>
<p>우리는 위의 식을 후방이동연산자를 사용해서 바꿔서 쓸 수 있는데 다음과 같이 쓸 수 있다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e1cdd975-c767-4bd6-9ee5-cc7db3fe4e30/image.png" alt="">
여기서 
  <img src="https://velog.velcdn.com/images/leesungjoon-net/post/1910a224-f079-4d4c-a464-4178f0835d62/image.png" alt="">
이고 μ는 $y_t&#39;$의 평균이다 [d는 differential 차수]
여기서 c는 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/ce838323-9a6d-4e5a-abd6-b29e61983321/image.png" alt="">
로 정의한다.</p>
<p>우리는 ARIMA가 정확히 어떤 수학적인 기준으로 모델의 차수를 고르는지 이해할 필요가 있지만 이는 소프트웨어에게 맡기도록 하자
우리는 이와 관련해서 쓸 수 있는 모델이 2가지가 있는데 auto_arima와 ARIMA이다 
호출방법은 다음과 같다
from pmdarima import auto_arima 
pmdarima의 auto_arima는 information criterion 값을 사용해서 모델의 AIC 값이 가장 작은 모델 모델을 선택한다 모델의 d값을 선택하기 위해 KPSS ADF test등을 사용하고</p>
<p>auto_arima는 ARIMA모델을 얻기위해 Hyndman-Khandakar(힌드만-칸다카르) 알고리즘을 사용한다</p>
<h3 id="hyndman-khandakar">Hyndman-Khandakar</h3>
<ol>
<li>KPSS 검정을 반복해 차분횟수 d를 결정한다</li>
<li>데이터를 d번 차분한후에 AIC를 최소화하는 p와 q를 고른다 이때 p와 q의 모든 가능한 조합을 살펴보는 것이 아니라, 모델 공간을 탐색하기 위해 단계적(stepwise) 탐색을 사용한다
    기본모델 4가지를 맞춘다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3509611a-5acb-4a3d-92a5-0db2fd5908db/image.png" alt="">
d&gt;=1이면 상수는 제거된다
여기서 맞춘 AIC 값이 가장 좋은 기본모델을 현재모델로 둔다</li>
</ol>
<p>    현재모델에서 p와 q를 +-1로 바꾸거나 상수를 넣거나 빼서 가장 좋은 모델을 현재모델로 채택한다</p>
<p>    더 작은 AIC가 나오지 않을 때까지 반복한다</p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b5edb7ce-618f-46ff-8cd2-89628cc77f70/image.png" alt=""></p>
<h3 id="g-수동모델링-과정">g. 수동모델링 과정</h3>
<p>c,d값
우리는 Auto Arima를 통해 모델을 자동 선택할 수 있지만 모델이 대략적으로 작동하는 방식은 공부해볼만 하다 상수 c와 차분의 정도 d는 장기 예측값에 중요한 영향을 준다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2b555cc2-3057-459c-8801-fe34d492e85c/image.png" alt="">
d 는 예측구간에도 영향을 주는데 d값이 클수록 예측구간의 크기가 급격하게 늘어나고 d=0에서 장기 예측 표준 편차가 과거 데이터의 표준편차에 가까워질 것이다 따라서 모든 예측구간은 실제적으로 같게 될 것이다.</p>
<p>** process**</p>
<ol>
<li>데이터를 그래프로 나타내고, 특이한 관측값을 찾는다</li>
<li>분산을 안정화하기위해 박스-칵스 변환을 사용해 데이터를 변환한다</li>
<li>데이터가 정상성을 나타내지 않는다면, 데이터가 정상성을 나타낼 때까지 데이터를 가지고 1차차분을 계산한다</li>
<li>ACF/PACF 를 살펴보고 ARIMA(p,d,0)가 적당할지 ARIMA(0,d,q)가 적당한지 살펴본다</li>
<li>우리가 고른 모델을 사용해보고 더 나은 모델을 위해 AIC를 사용한다</li>
<li>잔차의 ACF를 고려하고 융-박스검정과 같은 포트맨토 검정을 하여 잔차가 White Noise인지 확인한다</li>
<li>잔차가 백색잡음이면 예측값을 계산한다
힌드만-칸다카르 알고리즘은 3~5단계만을 처리해준다</li>
</ol>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b15ce62e-61da-40d2-bc08-4e1aea194e1c/image.png" alt="">
잔차의 acf와 pacf를 그린후 ljung-Box test까지 해보기
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3376fcd8-1aa7-4eb0-a291-d0f571ac2734/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/7641dd7e-0046-432f-ae06-e9fc562c3f3d/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/6813d804-59f6-4038-add8-cc97eec3c8d2/image.png" alt="">
인덱스는 lag값 / lb_stat =통계량 , lb_pvalue는 p_value를 의미</p>
<h3 id="h-점예측하기">h. 점예측하기</h3>
<p>점예측은 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/ff9d9e5c-28d1-418b-b65b-5a7357a79781/image.png" alt="">
위와 같은 과정을 거치는데
ARIMA(3,1,1)에대해 작성하면 다음과 같다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/943d7a2f-4c28-4bee-9a02-836c2ea0042e/image.png" alt="">
ARIMA의 예측구간은 더 복잡한 과정을 다루므로</p>
<p>따라서 Python에서 구현해봤는데
정상시계열에선 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/555d8a5f-d149-498f-9bb8-ac17f92949df/image.png" alt="">
PI가 일정하게 나왔고
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/aec9d2bf-aef5-4183-b47f-5821f2ee19a1/image.png" alt="">
비정상 시계열에선 PI가 퍼지듯이 나왔다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/cf30bef7-f33f-4e7a-8222-cff3df9dc2d1/image.png" alt=""></p>
<h3 id="i-sarima">i. SARIMA</h3>
<p>우리는 ARIMA를 진행하다보면 Seasonality가 들어있는 데이터는 처리할 수 없다는 사실을 알 것 이다 따라서 계절성을 지원하는 ARIMA라는 뜻에서 SARIMA가 나오게 됐다 SARIMA는 기존의ARIMA에서 P,D,Q가 새로 추가가 됐는데
P,D,Q가 의미하는 바는 다음과 같다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/26c59c66-ca7d-4ff7-8322-2e0a04c4a2c1/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/acfe14a1-cd42-46f8-9a9d-9b4c8fd74720/image.png" alt="">
SARIMA(1,1,1)(1,1,1) Formula
ARIMA Formula 에서 계절성 요소들을 추가한것과 같다
S는 계절성 주기를 의미한다<br>우리는 ARIMA와 같이 ACF와 PACF를 보고 이 데이터가 어떤 모델을 써야할지 대략적으로 유추 할 수 있는데 다음과같다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/61452885-f0a3-4fbf-8060-3817d9204262/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/ed9c829e-c00f-4e48-8323-792ef46d31e0/image.png" alt=""></p>
<p>우리는 계절성 데이터를 계절성 차분을 2회 구해서 plot을 그려보았다
미국의 CO2 배출량을 ppm단위로 만든 데이터는 계절성 데이터 인데 이것의 ACF,PACF를 그려보겠다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/52bfcc72-b4c1-48b6-a1d8-b8c36a55fd59/image.png" alt="">
이는 위에서 ARIMA(0,0,0)(1,2,0)[계절성 2회차분]모델에 더 가까움을 알 수 있고 AR(1)모델을 사용한다고 봐야한다
따라서 우리는 기본모델을 ARIMA(1,0,0)(1,2,0) 이라고 볼 수 있다 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2ec295d5-a97a-448a-b17d-9f9fd3b4c88a/image.png" alt="">
Auto_arima로 수행했을 때 거의 비슷함을 알 수 있다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/865cebfd-5b78-4328-a446-5099efa50954/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/6b6a7350-bbd0-4a79-b79c-0ab7ba871729/image.png" alt=""></p>
<h3 id="j-sarimax">j. SARIMAX</h3>
<p>SARIMA의 외생적 회귀 변수도 지원한다는 의미이다
예를 들어보자 우리가 레스토랑에 방문하는 방문자 수를 예측하고자 하고 이전에 방문객수의 데이터를 갖고 있다고 해보자 우리는 이전에 해왔던 것처럼 예측을 수행할 수 있다 하지만 휴일정보를 포함하고 싶을 땐 어떻게 해야할까?
    우리는 휴일 정보를 Dummy Variable로 만들어 적용할 수 있을 것이다 
( pd.get_dummies( ) )</p>
<p>우리가 직접 외생변수(exogeneous variable)를 넣을 수 있는데 여기에는 약간의 직관이 필요하다 우리가 예측에 관련이 있다고 생각하는 것들을 외생변수로써 넣는 것이다  </p>
<p>하나 중요한점은 우리는 외생변수를 예측하는 것이 아니고 그저 미래시점에 대해 우리가 알고 있는 외생변수를 제공하는 것이다 다시 말하면 우리는 미래의 외생변수 까지 알고 있어야 하며 실제로 외생변수는 휴일과 같은 단순한 것들이다 혹은 우리가 어떤 근거로 미래의 외생변수에 대해 강한 확신이 있어야 한다 
[일자별 레스토랑 방문객수에 대한 데이터 SARIMA &amp;SARIMAX][미래시점의 총방문객수 예측]
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c2c8aa78-20a4-4415-84a0-27ee425e34a1/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2aa09876-9bab-4de2-8efd-1e0a3c57e080/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b055343d-3806-4457-a6f5-a44c56b07c1a/image.png" alt=""></p>
<p>분지형으로 된 곳이 잘 예측되지 않았다고 볼 수 있는데 이것이 휴일의 영향일 것이라고 예측할 수 있다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/df9fef41-9a01-467d-8d47-ae67fb0f31ed/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/8ecb22b5-16c3-4c3f-bb95-0c9b3473c919/image.png" alt=""></p>
<p>SARIMAX 구축
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d6e6a29b-391f-4eef-bf10-5ae0eae0a20c/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2f8befa7-b09d-4991-a1e3-4cec607f7fc0/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e2af1add-c6a6-4e23-b408-5af32bf73509/image.png" alt="">
SARIMAX가 더 적당하다고 판단 가능하다
따라서 SARIMAX에 대해 모든 데이터로 다시 학습을 하고 실제 미래에 대한 예측을 진행하면 된다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AICE합격수기]]></title>
            <link>https://velog.io/@leesungjoon-net/AICE%ED%95%A9%EA%B2%A9%EC%88%98%EA%B8%B0</link>
            <guid>https://velog.io/@leesungjoon-net/AICE%ED%95%A9%EA%B2%A9%EC%88%98%EA%B8%B0</guid>
            <pubDate>Wed, 09 Aug 2023 03:41:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/56921504-8a5e-4890-86d3-f0481bf0855a/image.png" alt="">
95/100으로 합격했다
일단 이 시험의 장점은 강의를 듣게되면 오버해서 학습을 하게되고, 시험은 그에 비해 쉬운 수준에 있다는 것이다.
나는 이 시험이 오픈북인 것을 알고 있음에도 구글링을 사용하지 않았는데, 왜냐면 주피터 노트북의 기본기능으로 충분하게 코드를 작성할 수 있었음에 있다. 물론 이를 위해서 Pandas를 다시 복습하였고, Pytorch만 써보다 TensorFlow도 처음 써봤고, 모의시험도 한번 풀어봤지만 <strong>이 모든 과정이 복습하기에 적절했다. 따라서 구글링을 해야겠다는 마인드로 자격증 공부를 하기 보다는 처음부터 복습을 한다는 마음을 가졌으면 좋겠다.</strong><br></p>
<p><strong>AICE에서 제공하는 강의의 단점도 물론 존재했다</strong>
첫째로, 이론적인 설명이 부족했다. 나는 이론적인 배경이 매우 중요하다고 생각한다. 왜냐면 현재 나온 모델중 어떠한 모델도 완벽하다고 불릴만한 모델은 존재하지 않고, 완벽한 모델을 추구하는 과정에서 이론적인 배경은 핵심이기 때문이다. 이러한 니즈때문에 내가 적어놓은 블로그에는 약간의 이론적인 백그라운드를 작성해뒀다. 하지만 이론적으로 좋다고 하더라도, 실제로 사용하는 측면을 등한시 할 수는 없기 때문에 ** 활용적인 측면에서 모든것을 복습하기에는 매우 좋았다 **</p>
<blockquote>
<p>이론적인 측면은 내가 포스팅을 해보겠다.
 Word파일로는 작성돼있는데, 이것을 옮기는데 상당히 시간이 필요해서 자꾸 미뤄지는 것 같다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[판다스를 사용한 데이터 전처리 및 시각화]]></title>
            <link>https://velog.io/@leesungjoon-net/%ED%8C%90%EB%8B%A4%EC%8A%A4%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%AC-%EB%B0%8F-%EC%8B%9C%EA%B0%81%ED%99%94</link>
            <guid>https://velog.io/@leesungjoon-net/%ED%8C%90%EB%8B%A4%EC%8A%A4%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EC%B2%98%EB%A6%AC-%EB%B0%8F-%EC%8B%9C%EA%B0%81%ED%99%94</guid>
            <pubDate>Thu, 20 Jul 2023 10:15:18 GMT</pubDate>
            <description><![CDATA[<p>시작해보겠다. 이 주제에 관해서 맨 마지막에 작성하는 이유는 실제로 판다스 라이브러리의 메소드들은 워낙 방대한 내용으로 작성돼있고, 실제로 다양한 name으로 같은 기능을 수행할 수 있기 때문에, 나는 필요한 기능을 그때그때 찾아보고 많이쓰는건 기억하면서 사용해왔었다. 
요점은 너무 많은 기능이 존재하기 때문에, 머신러닝이나 딥러닝처럼 이론적인 부분은 거의 없고 기능을 위주로 살펴보아야 한다. 
따라서 이번 기회에 이 velog를 작성하고 새로운 것을 알게 될때마다 기능을 업데이트해 나가겠다.</p>
<blockquote>
<p><strong>Note!</strong> 내 기준 생소한 기능만을 작성할거라 Drop과 데이터프레임 생성 concat등 기본적인 기능들은 실리지 않음을 알고 봐주셨으면 한다.</p>
</blockquote>
<h1 id="pandas">Pandas</h1>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/28a9a84b-b2dd-4302-9a2b-a7325b17cf67/image.png" alt=""></p>
<h3 id="pdread_csvpathindex_colusecolssep"><code>pd.read_csv(path,index_col,usecols,sep)</code></h3>
<ul>
<li><code>usecols = []</code>안에 들어가는 column name은 index_col이 작성될경우 포함해줘야 한다.</li>
<li>가끔 인코딩이 <code>|</code>를 기준으로 뭉뜽그러져 있는 데이터셋이 존재한다. 이에 맞춰서 <code>sep=|</code>을 통해 Decoding해줘야 한다.</li>
</ul>
<blockquote>
<p>이외에도 <code>pd.read_</code>를 검색해보면
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7122cfaf-6457-4c27-8ab1-21a1552fb61d/image.png" alt="">
수많은 파일 형식을 지원함을 확인 할 수 있다. 
&rightarrow; 실제로 Json 형식도 많이 사용된다고 알고 있다.</p>
</blockquote>
<h3 id="dataframe-행-가져오기">DataFrame 행 가져오기</h3>
<blockquote>
<p>DataFrame은 리스트와 같은 mutable한 객체이다.</p>
</blockquote>
<ul>
<li>하나의 column을 선택할때
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2cb5f69a-9f64-41dd-ab46-2fde19fb4246/image.png" alt=""></li>
</ul>
<p>이렇게 작성시 Series 형태
cf&gt; <code>[[]]</code>로 작성해 주면 <strong>데이터프레임 형태로 가져온다</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/28a8eebc-331e-4ed9-ba35-0e926eecd77c/image.png" alt=""></p>
<ul>
<li>여러개의 column 선택시 
<code>[]</code>로 작성하면 오류가 발생한다.
무조건 <code>[[]]</code>로 작성을 해주어야 한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/7f6707b1-96cc-4182-b7f0-4584525c43d3/image.png" alt=""></li>
</ul>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/cdcb22cd-9958-4b45-8ba7-62bc29dd62dd/image.png" alt=""></p>
<ul>
<li>Slicing</li>
<li><em>&rightarrow; 데이터프레임에서 <code>[]</code>의 기본은 <code>column</code>단위이지만
<code>:</code>를 사용하여 slicing을 해주면 <code>row</code>단위로 처리를 해준다.*</em>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/8e1d2acb-f21a-4f66-ae2a-cd7d0a2a5884/image.png" alt=""></li>
<li>loc와 iloc
&rightarrow; <code>loc</code>은 name으로 데이터를 가져오고
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/bd2f286e-37b1-4083-ae62-4f8aca5d9913/image.png" alt=""></li>
</ul>
<blockquote>
<p>iloc와 loc의 값 읽기
<code>input_data.iloc[-1][&#39;A&#39;] = 11</code>
이렇게 사용을 하게되면 실제 데이터프레임의 값이 변하지 않는다. iloc를 이용해서 값을 변경하려면 iloc만 사용해야 한다. 따라서 다음과 같이 할 수 있다. &#39;A&#39; 컬럼의 인덱스가 -1일때
<code>input_data.iloc[-1,-1] = 11</code>
loc또한 마찬가지이다.</p>
</blockquote>
<p>&rightarrow; <code>iloc</code>는 index로 데이터를 가져온다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/60ab22db-38c4-468d-90dd-b7374489da0d/image.png" alt=""></p>
<blockquote>
<p><strong>loc와 slicing을 결합하여 다음과 같이 사용할 수 있다.[name을 기준으로 생각해보면 자연스러움]</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/88056bd0-b13a-46b7-8580-006f96743564/image.png" alt=""></p>
</blockquote>
<blockquote>
<p><strong>iloc와 slicing을 결합하여 다음과 같이 사용할 수 있다.[index를 기준으로 생각해보면 자연스러움]</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f2b5b5de-93ad-4da8-b2e1-f328539dfdcc/image.png" alt=""></p>
</blockquote>
<h3 id="boolean-indexing으로-filtering하기">Boolean Indexing으로 Filtering하기</h3>
<p>DataFrame은 Boolean indexing이 가능한데, 이를 가장 많이 사용하는 것은 조건에 맞게 데이터프레임을 재구성할때 가장 많이 사용한다. AICE에서 제공해주는 데이터가 전처리가 돼있지 않기 때문에 알고있지만 그동안 잘 쓰지 못했던 Boolean Indexing을 경험할 좋은 기회였다.
다음과 같이 indexing을 수행하여서 새로운 데이터프레임을 만들어낸다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/85151de0-dfd5-40dd-8642-209d2d3f0180/image.png" alt=""></p>
<h3 id="group-by">group by</h3>
<p>나는 주로 딥러닝 모델을 공부해와서 직접적으로 데이터를 분석해본 경험은 몇번 없다. 따라서 group by를 써볼 기회가 충분치 않았다.</p>
<ul>
<li>groupby의 결과는 dictionary의 형태이다.
다음을 확인해보자.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/603ad77b-c3cf-465f-8d09-0284dda440f8/image.png" alt=""></li>
</ul>
<h4 id="groupby의-groups-속성">groupby의 groups 속성</h4>
<ul>
<li>각 그룹과 그룹에 속한 index를 dict 형태로 표현
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d47e45ed-87cd-4311-badb-a58cfec5ff7f/image.png" alt=""></li>
</ul>
<blockquote>
<p>나는 My SQL을 경험해봤기 때문에 group by와 aggregation function이 set임을 알고 있다.</p>
</blockquote>
<h4 id="groupby의-aggregation-function-method">groupby의 aggregation function method</h4>
<ul>
<li>그룹 데이터에 적용 가능한 통계 함수(NaN은 제외하여 연산)</li>
<li>count : 데이터 개수</li>
<li>size : 집단별 크기</li>
<li>sum  : 데이터의 합</li>
<li>mean, std, var : 평균, 표준편차, 분산</li>
<li>min, max : 최소, 최대값</li>
</ul>
<p>e.g. 
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/da43ced9-7699-4b58-81ee-af6b48465f22/image.png" alt=""></p>
<h4 id="복수-column-을-이용한-groupby">복수 column 을 이용한 groupby</h4>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/a0057afd-b621-445b-b0cc-f4549f690ddb/image.png" alt="">
이때 loc를 사용하기 위해서는 <code>Tuple</code>을 이용해서 지정해줘야한다.</p>
<pre><code># INDEX는 DEPTH가 존재함 (loc을 사용하여 원하는 것만 가지고 옴)
cust.groupby([&#39;cust_class&#39;, &#39;sex_type&#39;]).mean().loc[[(&quot;C&quot;,&quot;M&quot;)]]
# 튜플을 사용해서 하나의 key로 사용을 해야 한다.</code></pre><h4 id="set_index와-reset_index"><code>set_index()</code>와 <code>reset_index()</code></h4>
<p>미리 데이터프레임을 만들어 놨다면 데이터프레임의 <code>set_index()</code> 메소드를 활용해서 index를 지정할 수 있다.</p>
<pre><code>#set_index로 index셋팅(멀티도 가능)
cust.set_index([&#39;cust_class&#39;,&#39;sex_type&#39;])</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/f52df9fa-c741-45ed-bfec-d84652e92f6a/image.png" alt=""></p>
<p>이를 원래대로 돌리기 위해서는 <code>reset_index()</code>를 사용하면 된다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f2f4aa30-8311-4aee-8a79-202c83d0a139/image.png" alt=""></p>
<blockquote>
<p><strong>DataFrame의 level이란?</strong>
DF의 level은 바깥에서부터 0,1, .. ,로 읽어 내려가면 된다.</p>
</blockquote>
<h4 id="set_index와-groupby-메소드의-level-파라미터를이용한-group-by">set_index와 groupby 메소드의 level 파라미터를이용한 Group by</h4>
<p>ex1&gt;</p>
<pre><code># 멀티 인덱스 셋팅 후 인덱스 기준으로 groupby하기
# &#39;sex&#39;와 &#39;cp&#39;를 기준으로 index를셋팅하고 index를 기준으로 groupby하고자 하는경우
# groupby의 level은 index가 있는 경우에 사용 
cust.set_index([&#39;cust_class&#39;,&#39;sex_type&#39;]).groupby(level=0).mean()</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/81ffaeec-f2e2-43a5-b5e9-1cc1b577d122/image.png" alt=""></p>
<p>ex2&gt;</p>
<pre><code>cust.set_index([&#39;cust_class&#39;,&#39;sex_type&#39;]).groupby(level=[0,1]).mean()</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/5c54330c-0fbe-4fa2-b548-76d8c3eff2cf/image.png" alt=""></p>
<h4 id="groupby의-aggregate메소드를-사용하여-여러개의-집계함수-동시에-사용하기">groupby의 aggregate메소드를 사용하여 여러개의 집계함수 동시에 사용하기</h4>
<pre><code>cust.set_index([&#39;cust_class&#39;,&#39;sex_type&#39;]).groupby(level=[0,1]).aggregate([np.mean,np.sum])</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/f8c1fc77-91d5-4d96-b143-d1be6c225e6c/image.png" alt=""></p>
<h3 id="pivotpivot_table">pivot/pivot_table</h3>
<blockquote>
<p><strong>pivot</strong>의 사전 뜻
a fixed point supporting something that turns or balances
-&gt; 고정점</p>
</blockquote>
<h4 id="pivot">pivot</h4>
<p>우리는 데이터 프레임에 고정점들을 두어서 새로운 데이터프레임을 만들 수 있다.
다음과 같은 데이터 프레임을 생성했다고 해보자.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/eeff9929-638b-45b5-9a48-5a0c5f071795/image.png" alt="">
이 데이터프레임은 가독성이 떨어지는 것을 확인할 수 있다. 우리는 이 데이터프레임의 정보를 가독성 좋게 확인하기 위해서 어떤 column set을 index로 어떤 column set을 column으로 할때의 value값을 확인하고자 데이터프레임의 <code>pivot</code>메소드를 사용하여 고정점을 둔후 사용할 수 있다.
e.g.&gt;</p>
<pre><code>data.pivot(index = &#39;cust_id&#39;, columns = &#39;prod_cd&#39;, values = &#39;pch_amt&#39;)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/21ee8f45-3207-4eea-a857-9845db825137/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/1dc39ae5-2a96-4c4c-863b-b012437aa460/image.png" alt="">
&uparrow; pivot은 dataframe의 형태를 가지고 있음을 확인할 수 있다.</p>
<h4 id="pivot-table">pivot table</h4>
<p>pivot_table은 pivot과 동일하지만 index에 중복이 있을경우aggregation function을 적용할 수 있다.
아래의 예시를 보자.
ex&gt; 
<code>pivot()</code>의 경우
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f0bd171f-f758-4db8-99e7-0cf5102f2212/image.png" alt="">
<code>pivot_table()</code>의 경우
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/cdd20f74-a3ec-442b-88e5-a54e360c3f26/image.png" alt="">
&rightarrow; pivot은 aggregation function을 사용할 수 없기 때문에 value error를 반환하지만 pivot_table은 사용할 수 있어서 평균값을 리턴하는 것을 확인할 수 있다.</p>
<p>이외에도 <code>aggfunc=</code> 파라미터의 numpy 함수(e.g.<code>np.sum</code>)등을 제공하면 그 함수에 맞추어서 계산을 수행해준다.</p>
<h3 id="데이터프레임-stack메소드와-unstack메소드">데이터프레임 stack()메소드와 unstack()메소드</h3>
<blockquote>
<ul>
<li><strong>stack</strong> : 컬럼 레벨에서 인덱스 레벨로 dataframe 변경<ul>
<li>즉, 데이터를 row 레벨로 쌓아올리는 개념으로 이해하면 쉬움</li>
</ul>
</li>
<li><strong>unstack</strong> : 인덱스 레벨에서 컬럼 레벨로 dataframe 변경<ul>
<li>stack의 반대 operation</li>
</ul>
</li>
<li>둘은 역의 관계에 있음</li>
</ul>
</blockquote>
<p>다음 데이터 프레임을 생각해보자
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/539d998c-8d8a-4e3e-8a27-cd6b0fb61a38/image.png" alt=""></p>
<p>이때, 지역과 요일을 set_index()함수를 통해서 index로 설정해보자</p>
<pre><code>new_df = df.set_index([&#39;지역&#39;,&#39;요일&#39;])</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/af9205d8-498a-45e8-bf94-fb32449dd7ff/image.png" alt=""></p>
<blockquote>
<p><strong>위에서 언급한 level개념을 적용하면 된다.</strong>
이때, stack과 unstack으로 쌓이는 것은 높은 level로 쌓이는 것으로 생각하면 된다</p>
</blockquote>
<p><code>new_df.unstack(0)</code>를 수행하면 index가 column의 <code>level 1</code>으로 이동한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/cdd1e899-c171-46cd-8969-5a0f40ab65be/image.png" alt=""></p>
<p>example 2&gt;
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/dc3cd6f1-db5c-49c1-bf20-65605e414d02/image.png" alt=""></p>
<h3 id="concat함수의-join과-verify_integrity무결점-확인-파라미터에-대한-이해">concat함수의 join과 verify_integrity(무결점 확인) 파라미터에 대한 이해</h3>
<ul>
<li><p><code>join = &#39;inner&#39;</code> &rightarrow; 교집합</p>
</li>
<li><p><code>join = &#39;outer&#39;</code> &rightarrow; 합집합</p>
</li>
</ul>
<p>이때, axis = 0을 지정하면 column을 기준으로 교집합 합집합을 따지고 axis = 1을 지정하면 index를 기준으로 교집합 합집합을 따진다.</p>
<ul>
<li><p><code>verify_integrity=True</code> &rightarrow; 두 데이터프레임이 중복 인덱스(when axis = 1, 컬럼)를 가질경우 error 발생</p>
</li>
<li><p><code>verify_integrity=False</code> &rightarrow; 두 데이터프레임이 중복 인덱스(when axis = 1, 컬럼)를 가질경우 error 발생하지 않음</p>
</li>
</ul>
<h3 id="pandas의-merge와-join함수">Pandas의 merge와 join함수</h3>
<h4 id="merge">merge()</h4>
<p>MySQL에서 여러가지 join을 배웠었다. 이때 join은 외래키를 사용하여 join했었는데 판다스의 merge도 같은 기능을한다. 다음과 같은 두 데이터프레임을 생각해보자.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c96e8198-eeca-4428-a88f-a2fbdc3b393b/image.png" alt=""></p>
<ul>
<li><strong>on: join대상이 되는 column[외래키] 명시</strong>
how의 default는 <code>inner</code>[공통된것]
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/1c7e8314-f6df-49eb-850e-02e092f61426/image.png" alt=""></li>
<li><strong>how: inner, outer, left, right</strong>
<code>left</code>&rightarrow; 왼쪽에 적은 데이터 프레임이 가진 외래키를 기준으로 데이터프레임을 merge하는데 오른쪽이 갖지 않은것은 NaN으로 작성된다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/1b52abb9-2ef0-4f0c-a93e-debeff886ffc/image.png" alt="">
<code>right</code>&rightarrow; 오른쪽 데이터프레임이 갖는 외래키를 기준으로 데이터프레임을 merge한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/22c567d5-9b5c-49e5-85e5-63f15addfa57/image.png" alt=""></li>
</ul>
<p><code>outer</code>&rightarrow; left와 right merge한 것을 합집합함
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/5f2eb012-ed7a-4011-bb4b-953540824fea/image.png" alt=""></p>
<blockquote>
<p>연습문제 1 : 가장 많이 팔린 아이템은?</p>
</blockquote>
<pre><code># 3. sort_values를 이용하여 quantity를기준으로 sort + 내림차순으로 정렬
pd.merge(customer, orders, on=&#39;cust_id&#39;, how=&#39;right&#39;).groupby(&#39;item&#39;).sum().sort_values(by=&#39;quantity&#39;, ascending=False)
# 오름차순 ascending= False
# 만약 groupby를 하는 기준이 되는 키값이 NaN이면 그 row는 드롭이된다.</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/992525f8-ad51-4907-8541-07fbcf7b4992/image.png" alt="">
연습문제2: 영희가 가장 많이 구매한 item은?</p>
<pre><code>pd.merge(customer,orders, on = &#39;cust_id&#39;, how = &#39;inner&#39;).groupby([&#39;name&#39;,&#39;item&#39;]).sum().sort_values(&#39;quantity&#39;,ascending = False).loc[&#39;영희&#39;]</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/77414532-e420-4f0a-8816-a7ff91e24639/image.png" alt=""></p>
<h4 id="df의-join메소드">DF의 join()메소드</h4>
<ul>
<li><code>join()</code>은 <code>merge()</code>를 이용한 메소드로써, <strong>index를 사용하여 join을 수행하고</strong>, 기본형태는 다음과 같다.
<code>DataFrame1.join(DataFrame2,how = &#39;left&#39;)</code>
how의 Default값이 &#39;left&#39;이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d4960718-c6a8-42b1-b0aa-dc849e87627d/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/efe00029-7d57-44da-8acc-c69caf583a54/image.png" alt=""></li>
</ul>
<h3 id="dataframe의-replace-메소드">DataFrame의 replace 메소드</h3>
<p>데이터프레임의 특정값을 바꾸고자 하는 메소드로써 가끔 파일을 보다보면 결측치를 &quot;-&quot;라고 처리하는 경우가 있는데, 이럴때 사용하면 좋다.
<code>cust.replace(&quot;_&quot;,np.NaN)</code></p>
<blockquote>
<p><strong>NaN의 Float지원</strong>
NaN은 기본적으로 float형식만을 지원하기 때문에, 다음과 같은 상황
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3e3fc636-d38d-421a-a84b-db92507a4b9c/image.png" alt="">
에서 우리가 age를 <code>astype(float)</code>으로 float형으로 바꾸고 싶다면 NaN을 지원하는 특성때문에 바뀌어진다.
하지만 <code>astype(int)</code>에서 int는 지원하지 않기 때문에 바뀌지 않는다.</p>
</blockquote>
<h3 id="fillna의-method-파라미터">fillna의 method 파라미터</h3>
<p>결측치를 처리하기 위해서 사용하는 메소드중에 <code>fillna()</code>라는 메소드가 있는데 파라미터로 method를 갖는다. 이때 다음과 같다.</p>
<ul>
<li><code>pad</code> or <code>ffill</code> 앞의 원소를 사용하여 결측치를 채운다.</li>
<li><code>bfill</code> or <code>backfill</code> 뒤의 원소를 사용하여 결측치를 채운다.
<code>cust.fillna(method = &#39;ffill&#39;)</code></li>
</ul>
<p>이때, 맨앞 원소와 맨 뒤 원소가 결측치인지 확인해보아야 한다.</p>
<blockquote>
<p>중간값이나 다른값으로 채우고 싶으면 replace를 사용하는 것도 고려해볼만 하디.</p>
</blockquote>
<h3 id="결측치의-선형처리를-위한-interpolate메소드">결측치의 선형처리를 위한 <code>interpolate()</code>메소드</h3>
<p>interpolate 메소드를 사용하면 선형적으로 결측치 값이 채워지는데, 당연하게도 수치형 column만이 채워진다.
<code>cust.interpoltate()</code></p>
<h3 id="결측치-drop하기listwise-pairwisedropna-파라미터">결측치 drop하기(listwise, pairwise)+dropna 파라미터</h3>
<p>결측치를 drop할때 기본적으로 두가지의 개념이 있다</p>
<ul>
<li>listwise방식: 결측치가 하나라도 존재할 경우 drop</li>
<li>pairwise방식: 모든 column이 결측치일 경우 drop</li>
</ul>
<p>두방식 모두 기본적으로 <code>dropna</code>메소드를 사용하고</p>
<blockquote>
<p>pairwise방식 같은 경우에는 dropna의 <code>how</code> 파라미터에 <code>&#39;all&#39;</code>을 작성해주면 되고 기본은 listwise 방식으로 drop한다.</p>
</blockquote>
<ul>
<li><code>dropna</code>의 <code>thresh(threshold)</code>파라미터는 NA가 아닌값이 지정된 개수 이상의 경우만 남겨두고 나머지는 전부 drop한다.</li>
<li><code>dropna</code>의 <code>subset=[column_name1, .. ]</code> 파라미터는 지정된 열 안에 NA만 참고하여 결측치를 처리한다.
예를들어
<code>cust = cust.dropna(subset = [&#39;class&#39;])</code>는 class안에 NA가 존재하면 DROP하고 아니면 DROP하지 않는다.</li>
</ul>
<h3 id="iqr을-inter-quatile-range-">IQR을( Inter Quatile Range )</h3>
<p>우리는 IQR을 기준으로 outlier와 outlier가 아닌것을 비교한다. </p>
<blockquote>
<p><em>*IQR = 1.5</em>(df.quantile(0.75)-df.quantile(0.25)) **로써
quantile 25퍼센트 값으로부터 아래로 IQR미만(즉, value&lt; df.quantile(0.25) - IQR))
quantile 75퍼센트 값으로부터 위로 IQR초과(즉, value&gt;df.quantile(0.75) + IQR))인 경우에 보통 outlier라고 정의한다.</p>
</blockquote>
<h3 id="binning">Binning</h3>
<p>Binning은 수학의 modulo를 이용한 개념으로써 연속형 범주를 범주형 변수로 만들어준다.
다음과 같이 수행할 수 있다.</p>
<pre><code>cust_data[&#39;by_age&#39;] = cust_data[&#39;age&#39;]//10*10</code></pre><p>위의 코드로 나이가 몇십대인지 알려줄 수 있다.</p>
<h3 id="pandas의-binning을-위한-cut과-q_cut-메소드">Pandas의 Binning을 위한 cut과 q_cut 메소드</h3>
<p>판다스는 cut과 qcut메소드를 제공해서 왼쪽 열린구간이 만들어지도록 한다.<br>
이때, cut은 범위를 지정해서(<strong>왼쪽 열린구간 오른쪽 닫힌구간으로 생각</strong>) 그 범위 안에 들어가는 요소에 대해 해당범위를 채워서 Series로 반환해준다.<br>
qcut은 bin의 개수(q)를 지정해서 해당 column의 min과 max값 사이를 q에 지정된 값만큼의 bin의 개수로 나눠준다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/4ba0bc5e-7b7a-421a-994e-d05283db53d7/image.png" alt=""></p>
<blockquote>
<p><strong>이러한 메소드들은 parameter로 <code>labels</code>를 가지고 있는데 따라서 범위에 따라서 categorical한 변수를 만들기 매우 좋은 함수이다.</strong>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3c8dfce7-8c77-493b-b722-853af8588043/image.png" alt=""></p>
</blockquote>
<pre><code>pd.cut(cust_data[&#39;avg_bill&#39;], bins = [0,cust_data[&#39;avg_bill&#39;].quantile(0.25),cust_data[&#39;avg_bill&#39;].quantile(0.75),cust_data[&#39;avg_bill&#39;].max()], labels = [&#39;low&#39;,&#39;mid&#39;,&#39;high&#39;])</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/38ed7a90-648c-4092-90d3-6945fb0504d6/image.png" alt=""></p>
<h3 id="categorical변수-one-hot-encoding을-위한-pandas의-get_dummies함수">categorical변수 one-hot encoding을 위한 Pandas의 <code>get_dummies()</code>함수</h3>
<blockquote>
<p>dummy: 많은 물건들이 모여있는 덩어리</p>
</blockquote>
<p><code>get_dummies()</code>함수를 이용해서 categorical 변수를 원핫 인코딩 시킬 수 있고, 다음과 같이 사용한다.
<code>pd.get_dummies(data,columns[list-like],drop_first, ...)</code></p>
<p>columns를 지정해주지 않을경우 모든 categorical변수에 대해서 get_dummies()함수를 적용한다.</p>
<p>drop_first 파라미터는 zero_vector를 사용할지 결정하는 것으로써 True로 설정해놓으면 사용하지 않는것이다</p>
<blockquote>
<p>classify 문제에서 우리는 target의 one-hot encoding이 돼있냐 안돼있냐에 따라서 돼있으면 categorical_crossentropy 돼있지 않았으면 sparse_categorical_crossentropy를 사용했다.
이때, 이진분류를 수행하는데 drop_first때문에 one-hot encoding이 안돼있는것처럼 돼서 sparse_categorical_crossentropy를 사용한적이 있다. &quot;AICE시험을 위한 M.L코드&quot;를 확인해보길 바란다.</p>
</blockquote>
<h1 id="matplotlib-and-seaborn">Matplotlib and Seaborn</h1>
<h2 id="matplotlib">Matplotlib</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/c00b6293-21c8-422c-9bf9-37b1a5721755/image.png" alt=""></p>
<h3 id="pltscatter">plt.Scatter()</h3>
<p><font color = blue>산점도는 키와 몸무게 같은 두 값 간의 관계를 표현하고</font> 두 값이 양의 상관관계인지 음의 상관관계인지를 파악할 수 있다.
다음과 같이 사용한다.</p>
<pre><code>plt.figure(figsize = (16,5))
plt.scatter(x = df[&#39;age&#39;], y = df[&#39;avg_bill&#39;])
plt.show()</code></pre><h3 id="plthist">plt.hist()</h3>
<p><font color = blue>히스토그램은 수치형 데이터의 분포를 나타낸다.</font> 흔히 빈도, 빈도밀도, 확률등의 분포를 그릴때 사용한다.
bins(default = 10)를 정해줘서 수치형 데이터의 구간을 나눈다.</p>
<pre><code>plt.figure(figsize = (16,5))
plt.hist(df[&#39;age&#39;], bins = 10)
plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/92833a5a-de7d-43d4-b27f-40228c52b6a7/image.png" alt=""></p>
<h3 id="pltbar--dfplotkind--bar">plt.bar() &amp; df.plot(kind = &#39;bar&#39;)</h3>
<p><font color = blue>막대그래프는 범주형 데이터의 수치를 나타낸다. 이것은 위에 hist와 다르게 두개의 변수를 받아서 빈도수가 아닌실제 y값을 표현해준다는 점에서 명백히 다르다.</font>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f370dd24-6e7e-4126-8103-0b6e259b5e0a/image.png" alt="">
DataFrame을 이용해서 그릴수도 있다. 이때, index를 X축으로 사용해야 하기 때문에 DataFrame을 변형하여 그려야 한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c9c1c8b1-5544-499d-8bfb-83359c359354/image.png" alt=""></p>
<p>다음과 같이 그린다.</p>
<pre><code>df2[[&#39;A_bill&#39;,&#39;B_bill&#39;]].plot(kind = &#39;bar&#39;)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/b0a379c4-f378-45bc-9249-28a2a8321f1c/image.png" alt=""></p>
<pre><code>df2[[&#39;A_bill&#39;,&#39;B_bill&#39;]].plot(kind = &#39;bar&#39;,stacked = True)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/24934dad-5adb-4cec-8c73-7d94edd416b4/image.png" alt=""></p>
<h3 id="pltboxplot--dfboxplot">plt.boxplot() &amp; df.boxplot()</h3>
<p>수치적 자료를 받아 값의 범위 분포를 표현하는 그래프이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/6bdb0b10-fb3f-410f-b846-cf7dc3c33e5c/image.png" alt=""></p>
<p>데이터프레임에서도 <code>boxplot()</code>메소드를 활용하여 그릴 수 있는데, 이때, <code>by</code>파라미터는 x축 <code>column</code>파라미터는 y축을 담당하기 때문에 x축은 categorical column이 y축은 수치형 column을 지정하는 것이 보기 좋다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c9ed74a6-e255-4692-9bbf-de97f68f07c3/image.png" alt=""></p>
<h3 id="pltsubplot">plt.subplot</h3>
<p>난 보통 plt.subplots를 이용해서 여러개의 그래프를 한번에 그렸는데, plt.subplot도 이용할만한거 같아서 사용해보겠다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e1a211b1-bc3c-47cf-8410-ebf1dd669ee1/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c6029b5e-5ce1-4b68-abda-34335dd536ca/image.png" alt=""></p>
<h2 id="seaborn">Seaborn</h2>
<p>seaborn은 matplotlib을 기반으로 만든 라이브러리로써, 화려한 시각화를 지원해준다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f5920d4f-b1df-403c-88c1-ad6ca7bef605/image.png" alt=""></p>
<h3 id="seaborn-scatter-plot">Seaborn Scatter plot</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/739abda3-26fa-498a-8592-f5887ba0a373/image.png" alt="">
<code>hue = categorical column</code>을 이용해서 그래프 내에서 분류할 수 있다.</p>
<h3 id="catplotcategorical-plot">catplot(categorical plot)</h3>
<p>sns.catplot은 <code>col</code>파라미터에 categorical변수를 적어줌으로써 해당 category에 포함된 변수들의 산점도를 그려준다. 다음과 같이 사용한다.
<code>sns.catplot(data = df, x=&#39;age&#39;,y=&#39;avg_bill&#39;,col=&#39;sex&#39;)</code>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d969dcfd-d2a6-4bbe-9e0b-ad6224bc6925/image.png" alt=""></p>
<h3 id="lmplot산점도회귀선">lmplot(산점도+회귀선)</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/46a85710-d04b-44ed-8c96-53a23a9d167c/image.png" alt=""></p>
<h3 id="countplot범주형-데이터의-개수-파악">countplot(범주형 데이터의 개수 파악)</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/8ba4c017-b684-44a2-b5fb-72371bdceab7/image.png" alt=""></p>
<h3 id="histplotplthist에-대응연속형-데이터의-범주에-따른-개수-파악-seaborn은-범주형도-깔끔함">histplot(plt.hist에 대응(연속형 데이터의 범주에 따른 개수 파악+ seaborn은 범주형도 깔끔함))</h3>
<pre><code>plt.figure(figsize = (16,5))
sns.histplot(data = df, x = &#39;avg_bill&#39;, bins = 20)
plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/f369f7fc-ef95-41c9-95f7-e86a817d5b3f/image.png" alt=""></p>
<h3 id="유용한-jointplot산점도-histplot">유용한 jointplot(산점도+ histplot)</h3>
<p>산점도와 동시에 데이터의 밀도를 보여주는 plot이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/c050aa42-f644-4276-ac1c-3c030bf229a1/image.png" alt=""></p>
<p>여기서 kind를 사용하면 산점도 영역의 그래프를 다른 모양으로 변경 가능하다.</p>
<h3 id="매우-유용한-heatmap연속형-변수의-상관관계를-그려줌">매우 유용한 heatmap(연속형 변수의 상관관계를 그려줌)</h3>
<blockquote>
<p><strong>seaborn의 heatmap을 사용하기 위해서는 df.corr()을 알아야한다. 이는 데이터프레임의 모든 수치형 변수에 대한 상관관계를 데이터프레임 형태로 반환해준다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/83d60029-5207-48cb-b9db-1d99512bd5df/image.png" alt=""></p>
<h3 id="1변수만-받았던-boxplot과-달리-2변수x--categorical-y--numerical를-받아-표현하는-boxplot">1변수만 받았던 boxplot과 달리 2변수(x = categorical, y = numerical)를 받아 표현하는 boxplot</h3>
<p>우리는 위에서 <code>df.boxplot(by,column)</code>을 통해서 boxplot을 그릴 수 있었다 seaborn과 비교해보겠다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/5708ed30-b733-46a3-afa6-422ab5054a0f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AICE자격증을 위한 D.L코드]]></title>
            <link>https://velog.io/@leesungjoon-net/AICE%EC%9E%90%EA%B2%A9%EC%A6%9D%EC%9D%84-%EC%9C%84%ED%95%9C-D.L%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@leesungjoon-net/AICE%EC%9E%90%EA%B2%A9%EC%A6%9D%EC%9D%84-%EC%9C%84%ED%95%9C-D.L%EC%BD%94%EB%93%9C</guid>
            <pubDate>Wed, 19 Jul 2023 17:50:37 GMT</pubDate>
            <description><![CDATA[<p>나는 DL모델을 주로 파이토치를 이용해서만 사용해왔다. 파이토치로 내가 모델을 구성한이후 <code>loss.backward()</code>를 이용해서 모델의 가중치를 업데이트 하는 방식을 사용해왔었다. 또한 <code>pytorch_lightning</code>을 이용해서 모델을 훈련시켜보기도 했다. 각각에 대한 내용도 상기해서 추후 포스팅에 정리를 해두겠다. 하지만 AICE자격증에서는 TensorFlow를 이용해서 모델을 훈련시키는데, <code>fit()</code>을 사용해서 간단하게 훈련을 시킬 수 있고, 아직 많은 분야에서 TF를 많이 쓰고 있긴 하기 때문에 기본적인 내용을 알아두는 것이 괜찮을 것이라고 생각했다. 그렇다면 시작해보겠다. </p>
<h2 id="dnn">DNN</h2>
<p>DNN은 Deep Neural Network로써 여러개의 hidden layer가 존재하는 Neural Network이다.
ANN, 즉 Artificial Neural Network와의 차이점은 hidden layer가 하나만 존재하면 ANN 2개이상 존재하면 DNN이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/e3364a5e-6e9c-43ec-b6ea-3f4a1d7e8597/image.png" alt="">
<a href="https://iotric.medium.com/deep-neural-network-dnn-its-scope-and-nature-of-complexity-56af59f87ea4">이미지출처</a></p>
<p>너무 많이 봐온 그림이다. 이러한 DNN의 구현을 TensorFlow에선 어떻게 구현할까? 먼저, 필요한 element들을 라이브러리로부터 import 해오겠다.</p>
<pre><code>import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Activation,Dropout</code></pre><p>그 이후 tensorflow는 Sequential()이라는 모델 구성요소를 담는 Container를 정의하고 Sequential 클래스 메소드인 add를 통해서 layer를 추가하면 된다. 다음과 같이 수행하자</p>
<pre><code>model = Sequential()
model.add(Dense(4,activation = &#39;relu&#39;,input_shape=(18,)))
model.add(Dense(3,activation=&#39;relu&#39;))
model.add(Dense(1,activation=&#39;sigmoid&#39;))</code></pre><p>첫번째로 추가시켜준 Dense Layer에는 <code>input_shape</code> parameter를 정의해줘야 한다. 여기에는 18개의 feature가 들어오는 것으로 돼있다.</p>
<p>모델 구성요소를 확인하기 위해서는 <code>summary()</code>클래스 메소드를 사용해주면 된다.
<code>model.summary()</code>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2578704e-df5d-451f-968a-4e165c873788/image.png" alt=""></p>
<h3 id="이진분류">이진분류</h3>
<p>우리는 train과 test set에 모델을 fitting시켜주기 전에 compile과정을 거쳐야 하는데 compile과정은 <code>optimizer</code>,<code>loss</code>,<code>metrics</code> 를 model에 wrapping시켜주는 과정이다. 다음과 같이 진행한다.</p>
<pre><code>model.compile(optimizer = &#39;adam&#39;, loss = &#39;binary_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre><ul>
<li>loss: 손실함수로써 훈련셋과 연관되어 훈련에 사용한다.</li>
<li>metric: 평가지표로써 validation set과 연관돼어 훈련과정을 모니터링 하는데 사용한다.
이 metric은 모델 가중치의 업데이트에는 영향을 미치지 않는다.</li>
</ul>
<br>
우리는 실습단계에서 validation set으로 test set을 사용했는데, 실상은 이렇게 사용하면 안된다.

<blockquote>
<p>하지만.. 시험이고 강의에서 둘다 그렇게 사용했으니깐 그렇게 사용하도록 해보자.. 
실제론 train set으로부터 validation set을 따로 분리한 이후 validation set으로 부터 모델 파라미터들을 조정한후 validation set까지 합쳐서 train set을 새로 만들고 이를 재학습 시켜서 최종적으로 test set으로 성능을 파악해야한다. </p>
</blockquote>
<p>일단 model fitting을 진행해보겠다.</p>
<pre><code>from tensorflow import keras
from keras.callbacks import ModelCheckpoint, EarlyStopping

early_stopping = EarlyStopping(monitor = &#39;val_loss&#39;,patience = 10) # 조기종료 함수

checkpoint = ModelCheckpoint(checkpoint_path, save_weights_only = True,
                             monitor = &#39;val_loss&#39;, verbose = 1,save_best_only = True)

history = model.fit(X_train,y_train,
          validation_data = (X_test,y_test),
          epochs = 20,
          batch_size = 16,
          callbacks = [early_stopping,checkpoint])</code></pre><blockquote>
<p>보통의 경우 여기서 fitting을 진행한후 model의 predict 메소드를 활용해서 X_test를 예측하곤 하는데, AICE 강의에서는 훈련되는 과정을 보여주었다. 따라서 내가 예측을 진행해보았다.
<strong>절대로, X_test를 validation set으로 사용한 모델을 이용해서 X_test를 예측해선 안된다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/94b64da9-0520-45e2-9ab5-d0e2b8be1929/image.png" alt="">
위의 출력결과를 보면 확률이 출력됨을 확인할 수 있다. sigmoid의 결과로써 1일 확률을 출력한 것이다.</p>
<blockquote>
<p>1일 확률이라고 해석하는 이유는 무엇일까? 우린 우선 이진분류를 수행하는 중이다. 또한 LossFunction으로 binary-crossentropy를 사용한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f87e41a3-3437-4e9b-9ef5-e8962b63b946/image.png" alt="">
우선 loss를 최소로 만든다는 그 근간만 잊지 않으면 y=1일 경우 우리는 $y^{hat}$이 1에 가까워야지 loss가 0에 가까워질 것이고, y=0일 경우 $y^{hat}$이 0에 가까워야지 loss가 0에 가까워 질 것이다. 따라서, 우리는 sigmoid의 출력결과가 1일 확률을 예측하는 것이라고 해석할 수 있다.
&rightarrow; 실제로 확률이 아닌 분류를 수행하고 싶으면 예측한 확률을 가지고 threshold(기준)을 세워서 분류를 수행할 수 있을 것이다.</p>
</blockquote>
<p>다시 돌아와서 우리는 fitting을 시킨 이후 history객체를 반환하는데 이 history객체는 loss값과 metric값에 대한 레코드를 유지한다.
model을 fit시키는 과정은 내가 model의 variable을 찍어보니깐 in-place로 fitting이 되는 것 같다. </p>
<h3 id="다중분류">다중분류</h3>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/5567e464-fd74-48e3-a8fa-fcf7fc8de182/image.png" alt=""></p>
<p>다중분류는 마지막 Dense Layer에 activation을 <code>softmax</code>를 사용한다. 
-&gt; 아래는 categorical_crossentropy식
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3d259ecf-8033-4eb2-a892-fdf633d8d57b/image.png" alt=""></p>
<blockquote>
<p>위의 Binary Cross entorpy식도 그렇고 이것도 그렇고 앞에 N이 붙은경우 식이 있고 그렇지 않은 경우의 식이 인터넷에 존재하는데, 아마 내 생각엔 Batch로 처리할때의 표현을 나타낸 것으로 보인다. (정확한건 교수님께 여쭤보고 확인해보겠다)</p>
</blockquote>
<ol>
<li><code>activaiton</code> 설정<ul>
<li>마지막 출력층에 Label의 열이 하나고 두 개의 값으로 이루어진 이진분류라면 <code>sigmoid</code></li>
<li>Label의 열이 두개 이상이라면 <code>softmax</code></li>
</ul>
</li>
<li><code>loss</code>설정<ul>
<li>출력층 activation이 <code>sigmoid</code> 인 경우: <code>binary_crossentropy</code></li>
<li>출력층 activation이 <code>softmax</code> 인 경우: <ul>
<li>원핫인코딩(O): <code>categorical_crossentropy</code></li>
<li>원핫인코딩(X): <code>sparse_categorical_crossentropy</code></li>
</ul>
</li>
</ul>
</li>
<li><code>metrics</code>를 &#39;acc&#39; 혹은 &#39;accuracy&#39;로 지정하면, 학습시 정확도를 모니터링 할 수 있습니다.</li>
</ol>
<p>일반적인 경우 분류문제에서 마지막 Dense Layer에 activation 모델 구성은 다음과 같이 된다.
여기선 아까전 
<code>from tensorflow.keras.layers import Dropout</code>을 import한 것을 상기시켜서 Dropout 또한 적용해보겠다. 
&rightarrow; 드롭아웃도 layer니깐 그냥 add로 추가해주면 된다.</p>
<pre><code>model = Sequential()
model.add(Dense(4, activation = &#39;relu&#39;, input_shape = (18,)))
model.add(Dropout(0.3))
model.add(Dense(3, activation = &#39;relu&#39;))
model.add(Dropout(0.3))
model.add(Dense(2, activation = &#39;softmax&#39;))</code></pre><p>Dropout을 통해 30퍼센트의 노드만이 살아남아서 propagating되도록 했다. <code>model.summary()</code>를 찍으면 다음과 같다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/8697c01c-5217-4beb-8875-8a636d25ea54/image.png" alt=""></p>
<h3 id="compile-and-fit">compile and fit</h3>
<pre><code>model.compile(optimizer = &#39;adam&#39;,
             loss = &#39;sparse_categorical_crossentropy&#39;,
             metrics = [&#39;accuracy&#39;])
history = model.fit(X_train,y_train,
          validation_data = (X_test,y_test),
          epochs = 20,
          batch_size = 16)</code></pre><p>위에서 수행한 모델도 2진 분류 모델이지만 각각의 class에 대해서 확률이 나오도록 하였다 실제로 predict를 통해서 값을 찍어보면 다음과 같이 나온다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/925ea715-fe87-4072-aae0-d5d3b85786b5/image.png" alt=""></p>
<h3 id="history-객체-plot">history 객체 plot</h3>
<p>history객체의 history attribute는 loss와 metrics score에 대한 epoch별 record를 가지고 있다. 따라서 이를 데이터 프레임으로 만들고 그리고 싶은 Feature에 대해서 plot 메소드를 사용하면 간단하게 그릴 수 있다. 다음과 같이 말이다.</p>
<pre><code>record = pd.DataFrame(history.history)
record[&#39;accuracy&#39;].plot()
record[[&#39;loss&#39;,&#39;val_loss&#39;]].plot()</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/af0be2fa-5786-49d1-8735-751b43691e8f/image.png" alt="">
history.history는 딕셔너리를 가지고 있다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f92dff49-ed66-412a-80a8-be54306e1ac4/image.png" alt=""></p>
<p>matplotlib을 활용해 더 이쁘게 꾸밀 수도 있을것이다.</p>
<blockquote>
<p>여기서 sparse_categorical_crossentropy를 사용한 이유는 우리가 더미변수를 만들면서 one-hot encoding을 할때 다음과 같이 encoding을 했기 때문이다.</p>
</blockquote>
<pre><code>pd.get_dummies(data = df, columns = cal_cols, drop_first = True)</code></pre><p>여기서 drop_first parameter는 여러개의 category를 one hot encoding 시킬때, 0으로 채워진 녀석들도 포함 시킬건지의 여부이다. 이로써 원래 N개의 category에 대해서 N개의 one-hot encoding vector가 나올것을 0까지 포함해서 N-1개의 vector가 나오게 된다. </p>
<h2 id="cnn">CNN</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/e80af34d-f84f-4368-9d39-b0c92ee02014/image.png" alt="">
<a href="https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53">이미지 출처</a></p>
<p>image의 기본 shape는 
height,width,channel로 구성돼있다. 다음은 파일을 읽어와서 image를 decod하는 코드이다.</p>
<pre><code>gfile = tf.io.read_file(clean_img_path)
# tensorflow.inputoutput.read_file path에서 file을 읽어오고
print(type(gfile))
image = tf.io.decode_image(gfile, dtype=tf.float32)
# image를 decode한다.</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/48caaa6c-7cb4-46d0-bba0-682395820ea6/image.png" alt=""></p>
<p>실제로 image를 출력해보면 다음과 같다
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d0147272-cfc4-4b7d-8e90-4b46ee534541/image.png" alt="">
각각의 channel(RGB)값이 하나의 element(pixel)을 구성하고 그 element가 512개가 모여 하나의 line을 구성하고 그 line이 다시 384개가 모여 하나의 image를 구성함을 알 수 있다.</p>
<p>우리는 이런 image 데이터 특성을 이해하는 이유는 image 데이터를 전처리 하기 위해서이다. 
자 다시 위에 진행한 DNN을 생각해보자. 우리는 DNN에서</p>
<pre><code>from sklearn.model_selection import train_test_split</code></pre><p>을 통해 train set과 test set을 구분했던걸 기억할 것이다. 그런데 이미지 데이터셋은 어떻게 구분할까? 이를 위해선 tensorflow에서 제공하는 <code>ImageDagaGenerator</code>객체를 사용하여야 한다. 이는 tensorflow.keras의 preprocessing.image에 존재한다. 따라서 다음과 같이 import를 수행하면 된다.
<code>from tensorflow.keras.preprocessing.image import ImageDataGenerator</code></p>
<p>이를 통해 우리는 Image 데이터를 scaling 함과 동시에 validation_split인자를 사용해 이미지를 train set과 test set으로 나눌수 있다. </p>
<blockquote>
<p>물론 이 방법 외에도 나눌 수 있는 방법이 있을 것이다. 나의 주전공이 CV가 아니기 떄문에, CNN에 익숙치 않아서, 강의에서 알려주는 방식을 좀더 detail하게 기술할 뿐이다. 나중에 알게되면 추가 포스팅을 작성하겠다.</p>
</blockquote>
<p>다시 돌아와서 위의 방식으로 나누기 위해선 generator를 우선 두개를 생성한다. </p>
<pre><code>training_datagen = ImageDataGenerator(rescale = 1./255, validation_split = 0.2)
test_datagen = ImageDataGenerator(rescale = 1./255, validation_split = 0.2)</code></pre><p>이 generator의 <code>flow_from_directory</code>메소드를 사용하여서 pytorch의 DataLoader처럼 데이터가 세팅됨을 알 수 있다. 즉, Batch형태로 묶어주는 역할을 수행한다 코드는 다음과 같다.</p>
<pre><code>
# Generate Batch ImageDataGenerator객체의 메소드이다.
training_generator = training_datagen.flow_from_directory(
    &#39;./IMAGE/dataset-clean,dirty/&#39;,
    batch_size=batch_size, 
    target_size=(384, 512),       # 타겟 이미지의 사이즈 확인
    class_mode = &#39;categorical&#39;,   # binary , categorical
    shuffle = True,
    subset = &#39;training&#39;           # training, validation. validation_split 사용하므로 subset 지정
    )
# 데이터 증강과정인 ImageDataGenerator에서 validation_split을 사용했다면 
# subset을 training으로 설정해 줘야지 제대로 설정된다.(이 주피터 노트북에서는 test의 validation set을 사용하는게 좀 이상하긴 하다.
# class_mode를 통해 생성된 데이터셋이 가질 target label의 형태를 설정하는 것으로 categorical은 2D형테의 원-핫 인코딩 label이고 binary는 1D형태의 이진 label이다.
# Pytorch의 DataLoader와 비슷한 역할을 하는 것으로 보이는데, 구체적으로는 하위 디렉토리에 있는 모든 image데이터를 Image증강 단계인 ImageDataGenerator의 규격에 맞추어 가져온다.

test_generator = test_datagen.flow_from_directory(
    &#39;./IMAGE/dataset-clean,dirty/&#39;,
    batch_size=batch_size, 
    target_size=(384, 512),       # 사이즈 확인
    class_mode = &#39;categorical&#39;,   # binary , categorical
    shuffle = True,
    subset = &#39;validation&#39;         # training, validation. validation_split 사용하므로 subset 지정
    )</code></pre><blockquote>
<p>여기서 Batch형태로 묶을 경우에, batch_size = 4라고 하면, 크기가 어떻게 될까 궁금해서 찾아봤는데 그저 차원이 하나 늘었을 뿐이다. 다음과 같이 차원이 나온다.</p>
</blockquote>
<pre><code>batch_samples = next(iter(training_generator))
print(batch_samples[0].shape)
print(batch_samples[0][0].shape) #4d batch에서 cube의 형태를 유추할 수 있다.
print(batch_samples[1]) # 위에서 설정한대로 target label이 2D형태의 원-핫인코딩이 됐음을 확인할 수 있다. batch_samples를 출력하면 tuple이 나오는데 첫번째는 Batch가 나오고 두번째는 Target class가 나오는것을 확인할 수 있다.
# 여기서 class는 해당이미지가 속한 폴더의 이름을 의미하는 것 같다.
# binary로 바꿀경우 다음과 같은 형태가 나온다. [1. 1. 1. 1.]</code></pre><p>이제 CNN모델링을 시작해보자.</p>
<h2 id="cnn모델링">CNN모델링</h2>
<p>CNN도 마찬가지로 convolutional layer와 pooling layer가 존재해서 각 Feature의 특징을 뽑아내고 그들을 합치는 과정을 거친다. 확인해보자.</p>
<pre><code>import tensorflow as tf
from tensorflow.models import Sequential
from tensorflow.layers import Conv2D,MaxPooling2D,Dense,Flatten,Dropout</code></pre><pre><code>model = Sequential()#1
model.add(Conv2D(filters= 32, kernel_size =3,activation=&#39;relu&#39;, input_shape= (384,512,3))#2
model.add(MaxPooling2D(pool_size = 2))#3
model.add(Conv2D(filters= 16, kernel_size = 3, activation=&#39;relu&#39;))#4
model.add(MaxPooling2D(pool_size = 2))#5

model.add(Flatten())#6
model.add(Dense(50,activation=&#39;relu&#39;))#7
model.add(Dense(2,activation=&#39;softmax&#39;))#8</code></pre><p>#1 container 생성
#2 kernelsize = 3-&gt; 3x3 커널로 filters = 32-&gt;32개의 filter를 만들어서 이미지를 훑는다(합성곱 한다).
#3 합성곱해서 나온 이미지를 2x2 커널로 MaxPooling을 진행한다.(height와 width가 각각 2씩 줄어들것이다.)
#4 그렇게 해서 나온 이미지를 다시 16개의 filter를 만들어서 kernel_size 3x3으로 훑는다.(합성곱한다.)
#5 합성곱해서 나온이미지를 MaxPooling한다.
#6 그렇게 해서 나온 요소들을 쭉 펼친후 
#7~#8 DNN에 투입하여 분류를 수행한다.</p>
<h3 id="model-compile-fit">model compile&amp; fit</h3>
<pre><code>#model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate), 
model.compile(optimizer=&#39;adam&#39;, 
              loss=&#39;categorical_crossentropy&#39;, 
              metrics=[&#39;accuracy&#39;]) 
# fit을 하기전에 거쳐야 하는 과정

history = model.fit(training_generator, 
          epochs=20 ,
          steps_per_epoch = len(training_generator) / batch_size,
          validation_steps = len(test_generator) / batch_size,
          validation_data=test_generator, 
          verbose=1
)</code></pre><p>steps_per_epoch와 validation_steps는 학습과 평가를 조절하는 인자이다.</p>
<blockquote>
<p>steps_per_epoch: 에포크마다 모델을 통과할 Batch Step
&rightarrow; 한번의 에포크마다 몇개의 Batch를 통과시킬 것이냐
validation_steps: 각 Epoch마다 검증을 수행할 Batch의 갯수
&rightarrow; 이를 통해 더 빠른 Validation을 도모한다.</p>
</blockquote>
<h3 id="성능시각화">성능시각화</h3>
<p>위의 DNN과 비슷한 방식으로 수행하면 된다.</p>
<h2 id="rnn">RNN</h2>
<p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/78daf325-a87b-423f-9e73-d99f631124d1/image.png" alt="">
<a href="https://en.wikipedia.org/wiki/File:Recurrent_neural_network_unfold.svg">이미지 출처</a></p>
<pre><code>#RNN 라이브러리 임포트

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Flatten</code></pre><p>RNN은 데이터를 axis = 1에 데이터를 넣어줘야한다.
즉, 다음과 같이 구성시켜야한다(pytorch와 동일)</p>
<pre><code>X_train = X_train.reshape(-1,18,1)
X_test = X_test.reshape(-1,18,1)</code></pre><pre><code>model = Sequential()
model.add(LSTM(32, activation=&#39;relu&#39;, return_sequences=True, input_shape=(18, 1)))
# lstm의 hidden state크기라고 research에서 표현할 수 있지만, tf에서는 unit의 output크기라고 표현
# return_sequences
model.add(LSTM(16, activation=&#39;relu&#39;, return_sequences=True))
model.add(Flatten())
model.add(Dense(8, activation=&#39;relu&#39;))
model.add(Dense(1, activation=&#39;sigmoid&#39;))</code></pre><p><code>return_sequences=True</code>라고 설정하면 모든 시점의 hidden_state를 출력한다.
따라서 위에는 모든시점의 hidden_state를 출력하고 DenseLayer에 넣는것으로 보면 된다.</p>
<h3 id="model-compile-and-fit">model compile and fit</h3>
<pre><code>model.compile(optimizer=&#39;adam&#39;, 
              loss=&#39;binary_crossentropy&#39;, 
              metrics=[&#39;accuracy&#39;]) 
# compile은 optimizer loss, metric을 정의한다.

history = model.fit(x=X_train, y=y_train, 
          epochs=10 , batch_size=128,
          validation_data=(X_test, y_test), 
          verbose=1
)</code></pre><h3 id="성능-시각화">성능 시각화</h3>
<p>위에 DNN과 똑같이 진행하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AICE자격증을 위한 M.L 코드 ]]></title>
            <link>https://velog.io/@leesungjoon-net/AICE%EC%9E%90%EA%B2%A9%EC%A6%9D%EC%9D%84-%EC%9C%84%ED%95%9C-M.L-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@leesungjoon-net/AICE%EC%9E%90%EA%B2%A9%EC%A6%9D%EC%9D%84-%EC%9C%84%ED%95%9C-M.L-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Tue, 18 Jul 2023 06:43:33 GMT</pubDate>
            <description><![CDATA[<p>나는 주로 다루는 것이 파이토치 딥러닝을 주로 다루어 왔다. 이번 방학에 기본기를 다지고자 AICE자격증을 신청했고, pandas와 matplotlib seaborn에 대해서 기본기를 숙달하기 좋은 기회였다. 그에 비해 너무나 방대한 ML DL은 사용해보는 정도의 수준에 머물렀는데, DL은 익숙한 편이지만 ML은 예전에 해보고 까먹었기 때문에 내가 추가로 내용을 조금씩 정리해보면서 복습해보겠다.(이론의 완벽한 정리를 하는 것은 아니지만 핵심만 집어보겠다. 혹시나 틀린 것이 있다면 알려주시면 감사하겠습니다 !)</p>
<h1 id="ml">M.L</h1>
<h2 id="train데이터-test데이터-split">Train데이터 Test데이터 split</h2>
<pre><code>from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=0.3, 
                                                    stratify=y,
                                                    # y를 기준으로 비율을 나누는 것이다.
                                                    random_state=42)a</code></pre><p><code>stratify</code>는 target의 각 category의 비율을 train test 비율에 맞춰서 동등하게 나눠주는 역할을 한다. 이를 통해 한쪽에 데이터가 몰릴경우 맞추지 못하는 현상을 방지한다.</p>
<h2 id="scaler">Scaler</h2>
<p>데이터의 scaling은 각 Feature의 영향이 수치적인 크기에 따라서 좌지우지 되는 것을 막고자 사용한다.
<code>StandardScaler</code>: 우리가 아는 표준정규분포로 정규화 할때 사용하는 공식을 사용하여 정규화한다.
<code>MinMaxScaler</code>: Min값과 Max값을 이용해 정규화를 진행하는데 0~1사이의 값으로 나오도록 한다.
<code>from sklearn.preprocessing import MinMaxScaler</code>
import는 sklearn의 preprocessing에서 진행하고 유의할점은 다음과 같다.</p>
<blockquote>
<p>train데이터를 이용해 <code>fit_transform</code>을 진행해서 scaler가 train데이터의 정보를 이용해서 fit하고 transform할 수 있도록 하고, 이 train데이터의 정보를 이용해서 test데이터를 scaling해야한다. 
train, test데이터를 위와 같이 나누는 이유는 train set에 test set의 정보가 안 흘러들어가도록(Data Leakage)를 방지하기 위해서이다.</p>
</blockquote>
<h2 id="logistic-regression">Logistic Regression</h2>
<p>분류를 위한 회귀로써 회귀를 수행하고 나서(
y = a1x1+a2x2+ ... + 식으로 만들고 나서)
y값을 sigmoid function에 넣음으로써 분류를 수행한다. 이때, loss함수는 크로스 entrophy함수를 사용한다. 이 loss를 낮출 수 있도록 계수를 줄인다. 
참고할만한 링크를 달아두겠다.
<a href="https://hleecaster.com/ml-logistic-regression-concept/">블로그</a>
위의 Logistic Regression을 사용하기 위해서는 sklearn의 linear_model을 사용하면 된다.</p>
<pre><code>from sklearn.linear_model import LogisticRegression
lg = LogisticRegression(C=1.0, max_iter = 2000)
lg = lg.fit(X_train,y_train)
# 강의에서는 fit하고 다시 재할당을 해주지 않았지만, 나는 일관성을 위해 하겠다.</code></pre><blockquote>
<p><strong>parameter 소개</strong>
<code>C</code> 는 regularization strength의 역수로써 작으면 작을수록 가중치에 더 강한 regularization이 적용된다.
parameter 중에 <code>solver</code>가 있는데 solver는 gradient descent를 기반으로 한 weight를 최적화하는 유형들을 구분한 것이다. 
<code>max_iter</code>은 이러한 solver의 최적화 방식을 몇번 수행할것인지 정해주는 것이다.(epoch와 유사한 의미로 보인다.)</p>
</blockquote>
<h2 id="metricsaccuracy-precision-recall-f1-score">metrics(accuracy, precision, recall, f1 score)</h2>
<p>import하는 방법은 다음과 같다.
<code>from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score</code></p>
<p><code>accuracy_score</code>: 모델이 정답을 맞춘것의 비율
<code>precision_score</code>: 모델이 True로 예측한 데이터중 실제로 True인 데이터
<code>recall_score</code>: 내일 눈이 내릴지 아닐지를 예측하는 모델이 있다고 해볼떄, 이 모델이 항상 False를 출력하게 한다면 꽤 좋은 예측 성능을 보장할 수 있을 것이다.
이러한 상황을 방지하기 위해 실제로 True인 데이터를 모델이 True라고 인식한 데이터의 비율인 recall_score를 확인하여야 한다.
<code>f1 score</code>: 정밀도 + 재현율
위의 정밀도와 재현율은 trade-off 관계가 있어서, 이 둘을 모두 평가하기 위해서는
그 둘을 조화평균으로 엮은 F1 Score를 확인해보면 된다.</p>
<h2 id="knnk-nearest-neighbor">KNN(K-Nearest Neighbor)</h2>
<p>어떤 데이터를 기준으로 그 주변을 확인해서 더 많은 이웃이 속한 클래스로 판정하는 것이 KNN이다.
import는 다음과 같이 수행한다.</p>
<pre><code>from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 5)
knn.fit(X_train,y_train)</code></pre><h2 id="decisiontree">DecisionTree</h2>
<p>DecisionTree는 feature_importance를 제공하고 좋은 성능을 보인다는 점에서 훌륭하다. 
classfier 혹은 Regression 둘다로 사용할 수 있다.</p>
<blockquote>
<p>간단하게 Regression은 영역에 포함되는 element들의 평균을 사용한다고 생각하면 된다.</p>
</blockquote>
<p>먼저 <code>DecisionTreeClassifier</code>를 사용해보겠다.</p>
<pre><code>from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier(max_depth = 10, random_state = 42)
tree.fit(X_train,y_train)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/978f1d5e-4999-4312-b73f-a0096e18c045/image.png" alt="">
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/1e2ff926-02a1-4fb2-94aa-3d093840d6f6/image.png" alt=""></p>
<p>위의 두사진을 보면 감이 안올 것이다. 이는 내가 정리한 XAI word파일에 tree의 feature_importance를 구하는 방식을 정리해놓은 것을 보아야하는데, 우선 tree가 분기하는 방식이 entropy를 제일 낮추는 feature를 선택한다는 것을 기억하자. 
전체적인 데이터를 보고 위에 overcast에 해당하는 것들이 yes임을 확인하고, 나머지 feature에 대해서도 확인하는 방식으로 fitting을 진행한다.</p>
<blockquote>
<p><strong>parameter</strong>
파라미터로는 위에서 max_depth가 사용됐는데 말 그대로 트리의 최대 깊이를 의미한다.
이외에도, 각 노드와 leaf가 가져야할 sample의 최소갯수를 지정해주는 파라미터 등이 있다.</p>
</blockquote>
<h2 id="ensemble">Ensemble</h2>
<p>앙상블은 약한힘을 발휘하는 모델 여러개가 강한힘을 발휘하는 모델 한개보다 좋을 것이라는 발상에서 나왔다.</p>
<p><strong>앙상블 기법의 종류</strong></p>
<h3 id="배깅-bagging">배깅 (Bagging):</h3>
<p>여러개의 DecisionTree 활용하고 샘플 중복 생성을 통해 결과 도출. RandomForest
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/f411c013-c7ef-400e-be0b-99ae9bb9b0e2/image.png" alt="">
<a href="https://zetawiki.com/wiki/%EB%B0%B0%EA%B9%85">사진 출처</a></p>
<p>Bootstrap은 통계학에서 사용하는 용어로, random sampling(복원추출)을 적용하는 방법으로써 복원추출을 통해서 training data를 늘린다. 즉, Bagging은 Bootstrap을 통해서 얻은 train_data로 각각의 모델을 학습시킨 이후 각각의 예측을 <strong>categorical의 경우 투표로 집계하고 continuous의경우 평균으로 집계된다.</strong></p>
<h4 id="randomforest">RandomForest</h4>
<p><code>random forest</code>를 한번 사용해 보겠다.</p>
<p><strong>주요 Hyperparameter</strong></p>
<ul>
<li>random_state: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!</li>
<li>n_jobs: CPU 사용 갯수</li>
<li>max_depth: 깊어질 수 있는 최대 깊이. 과대적합 방지용<font color = blue> </li>
<li>n_estimators: 앙상블하는 트리의 갯수</font></li>
<li>max_features: 최대로 사용할 feature의 갯수. 과대적합 방지용[한번에 분기할 기준으로 사용할 feature갯수]</li>
<li>min_samples_split: 트리가 분할할 때 최소 샘플의 갯수. default=2. 과대적합 방지용</li>
</ul>
<pre><code>from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(n_estimators = 30, max_depth = 10, random_state = 42)
rfc.fit(X_train,y_train)</code></pre><h3 id="부스팅-boosting">부스팅 (Boosting):</h3>
<p>약한 학습기를 순차적으로 학습을 하되, 이전 학습에 대하여 잘못 예측된 데이터에 가중치를 부여해 오차를 보완해 나가는 방식. XGBoost, LGBM
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/fd2f2d44-1899-482e-b71e-cdc3f451ec9e/image.png" alt="">
<a href="https://quantdare.com/what-is-the-difference-between-bagging-and-boosting/">이미지 출처</a>
Boosting도 bootstrap을 통해 충분한 데이터를 확보하고 학습 알고리즘을 순차적으로 학습시킨다.</p>
<p>내가 이해한 바대로 작성해보겠다. 먼저 모델에 sequential한 특징을 부여한 것이 첫번째 Boosting계열 모델의 특징이다. 모든 모델은 학습하기전에, 데이터를 bootstrap하고, 학습을 통해 예측을 수행한다. 예측을 수행한후 target과의 error를 구한이후 그 에러를 바탕으로 데이터에 가중치를 곱해준다.(한 weekly 학습기가 학습할 때 Bootstrap추출된 데이터에 대해서 동일한 가중치를 곱한다.) 그 이후 이 에러를 바탕으로 모델 가중치(초기화는 1/(약한학습기의 개수)를 조정한다.
그 다음 모델은 앞서서 잘 분류하지 못한(가중치가 곱해진) 데이터를 더욱 심도있게 살펴보아서 그들을 잘 분류할 수 있는 모델을 만들고 이 모델에 대해서도 모델 가중치를 구한다.</p>
<p>이렇게 구한 n개의 모델을 additive model로 만들어서 최종적으로 예측을 수행한다.</p>
<p>Adaboost는 Decision Tree를 약한학습기로 사용하고 있기 때문에 entrophy를 최적화하는 방식으로 학습한다.(Not gradient descent)</p>
<p>GBM(Gradient Boosting Machine)은 adaboost와 유사하지만 경사하강법을 사용한다. 경사하강법을 사용하는만큼 예측성능은 좋지만 과적합이 될 가능성이 높다.</p>
<p>이문제를 해결하고자 한게
XGBoost: GBM에 기반한 것으로 GBM에 regularization term을 추가했다. 병렬학습이 가능하고다.
LightGBM: LightGBM은 최적의 리프만을 계속해서 분할하는 Leaf-wise tree growth방법을 사용한다.</p>
<p>각각이 큰 주제이기 때문에 여기선 이정도만 알고 넘어가겠다.</p>
<h4 id="xgboost">xgboost</h4>
<p>xgboost는 sklearn에서 제공하지 않기 때문에, 따로 install해주어야 한다. 다음과 같이 install하고 사용한다.</p>
<blockquote>
<p><strong>주요 Hyperparameter</strong></p>
</blockquote>
<ul>
<li>random_state: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!</li>
<li>n_jobs: CPU 사용 갯수</li>
<li>learning_rate: 학습율. 너무 큰 학습율은 성능을 떨어뜨리고, 너무 작은 학습율은 학습이 느리다. 적절한 값을 찾아야함. n_estimators와 같이 튜닝. default=0.1<font color = blue></li>
<li>n_estimators: 부스팅 스테이지 수. (랜덤포레스트 트리의 갯수 설정과 비슷한 개념). default=100</font></li>
<li>max_depth: 트리의 깊이. 과대적합 방지용. default=3. </li>
<li>subsample: 샘플 사용 비율. 과대적합 방지용. default=1.0</li>
<li>max_features: 최대로 사용할 feature의 비율. 과대적합 방지용. default=1.0</li>
</ul>
<pre><code>!pip install xgboost
from xgboost import XGBClassifier
xgb = XGBClassifier(n_estimator = 3, random_state = 42)
xgb.fit(X_train,y_train)
xgb_pred = xgb.predict(X_test)</code></pre><h4 id="lightgbm">LightGBM</h4>
<p>lightgbm또한 scikit learn에서 제공하지 않기 때문에, 따로 install해주어야 한다. 다음과 같이 install하고 사용해야한다.</p>
<blockquote>
<p><strong>주요 Hyperparameter</strong></p>
</blockquote>
<ul>
<li>random_state: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!</li>
<li>n_jobs: CPU 사용 갯수</li>
<li>learning_rate: 학습율. 너무 큰 학습율은 성능을 떨어뜨리고, 너무 작은 학습율은 학습이 느리다. 적절한 값을 찾아야함. n_estimators와 같이 튜닝. default=0.1</li>
<li>n_estimators: 부스팅 스테이지 수. (랜덤포레스트 트리의 갯수 설정과 비슷한 개념). default=100</li>
<li>max_depth: 트리의 깊이. 과대적합 방지용. default=3. </li>
<li>colsample_bytree: 샘플 사용 비율 (max_features와 비슷한 개념). 과대적합 방지용. default=1.0</li>
<li>subsample: 샘플 사용 비율. 과대적합 방지용. default=1.0</li>
</ul>
<pre><code>!pip install lightgbm
from lightgbm import LGBMClassifier
lgbm = LGBMClassifier(n_estimators = 3, random_state = 42)
lgbm.fit(X_train,y_train)
lgbm_pred = lgbm.pred(X_tset)</code></pre><h3 id="스태킹-stacking">스태킹 (Stacking):</h3>
<p>여러 모델을 기반으로 예측된 결과를 통해 Final 학습기(meta 모델)이 다시 한번 예측하는 방법이다. 이는 너무 좋은 포스팅을 찾았기 때문에 공유드리겠다.
<a href="https://techblog-history-younghunjo1.tistory.com/103">K-fold stacking 블로그</a>
<a href="https://kjhov195.github.io/2019-11-20-ensemble_2/">Vanilla stacking 블로그</a></p>
<p>KFold 교차검정으로 stacking을 사용하지 않고 기본적인 stacking의 과정은 다음과 같다.</p>
<p>개별 모델이 예측한 데이터를 기반으로 <strong>final_estimator</strong>에 종합하여 예측을 수행합니다.
한마디로 final model을 하나두고 그 이전단계에서 각각의 모델이 예측한 예측값을 Feature로써 사용해서 모델을 training시키고 final_model을 이용해 예측하는 경우를 얘기한다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/d454c6a8-3b61-4d7c-8cec-61ba6a589b4d/image.png" alt="">
<a href="https://www.geeksforgeeks.org/stacking-in-machine-learning-2/">이미지 출처</a></p>
<ul>
<li>성능을 극으로 끌어올릴 때 활용하기도 합니다.</li>
<li>과대적합을 유발할 수 있습니다. (특히, 데이터셋이 적은 경우)</li>
</ul>
<p>실제로 사용할때는 다음과 같이 사용한다. </p>
<pre><code>from sklearn.ensemble import StackingRegressor, StackingClassifier
stack_models = [
    (&#39;LogisticRegression&#39;, LogisticRegression(C=1.0,max_iter = 1000)), 
    (&#39;KNN&#39;, KNeighborsClassifier(n_neighbors = 10)), 
    (&#39;DecisionTree&#39;, DecisionTreeClassifier(max_depth = 10)),
]
rfc = RandomForestClassifier(n_estimators = 15)
stacking = StackingClassifier(stack_models, final_estimator=rfc, n_jobs=-1)
stacking.fit(X_train,y_train)</code></pre><p>원래 AICE강의에서는 학습된 모델을 사용했었는데, 모델의 구조를 보니 쫌 이상해서 아래 자료를 참고해보니 최초의 모델로 stacking을 수행했다.
<a href="https://www.kaggle.com/code/marcinrutecki/stacking-classifier-ensemble-for-great-results">https://www.kaggle.com/code/marcinrutecki/stacking-classifier-ensemble-for-great-results</a></p>
<h3 id="weighted-blending">Weighted Blending</h3>
<p>예측값에 weight를 곱해서 최종 output을 계산한다. 모델에 대한 가중치를 합산이 1이되도록 heuristic하게 조절한다.</p>
<pre><code>final_outputs = {
    &#39;DecisionTree&#39;: dt_pred, 
    &#39;randomforest&#39;: rfc_pred, 
    &#39;xgb&#39;: xgb_pred, 
    &#39;lgbm&#39;: lgbm_pred,
    &#39;stacking&#39;: stacking_pred,
}
# \은 줄바꿈의 의미
final_prediction=\
final_outputs[&#39;DecisionTree&#39;] * 0.1\
+final_outputs[&#39;randomforest&#39;] * 0.2\
+final_outputs[&#39;xgb&#39;] * 0.25\
+final_outputs[&#39;lgbm&#39;] * 0.15\
+final_outputs[&#39;stacking&#39;] * 0.3\

final_prediction = np.where(final_prediction &gt; 0.5, 1, 0)
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[python lambda function, list comprehension, locals, f-string]]></title>
            <link>https://velog.io/@leesungjoon-net/python-lambda-function-list-comprehension-locals-f-string</link>
            <guid>https://velog.io/@leesungjoon-net/python-lambda-function-list-comprehension-locals-f-string</guid>
            <pubDate>Tue, 27 Jun 2023 07:33:48 GMT</pubDate>
            <description><![CDATA[<p>책 [파이썬 알고리즘 인터뷰]의 3장에서 나온 파이썬 관련요소의 나머지를 한번 뜯어보겠다.
먼저 은연중 넘어간 Lambda Function이다.</p>
<h1 id="1-lambda-function">1. lambda Function</h1>
<p>사실 실제로 코딩을 할때, 이렇게 간단한 함수를 단독으로 사용하는 경우는 많이 없다. 따라서 사용경험은 많이 없는데, 이 기회에 정리를 해두면 좋을것 같아서 정리를 해두겠다.
람다는 간단한 함수를 하나의 line으로 간편하게 작성해서 사용하기 위해서 사용한다.
<code>lambda</code>의 기본적인 구성요소는 다음과 같다.
<code>lambda &lt;매개변수&gt;: &lt;결과 표현식&gt; &lt;조건&gt;</code>
위에서 언급한 lambda function을 활용하는 예시를 살펴보자.</p>
<pre><code>f = (lambda n,m: n+m if n&gt;0 else 0)
print(f(-1,2))
</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/cba1cfaa-7de6-43a4-add0-6ef03bc3e141/image.png" alt="">
주의해야할 점은 다음과 같다.</p>
<ul>
<li>뒤에 조건에 if와 else는 하나의 쌍이다. 즉, 조건문은 다음과 같은 형태여야한다.
<code>if 조건 else 결과표현식이 될 value</code>
즉, 다음과 같이 사용하면 오류가 발생한다.<pre><code>f = (lamda n,m: n+m if n&gt;0 else n=0)
or
f = (lambda n,m: n+m if n&gt;0 else if m&gt;0 ...)
# lambda function에서는 else if 를 사용할 수 없음
or
f = (lambda n,m: n+m if n&gt;0 n=4 else n=0)</code></pre>따라서 다중조건이 필요한 경우 lambda 함수를 작성하는 것은 고려하지 말자.<blockquote>
<p><code>map() filter() reduce()</code> 클래스는 함수를 매개변수로 받아서 결과를 반환하는데, 이때 람다함수를 자주 사용하곤한다. </p>
</blockquote>
</li>
</ul>
<p><strong>2. list comprehension</strong>
list comprehension은 꽤나 많이 사용해봤다고 생각했다. 책을 읽고 list comprehension을 dictionary에서 활용한 것을 보는 순간 큰 착각이였다는 것을 깨달았다.</p>
<p>먼저, <strong>list comprehension</strong>은 무엇인가 하면 리스트를 더 간편하게 구성하고자 사용하는 파이썬 구문이다.
따라서 기본적인 구성요소는 다음과 같다.
<code>[ (변수) for (변수) in (iterable객체) if문]</code></p>
<p>예시를 살펴보자 가볍게 1부터 10까지 짝수만을 리스트에 넣어보겠다. 다음과 같이 작성할 수 있을 것이다.</p>
<pre><code>new = []
for i in range(1,11):
    if i%2==0:
        new.append(i)
print(new)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/8adca2e7-7c87-4075-9646-c4a9bbebd78d/image.png" alt=""></p>
<p>이를 단번에 줄일 수 있다.
<code>print([new for new in range(1,11) if new % 2 == 0])</code>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/b9ca1a4d-ba10-45c2-be02-70d4c9918c8e/image.png" alt=""></p>
<p>위에처럼 리스트를 생성하면 생각을 하지 않고, 리스트를 생성할 수 있다. 하지만 코드가 길어지는 원인이 되기 때문에, 아래처럼 리스트 comprehension을 작성하도록 하자.</p>
<blockquote>
<p>list comprehension에서도 조건문을 여러개 작성할 수 있다. 하지만 if문을 사용할때 
<code>[n for n in range(1, 31) if n % 2 == 0 if n % 3 == 0]</code> 왼쪽과 같이 작성을 해야하고 이는 and로 연결돼있다. 가독성을 위해 and로 연결하고자 하면 오류를 발생시키고 or는 애초에 사용조차 할 수 없다.
<br>
결론적으로, 모든 적당한 것이 좋다. 여러 조건문을 사용해서 리스트를 구성해야할때는, 굳이 list comprehension을 작성하려고 하지말자 !</p>
</blockquote>
<blockquote>
<p>위의 구조를 이용해서 다음과 같이 리스트 컴프리헨션을 작성할 수도 있다.
<code>[i if i%2==0 else &#39;odd&#39; for i in range(5)]</code>
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/507e8c58-f1dc-4a77-985f-69904d130a0e/image.png" alt="">
위의 그림을 참고하면 <code>(if문이 True일때) if ~ else (if문이 False일때)</code>라는 명령어에 익숙해지고 이를 리스트 컴프리헨션안에 넣을수도 있다.</p>
</blockquote>
<ul>
<li>list comprehension을 꼭 리스트가 아닌 다른 자료구조(e.g. tuple, set, dictionary)에도 사용할 수있다.</li>
</ul>
<pre><code>set_a = { n for n in range(1,10) }
print(set_a)
print(type(set_a))</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/3acc0b65-7ac2-43d8-b665-e2a9c7fecf5f/image.png" alt=""></p>
<pre><code>from string import ascii_lowercase as Lower

print(Lower)
dict_a = {c: n for c, n in zip(Lower,range(1,27))}
print(dict_a)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/5abb102b-4c38-4d37-9226-9ce19d454319/image.png" alt=""></p>
<p>자 그렇다면 이제, tuple에 대해서 한번 해보자 !</p>
<pre><code>tup_a = ( n for n in range(1,10) )
print(tup_a)
print(type(tup_a))</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/37ef1831-9191-416f-b010-84f9bd10c711/image.png" alt="">
자연스럽게 위와 같이 작성하고 실행한 나는 예상치 못한 결과에 당황했다. 
알고보니 이는 generator를 만드는 <strong>generator comprehension</strong>이었다. </p>
<blockquote>
<p>이것이 바로 generator를 만들때 yield 구문을 사용하지 않고 generator를 만들 수 있는 방법이다.</p>
</blockquote>
<p>tuple을 만들기 위해서는 tuple()을 사용해주면된다.</p>
<pre><code>tup_a = tuple(( n for n in range(1,10) ))
print(tup_a)
print(type(tup_a))</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/6e106f70-5991-4f11-8c91-eca28f552833/image.png" alt=""></p>
<p><strong>3. locals()</strong></p>
<p><code>locals()</code>는 모든 지역변수를 조회할 수 있는 강력한 명령으로써 디버깅에 많은 도움이 된다. 특히 local scope에 제한해 정보를 조회하기 때문에 더욱 도움이 된다. 한번 <code>Decorator</code> 포스팅에서 사용한 <code>calculator class</code>를 이용해서 사용해보겠다.</p>
<pre><code>
from typing import Tuple
import pprint

class Calculator:
    def __init__(self, func):
        self.func = func

    def __call__(self,*args,**kwargs):
        print(&quot;연산시작&quot;)
        self.func(args)
        print(&quot;연산종료&quot;)



@Calculator
def add(tup: Tuple): # 2. add function 선언
    summation = 0
    for i in tup:
        summation = summation + i

    print(summation)
    print(locals())

add(1,3)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/927ed450-4e91-435b-8db3-d4b24be99cc9/image.png" alt=""></p>
<p>딕셔너리 형태로 함수 내부의 로컬 변수들을 출력해 줌을 볼 수 있다.</p>
<p><strong>4. f-string</strong>
나는 출력을 할때 보통 format을 이용해서 출력을 진행했다.<del>(알 것이 수두룩 빽빽인데, 출력하는 방법만큼은 통일하자.. 라는 생각을 했다.)</del> 그러다가 f-string을 책에서 사용하길래, 가볍게 정리를 하고 넘어가고자 한다.</p>
<p>f-string 포매팅은 f와 {}을 이용해서 문자열을 포매팅 하는 것으로 다음과 같이 사용한다.
<code>f&#39;문자열 {변수} 문자열&#39;</code>
한번 사용해보겠다.</p>
<pre><code>for i in range(1,11):
    print(f&#39;{i}번쨰 출력값 {i*2}&#39;)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/1934321a-2ba3-4094-a590-4579de3599de/image.png" alt=""></p>
<p>????? 뭐야 훨씬 편하고 좋잖아?????
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/3d9fe0a5-a753-461d-86dc-4db09ca2e6d9/image.png" alt=""></p>
<p>앞으로 f-string format방식을 주로 사용해야겠다...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PEP & TypeHint]]></title>
            <link>https://velog.io/@leesungjoon-net/Python-%EC%A0%95%EB%A6%AC1</link>
            <guid>https://velog.io/@leesungjoon-net/Python-%EC%A0%95%EB%A6%AC1</guid>
            <pubDate>Tue, 27 Jun 2023 05:20:28 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>PEP란?
Python Enhancement Proposals 로 파이썬 개발 제안서이다. 
PEP는 새로운 기능을 제안하고 커뮤니티 의견을 수렴하여 파이썬의 디자인 결정을 문서화하는 파이썬의 주요 개발 프로세스를 일컫는다. 뒤에 번호를 부여하여 PEP 0 이런식으로 부여하는데, 그 중 특히 PEP 8은 파이썬의 코딩 스타일 가이드이다.
<br>
저자는 특히 코딩을 하는 방식에 관해서 얘기를 많이 했다. 나도 이르긴 하지만 현재 일을 하고 있는 친구에게 듣기로, 가독성이 협업에서 굉장히 중요하다고 했다. 이러한 코딩하는 스타일에 관한 내용이 바로 PEP 8에 담겨져 있고, 이 중 저자가 몇가지 강조한 점을 작성한 이후 추가로 알게된 내용이 있다면 그때그때 수정하겠다.</p>
</blockquote>
<ul>
<li>Python은 Camel 표기법이 아닌 Snake 표기법을 지향해야한다.</li>
<li>영어로 주석을 달아서 제출하는 편이 좀더 프로페셔널 하다는 인상을 줄 수 있다.</li>
<li>인덴트는 공백을 4칸으로 한다.</li>
<li>함수의 기본값으로 가변객체를 사용하지 않아야한다.(구글 파이썬 스타일 가이드)
대신 불변객체를 사용하여야 한다.</li>
<li>최대 줄길이는 80자로 한다(구글 파이썬 스타일 가이드)<br>
파이썬의 철학 : 문제를 풀어낼 바람직하고도 유일하며 명확한 방법이 존재할 것이다.

</li>
</ul>
<p>이제 책을 읽으면서 놓칠법한 파이썬 문법들을 정리해보겠다. 평소에 딥러닝 모델을 돌리거나 파이토치를 뜯어보면 나오는 것들인데, 이번기회에 명확하게 집고 넘어가고자 한다.</p>
<h1 id="타입-힌트">타입 힌트</h1>
<p>먼저 이 파트는 책과 <a href="https://sjquant.tistory.com/68">블로그</a> 왼쪽 블로그에서 깊게 참조했음을 알린다.</p>
<p>먼저 책에서는 타입힌트에 관한 얘기를 하는데, 우선 파이썬은 동적 타이핑 언어, 즉 내가 따로 자료형을 지정해주지 않아도 되고, 중간에 변수의 타입이 바꿔도 괜찮다. 이러한 특성때문에 다른 언어보다 배우기 쉽다는 장점이 있다. </p>
<p>만약 우리가 아래와 같이 작성을 했다고 해보자.</p>
<pre><code>def fn(a):
    ...</code></pre><p>우리는 이 함수가 문자를 넘겨야 하는지 숫자를 넘겨야 하는지 전혀 알 수 없고, 함수의 리턴값 또한 알 수 없다. 이러한 함수가 하나 두개면 어떻게 파악할 수 있다고 쳐도 여러개의 함수가 얽히고 섥히게 된다면 가독성을 떨어트리고 버그의 원인이 될 수 있다. 
위에 함수를 수정한다면 다음과 같이 수정할 수 있을 것이다.</p>
<pre><code>def fn(a:int) -&gt; bool:
    ...</code></pre><p>위와 같이 수정할 경우 함수에서 받는 <strong>파라미터 a가 정수형이고 리턴값이 bool형</strong>임을 확실하게 알 수 있다. 이렇게 명시적으로 선언하면 가독성이 좋아지고 버그 발생 확률을 줄일 수 있다.</p>
<blockquote>
<p>물론 type hint는 강제성이 없다. 따라서 여전히 동적으로 할당 될 수 있고 이는 주의가 필요하다.</p>
</blockquote>
<pre><code>a: str = 1
print(type(a))</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/42595a15-0cf2-4b7a-8cc9-b63f511bd1a7/image.png" alt=""></p>
<p>위와 같이 동적 타이핑 언어이기에 오류가 발생하지 않는데, 타입 힌트가 잘못 지정됐는지 확인하기 위해서는 mypy를 사용하여 알아차릴 수 있다. 아래는 위에 작성한 코드를 mypy를 이용해 타입 힌트를 검사한 결과이다.
<img src="https://velog.velcdn.com/images/leesungjoon-net/post/2b4acc14-0bd5-4bad-998b-73e78f336e4a/image.png" alt=""></p>
<p>&quot;코딩 테스트는 일반적으로 짧은 알고리즘으로 끝나는 경우가 많기 때문에 굳이 타입을 지정하지 않아도 문제는 없지만 코드를 정리할 때 만이라도 타입을 지정하여 보기좋게 제출한다면, 코드 리뷰시 면접관에게 좋은 점수를 받을 것이다.&quot;
-[파이썬 알고리즘 인터뷰 79page]-</p>
<p>파이썬의 built-in Type인 int, str만으로는 우리가 원하는 모든 타입을 명확하게 표현할 수 없다. 이때 파이썬은 typing 모듈을 제공하는데 typing 모듈에서 제공하는 몇가지 타입들이 있다.</p>
<p><strong>1. typing.Union</strong>
하나의 함수의 인자에 여러 타입이 사용될 수 있을때는 typing.Union을 사용하면 된다.</p>
<pre><code>from typing import Union


def print_msg(msg: Union[str, int]) -&gt; int:
    print(msg)
    return 1


print_msg(&#39;안녕 이건 오류가 아니야&#39;)
print_msg(1)
</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/9f6fef26-b967-492a-926d-5a0a7687fb43/image.png" alt=""></p>
<p><strong>2. typing.Optional</strong>
<code>Union[&lt;타입&gt;,None]은 Optional로 대체할 수 있다.</code>
이때, 타입을 두개 즉, <code>Optional[str,int]</code>로 사용하면 오류가 발생한다.</p>
<pre><code>from typing import Optional


def print_msg(msg: Optional[str]) -&gt; int:
    print(msg)
    return 1


print_msg(&#39;안녕 이건 오류가 아니야&#39;)
print_msg(None)
</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/9ff65ed3-ca8a-4f04-88d5-ebc92dd9778f/image.png" alt=""></p>
<blockquote>
<p>여기서 None의 Type은 NoneType이다.</p>
</blockquote>
<p>*<em>3. typing.List &amp; typing.Tuple &amp; typing.Dict *</em></p>
<p>리스트와 튜블 딕셔너리안에 타입(dtype)을 나타내는 방법은 아래와 같다.</p>
<pre><code>from typing import List, Tuple, Dict


names: List[str]
location: Tuple[int, int, int]
id_pw: Dict[str, int]
</code></pre><p>*<em>4. typing.TypedDict *</em></p>
<p>딕셔너리의 경우 밸류의 타입이 하나로 고정돼 있는 것만은 아니기 때문에, <code>TypedDict</code>를 활용해서 더욱 다양한 데이터 타입의 딕셔너리를 사용할 수 있다.
이때 <strong>유의할 점은 객체를 선언할때 TypedDict 클래스를 상속받아야 한다.
또한 객체를 생성할때 초기 value값을 입력해 주어야 한다.(이때, TypedDict클래스는 &quot;Right-hand side values are not supported in TypedDict&quot; 이기 때문에 Decoration을 사용한 것처럼 바로 초기화를 할 수 없다.)</strong></p>
<pre><code>from typing import TypedDict


class StudentInfo(TypedDict):
    id: int
    password: int
    address: str


def print_info(students: StudentInfo):
    student_id = students[&#39;id&#39;]
    print(student_id)


student = StudentInfo(id=201900278, password=1, address=&quot;경기도 광명&quot;) #객체의 파라미터로 초기화
print_info(student)
</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/40f14048-c0c6-49a5-be0d-64a9a4a2f9c2/image.png" alt=""></p>
<p>또다른 방법으로 <code>@dataclass</code> 데코레이션(Decoration)을 사용할 수 있다. 
이 데코레이션 문법을 타입 힌트와 함께 활용함으로써 class를 이용해서 구조체 형태로 선언할 수 있다.
(책 62page)</p>
<pre><code>
from dataclasses import dataclass


@dataclass
# StudentInfo = dataclass(StudentInfo)
# dataclass 가 StudentInfo를 상속받음
class StudentInfo:
    # 바로바로 초기화
    id: int = None
    password: int = None
    address: str = None


def print_info(students: StudentInfo):
    print(students.id)
    print(students.password)
    print(students.address)


student = StudentInfo()
student.id = 201900278
student.password = 1
student.address = &quot;경기도 광명&quot;

print_info(student)
</code></pre><p>나에게는 아래의 방식이 좀더 친숙하다.
다음에 Decoration관련해서 포스팅을 작성하겠다.
<a href="https://velog.io/@leesungjoon-net/%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0Decorator">Decorator 관련 포스팅</a></p>
<p><strong>5. typing.Callable</strong>
함수를 인자로 받는 경우에는 다음과 같이 Callable 타입을 활용하면 된다.
<code>Callable[[input type, ... ],return type]</code></p>
<pre><code>from typing import Callable


def first_function(func:Callable[[int, int], int]):
    summation = func(2,3)
    print(&quot;summation:&quot;, summation)


def second_function(a: int, b: int) -&gt; int:
    return a+b


first_function(second_function)</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/cb54621b-e3de-4f26-bda7-b44ba06946c9/image.png" alt="">
만약, 여기서 함수의 인자의 타입을 신경쓰지 않고 리턴타입만 명시하고 싶다면 <code>...</code>(Ellipsis)를 사용해서 다음과 같이 바꿀 수 있다.</p>
<pre><code>
from typing import Callable


def first_function(func:Callable[...,int]):
# 이때 여기서는 인자와 return type이 하나의 괄호안에 들어있다.
    summation = func(&#39;A&#39;,&#39;+&#39;)
    print(&quot;summation:&quot;, summation)
    return 1


def second_function(a: str, b: str) -&gt; str:
    return a+b


first_function(second_function)</code></pre><p><strong>6. typing.TypeVar</strong>
Generic이란 여러 타입을 일반화 한것을 의미한다. 이는 자바에서도 중요한 개념으로써 사용된다.
이 Generic Type을 나타내기 위해서 <code>typing.TypeVar</code>을 사용하여 Generic 타입을 나타낼 수 있다.</p>
<pre><code>from typing import Sequence, TypeVar, Iterable

T = TypeVar(&quot;T&quot;)  # T 대신 다른 문자/단어를 써도 되지만 일반적으로 T를 사용합니다.


def batch_iter(data: Sequence[T], size: int):
    for i in range(0, size):
        yield data[i:i + size]
# 이때, data의 크기를 벗어나도 끝까지 생성해준다

gen = batch_iter([&quot;abc&quot;,3,&quot;def&quot;], 3)

print(next(gen))
print(next(gen))
print(next(gen))


</code></pre><p><img src="https://velog.velcdn.com/images/leesungjoon-net/post/c96b46be-b51f-4043-877d-995e3dfd4a87/image.png" alt=""></p>
<blockquote>
<p><code>list, tuple, range</code>등과 같이 나열 가능한 자료형을 sequence type이라고 한다.</p>
</blockquote>
<blockquote>
<p><strong>Generic Class의 사용이유</strong>
일단, 먼저 언급할 것이 파이썬의 경우 동적 타이핑 언어이기 때문에 Generic이 필요하지 않다. 하지만, Generic Class가 무엇인지 왜 필요한지를 이해할 필요가 있다. Generic은 위에서 말했듯이 일반화한 Type을 나타낸다. 그렇다면 Generic Class는 무엇일까? Generic Class란 Class안에 변수 Type을 Generic으로 설정해서 어떤 Type이 입력으로 들어오더라도 유연하게 대처하고자 만든 Class이다. 자세한 내용은 다음 영상을 참고하길 바란다.
<a href="https://www.youtube.com/watch?v=pLaVaUknETU">Generic Clss란?</a></p>
</blockquote>
<p>그렇다면, 어떤 Class가 Generic Class임을 파이썬에서는 어떤식으로 표현할까?</p>
<p>*<em>7. typing.Generic *</em></p>
<p>다음 예시를 살펴보자</p>
<pre><code>from typing import TypeVar, Generic
from logging import Logger

T = TypeVar(&#39;T&#39;)

class LoggedVar(Generic[T]):
    def __init__(self, value: T, name: str, logger: Logger) -&gt; None:
        self.name = name
        self.logger = logger
        self.value = value

    def set(self, new: T) -&gt; None:
        self.log(&#39;Set &#39; + repr(self.value))
        self.value = new

    def get(self) -&gt; T:
        self.log(&#39;Get &#39; + repr(self.value))
        return self.value

    def log(self, message: str) -&gt; None:
        self.logger.info(&#39;%s: %s&#39;, self.name, message)</code></pre><p><a href="https://docs.python.org/3/library/typing.html#user-defined-generic-types">파이썬 공식 문서</a>
위의 <code>__init__</code> 메소드의 value:T에서 우리는T의 타입이 정해짐을 알 수있다. 이렇게 정해진 type T가 set함수와 get 함수에도 영향을 미친다.
또한 위의 클래스가 Generic Class임은 인자로써 받은 <code>Generic[T]</code>가 암시한다.</p>
]]></description>
        </item>
    </channel>
</rss>