※ 본 내용은 stanford에서 제공하는 cs231n 강의, 강의자료를 바탕으로 작성하였습니다.

 

Lecture 15에서는 deep learning 모델의 inference, training이 효율적으로 이뤄질 수 있도록 하는 알고리즘, 하드웨어에 대해 다루고 있다. 

 

Agenda

총 위의 4가지 방법에 대해 다루고 있다.

 

※ 자세한 알고리즘보다는 대략적인 개념을 소개하고 있으므로 각각의 알고리즘에 대해서는 별로도 찾아보는 것이 좋을 것 같다.

<Algorithms for Efficient inference>

먼저 효율적인 inference를 위한 알고리즘들에 대해 다루고, 총 6개의 알고리즘을 다루고 있다.

 

- 1. Pruning

Pruning

 

Pruning은 '가지치기'라는 뜻 그대로 불필요한 연결이나 neuron을 제거하는 방법이다.

여기서 불필요하다는 것은 그 weight나 activation이 0에 가까워 의미가 없는 것들을 의미한다. 

 

당연히 더 많은 parameters를 가지치기할수록 모델의 accuracy는 떨어진다. 

그러나 그 정도는 생각보다 크지 않고, pruning한 모델을 다시 retrain하는 것으로 원래의 성능 정도로 복원할 수 있다.

노이즈에 의한 것이긴 하지만 본래의 모델보다 성능이 좋아지는 경우도 있다.

 

- 2. Weight Sharing

Weight sharing의 기본 아이디어는 quantization을 이용하는 것이다. 

예를 들어, 

2.09, 2.12, 1.92 -> 2.0

위와 같이 비슷한 수들을 하나의 수로 변경하는 것이다. 

 

Training 시에는 32 bit float으로 학습을 진행하고,

학습된 weights에 대해 clurstering을 수행해 묶어주는 것이다. 

 

이렇게 하면 훨씬 더 적은 bit수로 weights를 저장할 수 있다.

 

실험 결과 위 두 경우에는 4bits나 2bits까지 성능 저하가 크게 들어나지 않는 것을 확인할 수 있다. 

 

앞서 다룬 pruning과 함께 적용할 수도 있고, Huffman encoding을 이용하는 등의 방법으로 더욱 compact한 모델로 만들 수 있다.. 

VGG, ResNet 등의 모델에 대해서 각종 기법을 이용한 결과 수십배로 압축하면서 accuracy는 유지할 수 있었다고 한다. 

 

- 3. Quantization

Quantization은 앞서 다룬 weight sharing의 아이디어와 유사하다.

 

Weights의 통계를 이용하여 최소한의 bit수로 weights를 표현할 수 있도록 하는 방식이다.

 

- 4. Low Rank Approximation

하나의 convolution layer를 두 개의 layer로 나누는 방법이다. 이렇게 나누는 방법을 통해 model을 경량화할 수 있다. 

위의 경우를 예시로 들면, d 개의 k x k x c 개의 filters를 d'개의 k x k x c 개의 filters와 d개의 1 x 1 x c filters로 나누어 전체 weights를 감소시킬 수 있다.

 

- 5. Binary / Ternary Net

2개 또는 3개의 수로만 weights를 대체하는 방법이다.

학습된 weights를 시각화해보면 위와 같다. 

상당히 단순화 되었지만, 여전히 직관적으로 어떠한 역할을 수행하는 필터인지 판단이 가능한 필터들이 존재한다. 

실제로 거의 full precision 모델에 가까운 정도의 error rate를 달성한 결과를 보이기도 한다. 

 

- 6. Winograd Transformation

Convolution 연산을 matrix multiplication으로 치환하는 방법이다.

Transform 원리에 대해서는 강의에서 자세히 설명해주진 않지만, 데이터와 filter에 대해 transform을 거친 후 element-wise 곱만 수행해주면 그 결과가 convolution과 완전히 동일하게 된다고 한다. 

 

수행할 연산의 수를 줄일 수 있다. 

 

<Hardware for Efficient Inference>

하드웨어가 발전하거나, 연산에 최적화된 하드웨어를 설계함으로써 inference를 효율적으로 개선할 수 있다. 

Google TPU

Google에서 설계한 TPU이다. 

복잡한 구조를 다 살펴볼 수는 없지만 빨간색으로 표시된 영역의 units들을 통해 deep learning 연산을 최적화하고 있다. 대표적으로 Matrix Multiplication Unit을 통해 많은 수의 연산을 처리할 수 있다.

