※ 본 내용은 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 기반 구조로 생성된 이미지로, 매우 정교한 이미지를 생성한다.

 


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

 

Lecture 12에서는 CNN 동작을 이해하기 위한 visualizing을 다루고 있다.

 

 

- Visualizaing Filters

Visualize filters in first layer

먼저 train된 모델들을 불러와 첫번째 layer의 필터를 시각화한 결과이다. 

Edge나 line등 비교적 직관적인 feature를 detection하고 있는 것을 확인할 수 있다. 

 

이전 강의에서도 다뤘듯 깊은 layer일수록 복잡한 특징에 response하고, 따라서 이후의 layers는 시각화하더라도 interpretable하지 않은 결과를 제공한다.

 

그러나 각각의 layers, weight가 어떻게 동작하고 있는지는 시각화할 수 있다.

 

먼저 AlexNet의 가장 마지막 FC layer가 어떻게 동작하는지 살펴보자.

앞선 강의에서 pixel값을 바탕으로 KNN을 classification에 이용하는 것은 비효율적일 뿐만 아니라, 정확하지 않은 것을 확인할 수 있었다. 

 

그러나 마지막 FC layer의 출력값(4096-dim vector)을 기준으로 KNN을 수행하면 꽤 정확한 결과를 보인다. 

(각 이미지마다 마지막의 layer의 출력값을 저장해두고, 해당 값을 기준으로 classification을 수행하는 방법)

 

위 이미지는 Mnist datasets에 대한 layer FC layer의 출력결과에 t-SNE라는 dimensinality reduction 기법을 적용한 결과이다.

10개의 군집으로 구분되는 것을 확인할 수 있다. 

 

- Visualizing Activations

Activations를 시각화하여 각 filter가 어떠한 역할을 수행하는지 짐작해볼 수 있다.

 

위 이미지는 conv5의 activation을 시각화한 결과로, 128개 chnnel에 대해 각각 13x13 grayscale 이미지로 출력한 결과이다. 

대부분 해석하기 어려운 결과를 보이지만, 초록 사각형으로 표시된 부분은 사람의 얼굴 부분에 대해 높은 activations를 보인다. 

해당 filter는 사람의 얼굴을 감지하는 등의 역할을 수행하는 것으로 예상할 수 있다. 

 

 

반대로 여러 이미지를 model에 input으로 주고, 임의의 filter에 대한 activations를 기록한 후 그 값이 컸던 이미지를 살펴보는 방법으로 그 filter의 동작을 예상해보는 방법도 있다.

 

임의의 filter에 대한 activation이 컸던 이미지들을 정리해둔 결과이다.

 

첫 행의 filter는 원을 감지하는 등의 기능을 수행할 것이고, 4번째 행의 filter는 글자를 감지하는 등의 기능을 수행할 것이라는 것을 예상해볼 수 있다.

 

나아가서, 모델이 이미지의 어떠한 영역을 보고 결정을 내렸는지 파악하는 것도 가능하다. 

 

오른쪽의 결과는 이미지의 일부 영역을 masking한 후, 해당 영역을 가렸을 때 classification probabiliy가 어떻게 변화하는지 출력한 결과이다. 

 

실제 해당 객체가 있는 영역일수록 probabilty가 낮아지는 것을 보며, 모델이 실제 객체를 인식하고 classification을 수행한 것임을 알 수 있다. 

 

Saliency Maps

같은 원리로 image pixel에 대한 score의 미분값을 계산해보아도, 어떠한 pixel이 classification에 큰 영향을 미쳤는지 알 수 있다.

실제 개가 있는 영역이 잘 감지된 것을 확인할 수 있다.

 

이러한 방법을 segmentation에 응용하기도 한다.

 

이미지가 아니라 특정 filter의 activation값을 기준으로 미분을 수행하여 해당 filter의 출력엔 이미지의 어느 부분이 영향을 끼쳤는지 파악하는 것도 가능하다. 

 

앞서 임의의 filter에 대한 activation이 큰 값을 보였던 이미지를 정리해두었던 자료에 대해, 그 filter의 actavtion에 대해 미분을 수행한 결과는 위와 같다.

예상한 것과 같이 첫번째 필터는 동그라미, 4번째 필터는 글자의 형태에 크게 영향을 받는다. 

 

- Gradient Ascent

Train 시 optimization을 수행하기 위해서는 gradient descent 알고리즘을 통해 loss를 최소화하는 방향으로 weight를 학습시켰다면,

gradient ascent를 이용하여 어떠한 filter의 activation score를 최대화하는 방향으로 image를 학습시키는 것도 가능하다.

 

특정 class에 대한 score를 최대화하는 방향으로 임의의 noize로 제공된 이미지가 gradient descent를 통해 변경하면, 위와 같이 해당 calss의 형태가 보이게 된다. 

