Computer Science/CS231n

[CS231n] Lecture 12

  • -
728x90
반응형

이번 단원에서는 CNN 내부에서 어떠한 일이 벌어지는 것인지 이해하기 위한 내용을 포함하고 있다.

현재 딥러닝이 가지고 있는 큰 문제점 중 하나는 내부에서 어떠한 일이 벌어지는지 명확하게 설명하기 힘들다는 점이다. 따라서 이러한 측면에서 중간에서 어떠한 일이 벌어지는지 규명하기 위한 노력 정도로 이 단원을 이해해주면 된다.

First Layer

Weight vector와 나란할 때 input값과의 inner product의 값이 최대가 된다. 즉, activation이 maximize하기 위해서는 input과 weight는 동일하다. 이를 통해 해당 filter가 어느 부분을 보고 있는지를 추정할 수 있다.

 

그림에서 볼 수 있는 것처럼 architecture의 종류와 data의 종류와 무관하게 first layer는 선분이나 다양한 색깔을 포함하고 있는 양상을 띄고 있다. 그러나 First layer의 경우 input값이 original image이므로 이러한 분석을 쉽게 할 수 있지만, 이후의 layer의 경우에는 이러한 분석을 취하는 것이 어려워진다는 문제점을 가지고 있다.

Last Layer

다른 방법으로는 Last layer에서 무슨 일이 일어나고 있는지 이해하는 것이다. image dataset을 CNN에 넣고, 각 이미지 별로 4096 dimensional vector를 기록해둔다.

Last Layer : Nearest Neighbors

앞에서 기록한 4096 dimensional vector 사이의 유사성을 기반으로 묶는다. 이전에 학습했던 Nearest neighbor의 경우는 pixel 사이의 유사성을 기반으로 판단했다면, 위 경우에는 CNN을 거쳐 나온 마지막 결과를 기준으로 분류하고 있으므로 feature 단위의 유사성을 판단하게 된다. 

Last Layer: Dimensionality Reduction

다른 방법으로는 앞에서 기록한 4096 dimensional vector를 2 dimensional vector로 차원 축소 처리하는 것이다.

차원 축소시킨 vector를 통해 각 들어온 이미지를 좌표에 대응시킨다. 결과를 visualization 시켜보면 cluster를 이루고 있는 것을 관찰할 수 있다. (t-SNE를 활용해주면 된다.)

Visualizing Activations

일반적으로 중간에 놓인 activation map을 분석해서 결과를 끌어내기는 힘드나, 위 사진에서 보이는 것처럼 유의미한 결과를 내는 경우도 존재한다. 위 사진은 사람의 얼굴이 위치한 곳이 크게 activation되는 결과를 확인할 수 있다.

 

Maximally Activating Patches

일단 128개의 Activation map 중 1개를 선택한다. 그리고 많은 이미지를 CNN에 통과시키고 해당 feature map에서 maximally activateed되는 곳을 관찰한다. 이를 바탕으로 해당 영역에서 처리하고 있는 feature를 추정할 수 있다.

 

추가적으로 CNN이므로 해당 영역은 input의 small receptable field일 것이고, 더 깊은 layer일수록 input image에 대응되는 이미지의 영역은 넓어지게 된다.

Occlusion Experiments

위 방법은 상당히 독특한데, input image의 일부를 가리고 이를 CNN에 주입힌다. 이를 바탕으로 어느 영역을 occlusion처리 했을 때 label을 잘 예측하지 못하게 되는지를 추정하게 된다. 즉, 해당 영역을 지웠을 때의 예측 확률이 가장 크게 떨어졌다면 해당 영역이 중요하다는 의미로 이해할 수 있다.

Saliency Maps

Saliency Maps는 Classification을 함에 있어서 어느 pixel이 중요한지를 알기 위해 고안된 방법이다.

기존의 CNN의 경우는 input값을 고정시키고 weight를 backporp의 결과 변화시켰다면, 이 방법론은 학습시킨 CNN의 weight를 고정시키고 input의 변화에 따른 loss의 변화를 체크하는 것이다. 잘 생각해보면 input pixel이 움직임에 따라 classification score이 움직이는 양상을 추적하는 것이므로, 이는 중요한 pixel을 판단하는 과정과 유사하게 바라볼 수 있다.

Saliency Maps를 적용하면 위의 그림처럼 해당 classificaion을 판단하기 위해 중요하게 작용한 pixel의 분포를 가시적으로 확인할 수 있다.

물론 이를 활용하여 Unsupervised인 Segmentation을 할 수 있으나, Supervised에 비해서는 결과가 좋지는 않다.

Intermediate Features via guided backprop