92T operations/second의 peak 성능을 보인다.

 

FLOPs/Byte의 비율이 충분히 크면 연산량은 FLOPS에 의해 결정되지만, FLOPS/Byte의 비율이 충분히 크지 못한 경우에는 memory bandwidth에 의해 성능이 좌우된다. 

 

그러나 사용되는 deep learning 모델들의 경우 대부분 memory access에 비해 사용되는 연산량이 적다. 

(memory bandwidth에 의해 성능이 제한되어 peak performance를 보이지 못한다.)

 

이를 해결하기 위해 불필요한 memory access와 불필요한 연산을 줄이기 위한 방법이 필요한데,

강의에서는 하드웨어를 이용한 솔루션 중 EIE(Efficient Inference Engine)를 소개하고 있다. 

 

핵심 아이디어는 0*A = A*0 = 0 임을 이용하여 불필요한 weight 저장과 연산을 줄이는 것이다.

크기 4의 벡터와 4x8 matrix의 곱을 나타내는 에시이다.

 

실제 회로상으로 어떻게 처리되는지는 자세히 설명하지 않지만, 

0인 값은 하나로 저장하고, 0과 곱해지는 연산은 스킵한다고 한다.

 

<Algorithms for Efficient Training>

Training 과정 또한 다양한 알고리즘을 통해 효율적으로 다룰 수 있다.

 

강의에서는 4가지 알고리즘을 소개하고 있다.

 

- 1. Paralleization

병렬처리를 통해 더욱 빠르게 training을 하는 방법이다.

Data Parallelism

서로 다른 환경에서 서로 다른 데이터에 대해 병렬적으로 forward 및 backward를 계산한 후, 하나의 server를 통해 parameter 업데이트를 수행하는 방법이다.

 

Model Parallelism

하나의 모델의 여러 부분을 서로 다른 환경에서 병렬 연산하여 더욱 빠르게 처리하는 방법이다.

 

추가로 hyper-parameter parallelism도 하나의 parallelism 기법이다.

Hyper parameter를 서로 다른 환경에서 다양하게 실험하면 최적 parameter를 더욱 빠르게 찾을 수 있다. 

 

- 2. Mixed Precision with FP16 and FP32

Weight 자체는 32-bit precision으로 저장하지만, training시에 이뤄지는 연산은 16-bit로 처리하여 효율성을 높이는 방법이다. 

실험 결과 성능차이가 거의 나타나지 않고, 오히려 노이즈에 의해 더욱 빠르게 수렴하는 경우도 있었다고 한다. 

 

- 3. Model Distillation

모델의 수렴이 훨씬 빠르게 이뤄지게 하는 방법이다. 

여러 개의 teacher model이 student model을 학습시키는 것으로 생각할 수 있는데, 

여기서 teaching의 의미는 score를 알려주는 것이다. 

Data의 label이 아니라 해당 score를 통해 학습하면 훨씬 빠르게 수렴한다고 한다.

앙상블의 결과를 바로 이용하는 것은 아니고, softened 결과를 이용한다.

Soften 정도는 T, temperatue라는 parameter를 이용한다.

 

- 4. DSD : Dense Sparse Dense Training

 

앞서 다룬 pruning을 적용한 모델을 먼저 학습하고, 어느 정도 학습이 이뤄지면 다시 re-dense를 수행한 후 학습을 계속하는 방법이다. 

이렇게 학습한 모델은 더 좋은 성능을 보인다고 한다. 

 

<Hardware for Efficient Training>

새롭게 발표된 Volta 구조에서는 딥러닝 연산에 최적화된 tensor core가 새로 추가되어, mixed precision operations를 훨씬 빠르게 처리할 수 있도록 도와준다고 한다.

 

 

 

 

 

 

 


※ 본 내용은 stanford에서 제공하는 cs231n 강의, 강의자료를 바탕으로 작성하였습니다.

 

Lecture 14에서는 reinforcement learning에 대해 다루고 있다. 

 

- Reinforcement learning

Reinforcement learning

강화학습에서 agent는 위와 같이 학습을 진행한다.

 

현재 state에서 어떠한 action을 취하면 환경이 그에 대한 reward를 제공하고, 다음 state로 넘어가는 과정을 반복한다.

 

위 과정을 반복하며 agent는 각 state에서 어떠한 action을 취하는 것이 가장 좋은지(cumulative reward의 기대값이 가장 큰) 학습하게 된다. 

 

MDP