뒤의 regularization term은 특정 pixel의 값을 통해 score가 커지게 하는 것을 방지하여 이미지가 실제 이미지와 유사하게 되도록 조정하는 역할을 한다. 

 

결과이미지에 값이 낮은 pixel은 0으로 처리하는 등의 추가적인 작업을 수행하여 조금 더 사실적으로 만드는 것도 가능하다.

 

- Fooling Images / Adversarial Examples

Gradient ascent를 이용하여 어떠한 이미지가 다른 class에 대한 score가 커지도록 작업하는 것도 가능하다.

코끼리 이미지를 koala class에 대한 score가 크도록, schooner이미지를 iPod class에 대한 score가 커지도록 조정한 결과이다. 

실제 이미지와 크게 다르지 않지만, 모델은 잘못인식하게 된다. 

이에 대해서는 추가적인 하나의 강의를 통해 다룬다고 한다. (Lecture 16)

 

- DeepDream 

실용적이기 보다는 실험적이고 재미를 위한 실험이다.

특정 뉴런보다는 어떠한 layer에서의 activations를 최대화하도록 gradeient ascent를 적용하면 해당 layer에서 response하던 features가 이미지에 나타나게 된다는 원리이다. 

 

어떠한 layer를 선택하느냐에 따라 위와 같은 결과들이 생성된다. 

 

- Feature Inversion / Texture Synthesis

Feature Inversion

Feature Inversion을 통해 이미지에서 특정 feature에 match하는 부분들을 강조할 수 있다.

 

어떠한 이미지에 대한 한 layer에서의 feature vector와 원본 이미지가 주어지면, 새로운 이미지와 해당 feature vector의 l2 distance를 최소화하면서 이미지가 자연스럽게 보이도록 학습시키는 방법이다. 

 

결과는 위와 같다.

 

깊은 층의 feature에 대해 적용할 수록 원본이미지와 달라지는 것을 확인할 수 있다.

이는 앞 layer에서는 raw pixel 에서 정보를 많이 보존되지만, 깊어질수록 색이나 질감같은 deatail보다는 semantic한 정보를 이용한다는 것을 의미한다. 

 

Texture Synthesis

Texture 정보가 담긴 patch가 주어졌을 때, texture를 유지하는 더 큰 이미지를 생성하는 task가 Texture Synthesis이다. 

 

위 output은 KNN을 이용한 결과로, KNN을 통해서도 어느정도 구현이 가능하지만 복잡한 패턴일수록 한계가 존재했다.

 

해당 task에 대해서도 딥러닝을 통해 한계를 극복할 수 있었다. 

 

각 layer마다 CxHxW tensor를 출력할 것이고, 이때 각 위치별로 C 차원 벡터 2개에 대한 outer product를 계산하여 CxC 크기의 matrix를 생성할 수 있다.

(co-occurence 정보를 계산하는 것, co-variance matrix를 사용하지 않은 이유는 outer product의 계산상 이점 때문)

 

그러한 matrix의 모든 위치 조합에 대한 결과를 평균낸 결과가 Gram Matrix이다.

 

Neural Texture Systhesis

위와 같은 총 9계의 단계를 통해 딥러닝을 통한 texture sysnthesis가 가능하다.

조금 더 단계를 통합하면 다음과 같이 그 동작을 정리할 수 있다.

 

(1) 주어진 image patch에 대해 모든 layer에서 Gram Matrix를 계산

(2) Random noise 이미지에 대해 Gram Matrix를 계산하고 기존 image patch의 gram matrix와 비교

(3) 그 차이를 loss로 계산하여 optimization 수행

 

위와 같이 꽤 괜찮은 결과를 보인다. 

(Layer가 나눠진 이유는 비교를 위해 각 layer별 Gram Matrix의 차이를 loss로 실험을 진행했기 때문, 실제로는 모든 layer의 Gram Matrix 차이의 합을 loss로 사용)

 

Style Transfer

Content image에 대한 feature reconstruction(feature inversion)과 texture synthesis를 결합하여 content image를 해당 texture style로 변환하는 것도 가능하다. 

 

위 그림에 나와있듯이 feature reconstruction을 위한 loss와 texture synthesis에 대한 loss를 모두 계산하는 방법으로 구현이 가능하다.

 

그러나 위 방법은 각 image 마다 수많은 forward/backward 연산을 반복해야 되기 때문에 실용적이지 않다.

Fast Style Transfer 

따라서 'Fast Style Transfer'에서는 각 style 별로 새로운 feedforward Network를 학습시켜, 해당 feedforward network만 거치면 학습된 style로 transfer가 가능하도록 한다.

+ Recent posts