이 방식은 Saliency map과 유사하지만, classification이 아닌 중간에 있는 activation map에서 판단하는 feature를 결정하는데 중요한 pixel 영역을 판단하는 것이다. (즉, 바라보는 지점이 조금 상이하다.)

방법 자체는 Saliency maps때 했던 것과 유사하게, input에 대해서 gradient descent 작업을 수행해주면 된다. 추가적으로 backprop을 수행할 때 positive gradient만을 Relu에 통과시키면 조금 더 깔끔한 이미지를 얻을 수 있다.

왼쪽은 위의 방법을 활용해서 얻은 결과이고, 오른쪽은 앞서 살펴보았던 Maximally activated patches를 활용한 결과이다.

위 결과에서 볼 수 있는 것처럼 이 방법을 사용하게 되면, 정확히 어느 부분을 activation map에서 바라보고 있는지 추정할 수 있게 된다.

Gradient Ascent

앞에서 살펴본 Saliency maps나 Intermediate features via guided backprop의 경우는 주어진 이미지에 대해서 어느 pixel을 확인하는지를 visualization시킨 것이라면, Gradient Ascent의 경우는 입력 이미지에 의존하지 않고 해당 뉴런을 활성화시키는 일반적인 image를 구하는 방법이다.

 

수식에서 볼 수 있는 것처럼, 주어진 input image(I)에 대해서 해당 뉴런을 통과한 값인 f(I)가 크면서 Regularizer에 대한 값도 고려한 값이 모두 최대가 되게끔하는 일반적인 image를 찾는 것이 목표이다.

방법 자체는 뭐 간단하다. 시작 input value를 zero image로 설정하고, input image의 변동에 따른 gradient를 구하고 이를 backprop시켜서 최적의 image를 구하게 된다. 위 식에서는 Regularizer를 L2 norm를 활용했는데, 뉴런을 통과한 값이 크면서 L2 norm이 작은 이미지를 구하게 된다고 이해할 수 있다. (Regularizer를 넣어야 규제를 가하게 되므로 보다 더 일반적인 그림을 구할 수 있게 된다.)

위 작업을 수행한 결과를 보면 natural하지는 않으므로, 아주 좋은 Regularizer는 아니다.

 

다음과 같은 3개의 작업을 더 수행하게 되면, 조금 더 나은 이미지를 얻을 수 있게 된다.

1) Gaussian blur image (이를 통해 spatial smoothness를 휙득한다.)

2) Clip pixels with small values to 0

3) Clip pixels with small gradients to 0

(2,3번은 계속 진행됨에 따라 nicer set/property에 projecting 시키는 느낌으로 이해하면 된다.)

딱 봐도 기존에 처리했던 것보다 조금 더 이미지가 깔끔하게 잘 나오는 것을 확인할 수 있다.

물론 중간 layer에 대해서도 동밀한 작업이 가능하다. 속한 label이 나올 score를 maximize하는 방향이 아니라, 중간 layer에 있는 neuron이 최대가 되게끔하는 image를 추정하게 된다.

추가적으로 multi modality도 고려해주면 성능이 조금 더 좋아질 수 있다. 한 class 내부에서 clustering을 진행하면 각 class 내에서 서로 다른 mode끼리 다시 class가 나뉜다. 위 사진을 보면 모두 grocery store 사진이지만, 띄고 있는 양상이 모두 다르는 것을 추측할 수 있다. 초기화 할 때 이러한 mode 중 1개와 가깝게 초기화시켜주면 결과가 조금 더 좋게 나오게 된다.

사진에서 볼 수 있는 것처럼, 확실히 이전에 비해서 성능이 올라간 것을 확인할 수 있다. 위 이미지는 target category에서의 score이 높고, realistic하게 만들어진 이미지라 조금 더 사실적으로 보이는 장점은 존재하지만, 극심한 regularizer를 가할수록 진짜로 해당 neruon이 보고 있는 것과 멀어진다는 단점이 존재한다.

Fooling Images

위에서 학습한 Gradient ascent를 활용해서 재밌는 예시를 만들 수 있는데, 대표적인 것이 Fooling Image이다.

이 작업은 zero based input으로 시작하는 것이 아니라 특정한 image에서 시작하되, gradient ascent를 통해 특정 class에 대해 maximize되게끔 이미지를 수정하는 것이다.

 

즉 위 사진에서 볼 수 있는 것처럼 인간의 눈에는 둘 다 elephant로 보이지만, 한쪽은 elephant 다른 한쪽은 koala로 학습하는 결과를 가져오게 된다.

DeepDream

이 방식은 특정 뉴런이 최대로 활성화되는 image를 합성하는 것이 아닌, 네트워크에서 검출된 해당 이미지의 특성을 증폭시키게 된다.