강화학습으로 다뤄지는 문제들은 보통 MDP, Markov Decision Process로 다뤄진다.

MDP에서는 위와 같이 S, A, R, P, $\gamma$ 가 정의될 때, cumulative (discounted) reward를 최대화하는 정책을 찾는 것을 목표로 한다. 

 

$ \Sigma_{t >= 0} {\gamma^tr_t}$

 

단순히 현재 state만 고려해서 reward를 최대화하기 보다는, 현재 state에서 action을 취한 state에서의 reward까지 계속해서 고려해서 cumulative discounted reward를 계산한다. 

Optimal Policy

여기서 policy, 정책이란 state가 주어졌을 때, 어떠한 행동을 취할 것인지 결정하는 함수이다. ($ \pi$로 표현한다.)

 

Value function and Q-value function

Value function은 현재 state에서 cumulative reward의 기대값을 통해 현재의  state를 평가하는 function이고,

Q-value function은 현재 state s 에서 action a를 취했을 때의 cumulative reward의 기대값을 통해 (state, action) 쌍을 평가하는 function이다. 

 

Bellman equation

Optimal Q-value function을 Q'이라고 하고, 각각의 (state, action) pair가 달성할 수 있는 최대 cumulative reward의 기대값을 나타내는 함수라고 하자.

 

이때 Q*는 Bellman equation을 따른다. 

즉, 어떠한 (state, action) 이 주어졌을 때 그 때의 Q*은 ① (s, a)에 대한 reward와 ② 전이한 state' 에서의 Q*의 최댓값에 discount를 적용한 값의 합이 된다.  

 

Value iteration을 거치며 Q는 Q*에 점점 수렴해가지만, 단순 value iteration만으로는 문제가 있다. 

 

실제 (s, a)를 모두 계산해봐야된다는 것이다. 게임의 pixel, 도로의 영상과 같이 복잡한 경우 이러한 것은 infeasible하다.

따라서 Q-value function도 NN을 approximator로 계산하게 된다.

 

- Q-learning

Optimal Q-value function을 NN을 통해 근사화하는 것을 Q-learining이라고 한다.

 

Loss function은 위와 같이 정의되고, Bellman equation을 따르는 Q-function에 근사할수록 loss가 작아진다고 생각하면 된다. 

 

Q-network Architecture

Q-learning을 통해 atari game을 플레이하도록 학습하는 예시이다.

 

Input image가 state이고 network를 통해 Q(s, a1~aN)이 계산되고, Q-value가 가장 큰 action을 선택하게 된다. 

 

Experience Replay

학습을 진행하며 주어지는 state를 연속적으로 학습하는 것은 문제가 될 수 있다.

현재의 sample이 다음 sample을 결정하므로, 다양한 path를 경험하기 어려울 수 있다. 

 

따라서 experience replay라는 방법을 사용한다. 

Experience replay에서는 한번의 play 과정을 별도로 저장해두고, 그 중 random한 minibatch를 선택하여 학습을 진행한다. 

 

최종적인 학습에 대한 pseudo code는 다음과 같다.

Pseudo code for Q-learning with Experience Replay

주의할 점은 action을 선택할 때 확률적으로 선택한다는 것이다. 

그렇지 않으면 여러 시나리오를 경험해보지 않고, 한 번 했을 때 괜찮은 path를 계속해서 반복할 수도 있다. 

 

 

- Policy Gradients (REINFORCE algorithm)

앞서 Q-learning에서는 Q-value function을 approximate한 후, 누적 reward의 기대값이 가장 큰 action을 선택하는 방식을 택했다. 

 

반면 REINFORCE algorithm은 policy를 직접적으로 학습한다.

Policy 자체를 parameter화한 후, policy를 따랐을 때 누적 reward의 기대값을 최대화하는 방향으로 학습한다.

따라서 학습은 gradient ascent를 통해 이뤄진다.

 

앞서 정의한 기대값은 위와 같은 과정을 통해 미분을 할 수 있다. 

정리된 식은 몬테 카를로 샘플링 방식을 통해 계산할 수 잇다.

 

※ r(\tau) 는 전략을 따랐을 때의 reward를 의미한다.

 

 

앞선 식에서 $ p(\tau;\theta) $를 계산하려면 transition probability를 알아야하지만, 

위 슬라이드의 수식에서 확인할 수 있듯이 $ \nabla_{\theta}log{(p(\tau;\theta))}$의 계산에는 transition probability가 필요하지 않다. 

 

