Reference
https://iai.postech.ac.kr/teaching/machine-learning
https://iai.postech.ac.kr/teaching/deep-learning
위 링크의 강의 내용에 기반하여 중요하거나 이해가 어려웠던 부분들을 정리하여 작성하였고,
모든 강의 슬라이드의 인용은 저작권자의 허가를 받았습니다.
또한, 모든 내용은 아래 Notion에서 더 편하게 확인하실 수 있습니다.
>>노션 링크<<
Keywords
- Class Activation Map (CAM)
- Global Average Pooling
- Gradient-weighted CAM (Grad-CAM)
Class Activation Map (CAM)
Deep Learning은 앞에서 학습한 것처럼, 현존하는 다른 알고리즘보다 성능이 좋으며 feature learning을 수행할 수 있다는 장점이 있다.
그러나 output이 도출되는 데에 내부적으로 어떻게 작동하는 지 알기 쉽지 않다는 단점이 존재한다. (black box)
결과가 좋다면 왜 좋은지, 잘못되었다면 어떤 것 때문에 잘못되었는지 해석할 수 없음. → 잘못된 부분을 찾아 고치기 어려움. (little interpretability)
우리는(사람은) 이미지를 볼 때 이미지 전체를 보는 것이 아닌, 직관적으로 가장 중요한 부분에 집중해서 이미지를 관찰한다.
마찬가지로 CNN 또한 (weight이 optimize되었다면,) 가장 중요한 part의 weight이 가장 큰 값을 가질 것이다.
그러므로 학습된 CNN에서 weight를 관찰하면, CNN이 이미지의 어느 부분을 중요하게 여기는 지 알 수 있다.
이러한 아이디어를 이용하여 내부적인 동작을 조금이라도 간접적으로 파악하고자 하는 것이다.
DL → black box. little interpretable. not explainable.
이 문제를 조금이라도 해결해보고자 함. Explainable AI (XAI). 그의 일종 → CAM.
그래서, CAM이란, 위와 같이 CNN의 classification 결과를 이용하여,
각 class라고 판단하였을 때 어떤 weight이 가장 높은 값을 가졌는지를 위와 같이 원본 이미지에 시각적으로 나타내는 것이다.
(왼쪽 예시에서, 대부분 빨간색으로 표시한 부분에 의해 palace라고 classify되었다는 것을 뜻한다. 다른 class에 대한 CAM 이미지도 동일한 뜻.)
(관련 논문)
Global Average Pooling
여기서부터는, ‘그래서 CAM을 어떻게 구현하는가?’ 에 대해 설명할 것이다.
위는 CNN의 기본적인 구조이다.
여기에서 우리는 Convolutional Layer에서 feature extraction을 진행하고, Fully connected Layer에서 Classification을 진행한다고 이미 학습하였다.
그러나 이 Classification 과정에서, 꼭 Fully Connected Layer를 사용해야 하는 것은 아니다. 다른 방법을 사용해도 된다. CAM에서는 이 부분을 교체하게 될 것이다.
Fully Connected Layer를 사용하는 대신, Flatten 이전의 output들을 모두 모아, weight를 곱해 더하여, weighted sum을 만드는 것이다. (선형결합. 여기서의 weight 역시 trainable.)
Global Average Pooling에 들어오는 Input Image는, Convolution Layer를 거쳐 여러 개의 image(activation map)가 나올 것이다.
이 이미지들 중 classification을 수행하기에 중요한 이미지에 대한 weight는 높게 train이 될 것이고, 크게 중요하지 않은 이미지에 대한 weight는 낮게 train될 것이다.
그렇게 진행된 weighted sum이 모인 2d activation map에서, 모든 element를 summation하여 sigmoid를 적용, classify를 수행하는 것이 Global Average Pooling이다.
(글보단.. 위의 그림을 같이 본다면 어렵지 않게 이해할 수 있을 것.)
이렇게 만들어진 구조의 CNN이 잘 작동하도록 학습되었다면, Global Average Pooling에서 최종적으로 나온 하나의 Activation Map을 원본 이미지에 씌운다.
이것이 CAM이다. 어떤 부분이 classification에 중요한 부분인지 시각적으로 확인할 수 있는 이미지가 도출되는 것이다.
위의 그림을 잘 이해하는 것이 핵심이다!
여기에서는 위의 Global Average Pooling을 구현하고, 최적화하는 과정을 설명한다.
위에서 설명한 Global Average Pooling을 계산 과정 그대로 하나하나 구현하면 위와 같은 코드로 구현할 수 있다. (코드의 내용은 차근차근 읽어 보면 어렵지 않게 이해할 수 있을 것이다.)
이 때, sigmoid를 적용하기 전까지의 모든 연산은 Linear한 연산이므로, 합하거나 순서를 바꾸어도 결과는 변하지 않는다!
각 image에 대해 Weighted Sum을 계산하고 - 마지막 Activation Map에서 하나의 숫자로 모든 element를 더하는 것이나,
각 image에서 모든 element를 먼저 더하고 - 그 숫자들의 weighted sum을 계산하는 것이나, 선형적인 계산이기 때문에 같은 결과를 가진다는 것이다.
$\sum_k \omega_k^c \sum_{x,y} f_k(x,y) = \sum_{x,y} \sum_k \omega_k^c f_k(x,y)$ 라는 것이다.
이렇게 계산하면 코드가 훨씬 간단해진다.
Grad-CAM
위에서 학습하였던 기존의 CAM은, Fully-Connected Layer를 Global Average Pooling Layer로 대체해야만 한다.
또한, 마지막 Layer에서의 Acitvation Map (feature map)만 시각화할 수 있으며, 중간 Layer에 대한 시각화를 달성할 수 없다는 단점이 존재한다.
이를 해결하기 위해 고안된 것이, Gradient-weighted CAM이다.
각 feature map에 대한 gradient를 통해, activation map을 구성하겠다는 아이디어이다.
CAM과 같이, activation map을 구성하고 싶은 특정 class에 대한 output을 계산한다.
그리고 그러한 class의 output에 대해, feature map의 gradient를 계산한다.
아래의 식과 같이 $\frac{\partial z_c}{\partial f_k(x,y)}$ 처럼 각 feature map에 대해 편미분을 수행하여 gradient를 계산하는 것이다.
이후, 각 특징 맵에 대한 graident의 전역 평균(Global Average)를 계산한다. 이 값을 각 feature map에 곱한 것이 최종 grad-CAM이다.
이런 형식으로 CAM를 구성하면, 최종 feature map이 아닌 중간 layer의 feature map에 대한 actication map도 구할 수 있으며(저수준의 feature에 대한 activation map을 알 수 있게 된다.), Global Average Pooling Layer를 넣지 않아도 된다!