본문 바로가기
ML & DL/tensorflow

Saliency Map

by 별준 2021. 1. 18.

(tensorflow v2.4.0)

2021/01/18 - [ML & DL/tensorflow] - Class Activation Map(CAM)

 

Class Activation Map(CAM)

(tensorflow v2.4.0) 오래전부터 CNN Model을 해석하기 위한 방법을 찾아왔습니다. 이전에는 주로 filter들을 시각화하거나 filter가 최대로 활성화하는 입력을 찾는 등의 filter 단위의 해석이 많았고, 실제

junstar92.tistory.com

 

CAM에서는 CNN 구조의 탑에 Global Average Pooling(GAP) layer를 두고, Dense layer를 쌓아서 Dense layer의 가중치와 마지막 Conv layer의 feature map을 통해서 모델이 이미지의 어떤 부분을 중점적으로 살펴보고 클래스를 분류하는지 알아보았습니다.

 

이번에 알아볼 Saliency Map도 마찬가지로 이미지에서 어떤 부분에 집중하는지 살펴보는 방법인데, 이 방법은 다른 영역에 비해서 픽셀값의 변화가 급격한 부분을 모아서 매핑한 후에 관심있는 물체를 관심이 없는 배경과 분리시키는 방법이라고 할 수 있습니다.

즉, 모델이 분류하는데 있어서 중요하게 생각하는 부분의 픽셀을 강조하여 보여줄 수 있습니다.

 

Saliency Map은 픽셀값의 변화가 급격한 부분을 모아서 매핑하는데, Gradient Descent를 사용하여서 변화가 큰 부분을 찾아냅니다.

 

이전 글에서 구현한 VGG16 모델과 cats vs dogs dataset을 그대로 사용하여, Saliency Map을 구현하고 어떻게 이미지를 강조하는지 살펴보겠습니다.

모델과 dataset load는 이전글을 참조해주시기 바랍니다. 학습이 완료된 이후부터 시작하면 됩니다 !

 

우선 살펴볼 이미지를 랜덤하게 추출하고, 실제 label 값을 one-hot vector로 나타냅니다.

image, label = iter(test_batches.shuffle(1024)).__next__()
print(label)

class_index = label
num_classes = 2

expected_output = tf.one_hot([class_index] * image.shape[0], num_classes)

 

그리고, model을 통해서 예측값을 얻고, loss를 구한 후에 Gradient Descent를 통해서 입력에 대한 미분값을 구합니다.

이때, Gradient Descent는 한 번만 진행하면 되므로, tf.GradientTape()를 통해서 역전파를 진행하여 미분값을 구합니다.

with tf.GradientTape() as tape:
    inputs = tf.cast(image, tf.float32)
    tape.watch(inputs)
    predictions = model(inputs)
    
    loss = tf.keras.losses.categorical_crossentropy(expected_output[0], predictions)

gradients = tape.gradient(loss, inputs)

gradients 결과값은 입력 이미지와 동일하게 (224, 224, 3)의 모양을 갖습니다. 어떤 픽셀을 집중해서 살펴보는지 시각적으로 더 잘 나타내기 위해서 gradients 결과를 gray scale로 변경해주는 작업을 먼저 진행하겠습니다.

gray scale로 변경하는 작업은 먼저 각 픽셀의 채널별 값을 절대값을 취해서 더해준 후에 픽셀값이 0~1의 값을 가질 수 있도록 최대값과 최소값으로 normalization을 수행합니다. 그리고, 마지막으로 (224, 224)의 모양을 갖도록 처리해줍니다.

# reduce the RGB image to grayscale
grayscale_tensor = tf.reduce_sum(tf.abs(gradients), axis=-1)

# normalize the pixel values to be in the range [0, 255].
# the max value in the grayscale tensor will be pushed to 255.
# the min value will be pushed to 0.
normalized_tensor = tf.cast(
    255
    * (grayscale_tensor - tf.reduce_min(grayscale_tensor))
    / (tf.reduce_max(grayscale_tensor) - tf.reduce_min(grayscale_tensor)),
    tf.uint8,
)

# remove the channel dimension to make the tensor a 2d tensor
normalized_tensor = tf.squeeze(normalized_tensor)
print(normalized_tensor.shape)

normalized_tensor가 어떤 픽셀들에게 집중하는지 먼저 살펴보고, 원본 이미지와 겹쳐서 살펴보겠습니다.

plt.figure(figsize=(8, 8))
plt.axis('off')
plt.imshow(normalized_tensor, cmap='gray')
plt.show()

중앙 부근에서 픽셀들의 값이 크다는 것을 보여주고 있습니다.

이제 원본 이미지와 합쳐서 어느 픽셀을 강조하는지 살펴보겠습니다.

고양이의 전체적인 부분을 골고루 강조하고 있으며, 눈과 머리쪽 그리고 엉덩이쪽을 더 많이 강조하고 있습니다.

 

또 다른 이미지를 살펴보면 다음과 같은 결과도 얻을 수 있습니다.

위 이미지에서는 강아지의 얼굴을 집중적으로 강조하고 있습니다.

'ML & DL > tensorflow' 카테고리의 다른 글

Class Activation Map(CAM)  (6) 2021.01.18
[tensorflow] UNet (Oxford-IIIT Pet segmentation)  (3) 2021.01.17
[tensorflow] Fully Convolutional Networks(FCNs)  (7) 2021.01.16
Breast Cancer Prediction  (0) 2021.01.13
[tensorflow] GradientTape  (0) 2021.01.12

댓글