최종적으로 정리된 $ J(\theta)$ 수식의 직관적인 해석은 다음과 같다.

$ r(\tau)$가 크면 해당 path의 action들의 확률을 높이고, 낮으면 반대로 낮추는 방법이다.

 

그러나 해당 path에서 모든 action들이 좋았다는 것은 보장할 수 없다. ex) action1 = 100, action2 = -10 

 

따라서 단순히 reward가 양수였다는 것보다는 상대적으로 좋고 나쁨에 대한 의미있는 판단을 할 수 있도록 수식을 변경한다.

어떠한 기준, baseline에 비해 더 좋았는지를 판단할 수 있도록 변경하면 된다.

 

간단한 baseline으로는 reward의 이동평균이 될 수 있지만, 앞서 우리는 각 state마다 얼마나 reward를 얻을 수 있을지 근사한 함수를 다뤘었다.

 

바로 Q-function과 value function이다. 해당 함수를 base라인으로 이용하면, 어떠한 선택이 단순히 긍정적인 결과를 가져오는 것에 대해 판단하는 것 뿐만 아니라, 최적에 가까운 선택인지 판단할 수 있게 될 것이다. 

Q-function과 value function을 이용한 estimator는 위와 같다. 

Action을 취했을 때 얻은 reward가 현재 value라고 생각했던 값보다 크다면 해당 action에 대한 probabiltiy를 높여주는 것이라고 이해하면 된다.

 

Policy gradient만으로는 Q-function과 value function을 알 수 없기 때문에, Q-learning까지 함께 학습을 진행하게 된다.

 

이러한 알고리즘을 Actor-Critic algorithm이라고 한다.

Policy는 actor Q-function은 critic으로, actor가 행동하고 critic이 평가한다는 의미이다.

 

 

 

 

 

 

 

 

 

Pytorch로 ResNet을 구현한 내용에 대해 정리해보겠습니다. 

 

원 논문은 아래에서 확인하실 수 있고, 

https://arxiv.org/abs/1512.03385

 

Deep Residual Learning for Image Recognition

Deeper neural networks are more difficult to train. We present a residual learning framework to ease the training of networks that are substantially deeper than those used previously. We explicitly reformulate the layers as learning residual functions with

arxiv.org

(Review에서 사용된 이미지는 원 논문에서 추출한 이미지입니다.)

 

구현 코드는 아래에서 확인하실 수 있습니다.

https://github.com/LimYooyeol/AI-Paper-Code/tree/main/ResNet

 

GitHub - LimYooyeol/AI-Paper-Code

Contribute to LimYooyeol/AI-Paper-Code development by creating an account on GitHub.

github.com

 

<Review>

- Background

딥러닝 모델에서 층을 깊게 쌓으면 gradient vanishing/explosion과 같은 문제로 인해 학습이 잘 이뤄지지 않았었지만,   Batch Normalization 등의 새로운 기법이 등장하면서 gradien vaninshing/explosion 문제를 해결할 수 있었고, 층을 깊게 쌓더라도 학습이 이뤄지게 되었습니다.

 

Degradation

그러나 층을 깊게 쌓을수록 오히려 성능이 안좋아지는 'degradation' 문제가 발생하게 되었는데, 

단순히 parameters의 수가 많아져서 test 성능이 떨어지는 것이 아니라, training data에 대해서도 더 깊은 모델이 더 큰 error를 보이는 문제였습니다. 

 

따라서 본 논문에서는 degradation 문제를 해결하기 위해 'Residual Learning'이라는 새로운 방법을 소개합니다.

 

- Residual Learning

Residual learning은 다음과 같은 아이디어로 부터 시작되었습니다.

 

'(1) Shallower 구조를 갖는 모델'과 '(2) 해당 모델에 몇몇 layers를 더 추가한 모델'이 있을 때,

(2)번 모델이 (1)번 모델보다 최소한 같거나 더 좋은 성능을 보여야한다.

(추가된 layers가 identity mapping을 수행하면 되므로)

 

그러나 앞서 background에서 살펴봤듯이, 실제 학습은 그렇게 이뤄지지 않았습니다.

 

따라서 연구자들은 다음과 같은 생각을 하게 됩니다. 

'위 그림에서 H(x)가 해당 layer를 거친 후의 이상적인 출력이라고 가정했을 때,

현재의 모델은 x -> H(x) 로의 mapping을 찾는 것에 어려움을 겪고 있다. 

 

H(x) = F(x) + x 라고 할 때(F(x) : residual), 모델이 residual(F(x))을 학습하게 하는 것이 어떨까?'

 