왜냐하면 layer에 있는 어떠한 특성이든 gradient를 해당 값과 같게 설정함으로써 해당 특성을 강화시키기 때문이다. 추가적으로 gradient가 해당 layer의 output값과 동일하므로 결과적으로 L2 norm의 값은 최대화시키게 된다.

 

사실 이를 수식적으로 옮기면 다음과 동치이다.

$$I^* = \text{argma}x_I \sum\limits_i f_i(I)^2$$

추가적으로 3가지 트릭을 활용해준다.

Jitter image(이미지를 살짝 움직임)의 경우는 일종의 Regularization의 역할을 수행하게 된다. 이를 통해 extra smoothness를 휙득하게 된다. 또한 L1 normalize를 시키고, 값이 0 ~ 255 사이여야하므로 pixel value를 clip처리해준다.

결과를 보면 개들이 참 많은데, 실제로 ImageNet 데이터의 20% 정도가 개라는 것을 감안했을 때 이상한 결과는 아니다.

Feature Inversion

Gradient Ascent와 비슷해보이지만, scoresk 중간 layer의 neruon이 최대로 출력되게끔하는 image를 찾는 것이 아니다.

위 방식의 경우, 이미지를 Network에 통과시키고 그 결과 나오는 Activation map을 저장해둔다. 저장해둔 Activation map을 바탕으로 이미지를 재구성하는 것이다.

$$\ell (\Phi (x), \Phi _0 ) = \begin{Vmatrix} \Phi (x), \Phi _0 \end{Vmatrix}^2 $$ 식을 보면 알겠지만, score나 중간 neuron을 최대로 활성화시키는 것이 목표가 아니라 특징 벡터간 거리를 최소화시키는 것이 목표이다. (참고로 $\Phi _0$가 저장한 Activation map이다.)즉, Activation map과의 차이가 작게끔하는 이미지를 찾고 이를 통해 해당 layer가 어느 부분을 바라보고 있는지를 추측하는 것이다. Regression의 경우는 인접 픽셀 사이의 차이에 대한 패널티를 부여하는 것이다. 이를 통해 spatial smoothness를 휙득하게 된다.

위 사진에서 볼 수 있는 것처럼, 층이 깊어지면 깊어질수록 low level의 detail은 점차적으로 흐려지게 된다.

Texture Synthesis

주어진 input값과 동일한 texture를 가지는 큰 이미지를 만드는 것이 목표이다. 

Nearest Neighbor

가장 쉽게 접근할 수 있는 방법이다. 주변에 있는 pixel에 대한 정보를 통해 이미지를 생성하는 방법이다.

하지만 이 방법은 original input image가 복잡한 구조를 가질 경우에는 잘 작동하지 않는다.

Gram Matrix

이 방법은 원하는 input image를 CNN에 집어 넣고, 특정 layer에 있는 2개의 feature column을 끄집어내서 외적연산을 취해 Gram Matrix를 얻는다. 이 과정을 수행함으로써 이미지 내 서로 다른 두 지점에 있는 특징들 간의 co-occurrence를 알 수 있게 된다. 해당 matrix에서 값이 크다는 것의 의미는 입력 vector의 i, j 요소가 모두 크다는 것을 의미하게 된다.

 

공분산 행렬을 이용하는 것보다 계산적으로 이득을 많이 볼 수 있게 된다.

전체적인 과정은 다음과 같다.

1. 원하는 input image의 gram maxtirx를 다양한 레이어에서 구한다.

2. 생성할 이미지를 random하게 초기화시킨다.

3. 두 gram matrix 사이의 L2 norm의 weighted sum을 loss로 설정한다.

4. 이를 바탕으로 생성된 이미지의 pixel의 변화에 따른 gradient를 구한다.

5. gradient descent를 통해 생성된 이미지의 pixel를 업데이트한다.

Neural Style Transfer

위에서 확인한 Gram matrix를 활용한 방법에서 Starry night 같은 그림을 input image로 주어진 상황을 의미한다.

이 경우 원본 이미지가 style image화 된 그림이 출력값으로 나오게 된다.

이때, Content Image는 기본적인 iamge의 모양이 어떤 것일지 Style Image는 어떠한 texture가 어떤 것일지 결정하는 이미지이다.

최종 이미지는 content imaged의 feature reconstruction loss가 작고, style image의 gram matrix loss가 작아지는 방향으로 그려지게 된다. 이 방법의 문제는 backprop / forward 작업을 많이 해야한다는 점인데 style transfer를 위한 네트워크를 따로 학습시킴으로써 이러한 문제를 해결하였다.

Fast style Transfer

 

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.