위와 같은 방법에서 만약 identity mapping이 H(x)라고 가정하면,

model은 모든 weight를 0으로 학습하면 되므로 x -> F(x) 로의 mapping은 x -> H(x) 로의 mapping보다 상대적으로 간단할 것입니다.

(항상 identity mapping이 ideal하다는 것은 아니고 하나의 예시이긴 하지만, 실제로도 layer의 뒤로 갈수록 F(x)의 출력은 작아지는 양상을 보인다고 합니다.)

 

Residual Learning

그렇게 등장한 것이 residual learning입니다. 

 

위 그림에서 두 개의 weight layer를 하나의 block으로 취급하면, 해당 block에서는 residual, F(x)를 학습하게 됩니다. 

 

- Results

다양한 실험을 보여주지만 ImageNet data에 대해 총 4개의 모델을 비교한 결과를 살펴보겠습니다.

 

  • plain 18 layers vs plain 34 layers

      Residual learning을 사용하지 않으면, 층이 깊어질수록 성능이 떨어지는 degradation 문제를 확인할 수 있습니다.

 

  • ResNet 18 layers vs ResNet 34 layers

       Residual learning을 사용한 결과, degradation 문제가 해결되어 더 깊은 모델이 좋은 성능을 보이는 것을 확인할           수 있습니다.

 

  • plain vs ResNet

        18 layers의 경우 큰 성능 차이는 보이지 않지만 ResNet의 경우가 더 빨리 수렴했고, 34 layers의 경우 큰 성능 차          이를 확인할 수 있습니다. 

 

 

이처럼 residual learning은 매우 성공적인 결과를 불러왔고, 발표될 당시 ImageNet challenge 및 기타 대부분의 challenge에서 모두 1위를 차지하게 됩니다.

<Implementation>

Pytorch에서 제공하는 CIFAR 10 dataset을 사용하여 구현 및 실험을 진행하였습니다.

 

먼저 모델의 구조는 논문에서 연구자들이 CIFAR 10 dataset에 대해 적용한 구조를 그대로 따랐습니다.

 

① 기본적으로 VGG의 방식을 따라 filter는 모두 3x3크기를 사용합니다. 

 

② Feature map size를 32x32 -> 16x16 -> 8x8 으로 감소시키고, feature map size가 감소할 때마다 channel의 수는 2배로 증가시켜 16->32->64의 순서로 증가합니다.

 

③ 각 feature map size마다 2n 개의 convolution layers( = n개의 residual block)를 적용합니다.

(모든 convolution 연산의 뒤에는 BN layer가 추가되어있습니다.)

 

가장 처음의 3x3 convolution layer와 마지막의 Linear layer까지 최종적으로 총 6n+2개의 layer가 존재하게 됩니다.

 

논문에서는 다양한 n에 대해 실험 결과를 제시하지만, n = 5, 즉 layers가 32개인 경우에 대해서만 실험을 진행했습니다.

- Residual Block

먼저 2개의 convolution layers로 이뤄진 residual block의 구현입니다. 

# Basic residual block consists of pair of convolution layer
class Residual_Block(nn.Module) :
  def __init__(self, in_channel, out_channel, feature_reduce = False) :
    super().__init__()

    self.feature_reduce = feature_reduce

    if feature_reduce :
      stride = 2
    else : 
      stride = 1

    self.Conv = nn.Sequential(
        nn.Conv2d(in_channel, out_channel, kernel_size = 3, stride = stride, padding = 1, bias = False), 
        nn.BatchNorm2d(out_channel),
        nn.ReLU(),
        nn.Conv2d(out_channel, out_channel, kernel_size = 3, padding = 1, bias =  False),
        nn.BatchNorm2d(out_channel)
    )

    if feature_reduce :
      self.shortcut = nn.Sequential(
          # reduce feature map by pooling (No more parameters, option (A))
          nn.MaxPool2d(kernel_size = 2, stride = 2)
      )
    else :
      self.shortcut = nn.Identity()

  def forward(self, x) :
    x_prev = self.shortcut(x)
    
    if self.feature_reduce :
      # zero padding for dimension matching
      concat = torch.zeros_like(x_prev)
      x_prev = torch.concat((x_prev, concat), axis = 1)
    else :
      x_prev = x_prev

    F_x = self.Conv(x)

    return F.relu(F_x + x_prev)

Shortcut을 제외하면 Conv-BN-ReLU-Conv-BN-ReLU 순으로 구성된 간단한 구조이므로, shortcut에 대해서만 조금 더 살펴보겠습니다.

 

첫 번째 convolution layer만 짚고 넘어가면, feature map size를 줄이는 경우 stride = 2인 convolution을 통해 처리하기 때문에 feature map size를 줄일 때는 첫번째 layer의 stride가 2가 되도록 구현했습니다. 

 

다시 shortcut으로 돌아가면, CIFAR10 dataset에 대해서는 모두 option (A), identity mapping을 적용하는 논문의 내용을 따랐습니다. (그 외에는 convolution을 이용합니다. 논문 참고)

 

따라서 Feature map size가 바뀌는 block의 shortcut은 MaxPooling을 이용하여 feature map size를 줄인 후, 늘어난 channel은 zero로 채우는 zero padding을 이용합니다.

 

그 외의 경우는 그대로 전달되는 identity mapping을 이용합니다. 

 

ex) input : 32x32x16, output(2번째 conv) : 16x16x32 인 경우, input을 그대로 output에 더해줄 수 없습니다.

따라서 maxpooling을 통해 16x16x16으로 만들어주고, zero padding을 통해 16x16x32로 만들어주는 것입니다. 

 

- Feature Block

Feature map 크기가 동일한 구간(n개의 residual blcok으로 구성)을 하나의 feature block으로 구현했습니다.

# Block consists of n residual blocks
class Feature_Block(nn.Module) :
  def __init__(self, in_channel, out_channel, n, feature_reduce = False) :
    super().__init__()
    self.n = n

    residual_blocks = [Residual_Block(in_channel, out_channel, feature_reduce = feature_reduce)]

    for i in range(0, n-1) :
      residual_blocks.append(Residual_Block(out_channel, out_channel))
    
    self.residual_blocks = nn.ModuleList(residual_blocks)

  def forward(self, x) :
    for i in range(0, self.n) :
      x = self.residual_blocks[i](x)

    return x

ModuleList를 통해 앞서 구현한 Residual_Block을 n개 쌓아줍니다. 

 

- ResNet

최종 ResNet은 다음과 같습니다.

# ResNet
class ResNet(nn.Module) :
  def __init__(self, n) :
    super().__init__()

    self.init_layer = nn.Sequential(
        nn.Conv2d(3, 16, kernel_size = 3, padding = 1, bias = False),
        nn.BatchNorm2d(16),
        nn.ReLU()
    )

    self.Feature_Block1 = Feature_Block(16, 16, n)

    self.Feature_Block2 = Feature_Block(16, 32, n, feature_reduce = True)

    self.Feature_Block3 = Feature_Block(32, 64, n, feature_reduce = True)

    self.FC = nn.Sequential(
        nn.AvgPool2d(kernel_size = 2, stride = 2),
        Flatten(),
        nn.Linear(4*4*64, 10)
    )

  def forward(self, x) :
    x = self.init_layer(x)
    x = self.Feature_Block1(x)
    x = self.Feature_Block2(x)
    x = self.Feature_Block3(x)
    x = self.FC(x)

    return x

우선 3x3 Conv layer를 통해 channel을 16으로 만들어주고, 

 

이후에 feature map size : 32 -> 16 -> 8, channel : 16 -> 8 -> 4의 순서대로 앞서 만든 Feature_Block을 3개 쌓아줍니다.

 

마지막으로 average pooling을 거친 후 linear layer를 통해 최종 출력이 계산됩니다. 

 

- Result

앞서 구현한 ResNet과 residual learning, short cut을 제외하면 동일한 구조의 plain 모델을 하나 더 구현하여 두 model의 성능을 비교해봤습니다. 

(plain 모델 및 traing 등의 코드는 github 링크에서 확인하실 수 있습니다. )

 

Loss는 training data에 대해, accuracy는 test data에 대해 계산한 결과이며, 

두 model 모두 lr = 5e-3, momentum = 0.9, nesterov 방식으로, 같은 hyperparameters를 사용했습니다. 

 

실험1(상), 실험2(하) / without average pooling

Training을 3번이나 진행하게 되었는데, 그 중 위 2번은 끝에 average pooling을 추가하지 않고 진행한 결과입니다.

 

ResNet을 적용한 모델이 더 빠르게 수렴하는 것을 확인할 수 있습니다. 

 

실험 3

두 번이나 training을 돌리고 나서 논문에서는 끝에 average pooling이 추가되어 있다는 것을 확인해서 추가로 한 번 더 실험을 진행했습니다. 

 

15 epochs로는 plain model이 수렴하기에 부족한 것 같아서 이번엔 25 epoch로 실험을 진행한 결과입니다. 이미 training에 시간을 너무 많이 쓰기도 했고.. ResNet은 빨리 수렴하여 20 epochs만 진행했습니다.

 

마찬가지로 ResNet이 더 빠르게 수렴하고 더 좋은 성능을 보이는 것을 확인할 수 있습니다. 

 

 

 

 

 

 

 

 


※ 본 내용은 stanford에서 제공하는 cs231n 강의, 강의자료를 바탕으로 작성하였습니다.

 

Lecture 13에서는 unsupervise learning과 generative models(FVBN, Variational Autoencoder, GAN)에 대해 다룬다.

 

- Supervised vs Unsupervised Learning

Supervised vs Unsupervised Learning

Supervised learning과 Unsupervised learning의 가장 큰 차이는 label의 존재유무이다. 

 

Supervised learning에서는 label을 통해 모델이 data와 label간의 mapping을 학습했다면,

Unsupervised learning에서는 주어진 데이터 자체에 내재된 구조, 특성을 학습한다.

 

Unsupervised learning의 대표적인 예시는 clurstering, dimensionality reduction 그리고 density estimation 등이 있다. 

 

<Generative Models>

본 강의에서 다룰 Generative Models는 train data의 분포를 학습(density estimation)하여 새로운 sample을 생성하는 model이다. 

 

Generative Models에도 여러 종류가 있다.

크게 Explicit density estimation / Inplicit density estimation으로 나뉘는데, -

Explicit density estimation은 실제 분포를 학습하는 방법이고,

Implicit density estimation은 분포를 직접적으로 정의하지 않고 생성하는 방법이다.

 

본 강의에서는 빨간 사각형으로 표시된 모델들(Pixel RNN/CNN, Variational Autoencoder, GAN)에 대해서만 다룬다.

 

- FVBN, Fully Visible Belief Nets : Pixel RNN/CNN

FVBN

FVBN은 explicit density model로, image의 likelihood를 maximize하는 방법이다.

 

이때 $ \Pi{p(x_i | x_1, ..., x_{i-1})} $는 매우 복잡한 분포를 따른다.

따라서 해당 분포를 학습할 때 NN을 이용한다.

 

먼저 RNN을 이용한 방법이다. 

PixelRNN

좌측상단에서 pixel부터 image를 generate하고, 생성한 pixel들의 값을 input으로 이용하는 RNN(정확히는 LSTM, training 이미지로 분포를 학습)을 사용하여 계속하여 주변 pixel을 generate하는 방식이다.

 

순차적으로 전파되는 방식을 사용하기 때문에 느리다는 단점이 있다. 

 

PixelCNN에서는 convolution을 이용해 generate하는 방식으로 속도를 개선한다.

Pixel CNN

여전히 좌측상단에서부터 시작하여 생성된 값을 바탕으로 인접 pixel을 생성하긴 하지만, RNN 방식보다 빠르게 동작한다. 

 

PixelRNN/CNN의 장단점

Pixel RNN/CNN의 장단점은 위와 같다. 

 

느리다는 단점뿐만 아니라 이미지 생성 자체에서도 자연스럽고 의미가 명확한 이미지를 생성하지 않는다. 

 

- VAE, Variational Autoencoders

 

위 수식에서 확인할 수 있듯이 VAE에서는 Pixel RNN/CNN과는 다른 값을 maximize한다. 

여기서 z는 image에 대응되는 feature vector라고 이해하면 된다.

 

먼저 autoencoder에 대해서 살펴보자.

Autoencoder

Input date를 encoder를 통해 어떠한 features vector인 z로 표현한 후, decoder를 통해 reconstruction을 수행할 수 있도록 encoder와 decoder를 학습시키면(loss = $ \|x - \hat{x}\|^2$),  

encoder는 original data에 대한 features를 표현할 수 있는 모델이 될 것이다. 

(encoder를 거친 필터에 FC layers를 추가하는 방식으로 supervised learning에 이용할 수도 있다.)

 

 

VAE는 sample features로부터 분포를 학습하여, 이미지를 생성하는 방법이다. 

 

임의의 분포(일반적으로 Gaussian)를 따르는 z로부터 training data x가 생성되었다고 가정하고, $ p_{\theta*}(x | z^{(i)})$ 를 학습하는 방법이다. 

 

여기에서도 마찬가지로 $ p_{\theta}(x|z)$를 나타내기 복잡하므로 NN을 이용하여 이를 학습하고, 

학습시에는 $ p_{\theta}(x) = \int_{}^{} p_{\theta}(z)p_{\theta}(x|z)$를 maximize하는 방식을 이용한다. 

 

그러나 이때 $ p_{\theta}(x|z)$의 적분은 매우 어려울 것이다. 

따라서 maximize하고자 하는 수식을 조금 변경한다.

 

Lower bound of likelihood를 maximize하고자 수식을 변경하면, train이 가능하다.

 

먼저 encoder network를 추가한다. 

Encoder network에서는 $ q_{\Phi}(z | x)$를 학습하고, decoder에서는 다시 $ p_{\theta}(x|z)$를 학습한다. 

 

학습 시에는 위 식과 같은 log likelihood를 maximize하는 방향으로 학습한다. 

 

식의 형태를 조금 변경하면 위와 같이 나타낼 수 있다. 

 

각각 term의 의미는 위와 같다.

가장 우측의 항은 역시 intractable하지만, 정의에 의해 양수이므로 likelihood의 lower-bound를 maximize하는 것이 가능해지는 것이다.

 

Training 과정은 위와 같다.

 

실제 데이터를 생성할 때는 z를 N(0, 1)에서 sample한 후, Decoder network에 전달하면 된다. 

 

앞서 z가 어떠한 features를 나타내는 vector라고 했는데, 실제로 z값을 임의로 조정하면 생성된 이미지가 달라진다. 

위 예시에서는 웃는 정도, 얼굴의 각도 등이 달라지고 있다. 

 

장단점은 위와 같다.

 

여전히 feature representation을 통해 다른 task에도 의미를 갖는다.

그러나 GAN과 같은 SOTA 기술에 비해서 low quality를 출력한다.

 

- Generative Adversarial Networks (GAN)

GAN은 explicit density modeling을 포기하고, train distribution으로의 transform을 nueral network를 통해 나타내는 방법이다. 

 

Input으로 random noise가 주어지면 GAN을 거쳐 training distribution을 따르는 image가 생성된다. 

 

GAN은 two-player game의 방식으로 training이 이뤄진다. 두 개의 network가 존재하고, 각각 다음과 같다.

Generator network : Discriminator가 구분하지 못하도록 실제와 같은 이미지를 생성하는 network

Discriminator network : Real image와 fake image를 구분하는 network

 

Training은 위와 같이 이뤄진다.

 

Discriminator는 real image에 대한 probability output을 최대화하고, 

Generator는 generator가 생성한 이미지를 가짜이미지로 생각할 확률을 최소화하도록 objective function이 정의된다. 

 

(1). Gradient ascent를 통해 discriminator가 real을 구분할 확률을 키우도록 학습

(2). 다시 gradient ascent를 통해 generator의 출력을 discrminator가 '틀릴 확률'을 최대화

 

(1), (2)를 반복하며 training은 이뤄진다. ((2) 한 번당 (1)을 여러번 수행하기도 한다.)

 

(2) 과정이 discirminator가 가짜 이미지로 생각할 확률을 최소화하는 것에서, 진짜 이미지로 생각할 확률을 최대화하도록 변경했는데, 그 이유는 위 슬라이드 우측하단의 그래프를 통해 확인할 수 있다.

 

학습이 잘 이뤄지게 하기 위해서인데, 초록색으로 표현된 그래프가 바뀐 수식이고, 파란색으로 표현된 그래프가 이전의 방식이다. 

초록색으로 표현된 그래프에서는 현재 real image로 생각할 확률이 낮다면 gradient값이 크기때문에 빠르게 학습이 이뤄진다.

 

Traing과정을 pseudo code로 나타내면 위와 같다.

 

앞서 언급했듯이 discriminator를 k steps 학습한 후, generator를 1 step 학습할 수 있다.

보통 k > 1이고, 이 또한 hyperparameter이지만 이 값의 선택에 대한 고민을 줄이기 위한 연구들이 존재하므로 확인하면 좋다고 한다. 

 

실제 생성된 이미지들로, 자연스러운 이미지를 생성한다.

 

Generator나 discrimator를 CNN으로 구현할 수도 있다고 한다. 

CNN으로 구현하기 위한 가이드 라인은 위와 같이 소개하고 있다.  

 

CNN 기반 구조로 생성된 이미지로, 매우 정교한 이미지를 생성한다.

 

+ Recent posts