2 분 소요

🔮 가중치 시각화

가중치는 입력 이미지의 2차원 영역에 적용되어 어떤 특징을 크게 두드러지게 표현하는 역할을 한다.

📍 가중치를 시각화하기

📌 훈련한 모델의 가중치 표현

from tensorflow import keras
# 코랩에서 실행하는 경우에는 다음 명령을 실행하여 best-cnn-model.h5 파일을 다운로드받아 사용하세요.
!wget https://github.com/rickiepark/hg-mldl/raw/master/best-cnn-model.h5
model = keras.models.load_model('best-cnn-model.h5')

model.layers

>>>
[<keras.layers.convolutional.Conv2D at 0x7ff6ae771150>,
 <keras.layers.pooling.MaxPooling2D at 0x7ff6ae771d90>,
 <keras.layers.convolutional.Conv2D at 0x7ff6ae771590>,
 <keras.layers.pooling.MaxPooling2D at 0x7ff6ae698910>,
 <keras.layers.core.flatten.Flatten at 0x7ff6ae69e190>,
 <keras.layers.core.dense.Dense at 0x7ff6ae6984d0>,
 <keras.layers.core.dropout.Dropout at 0x7ff6ae6a2450>,
 <keras.layers.core.dense.Dense at 0x7ff6ae69e210>]

8-2장에서 사용했던 모델의 층이 그대로 나와있는 것을 확인할 수 있다. 각 층의 가중치와 절편은 층의 weights 속성에 저장되어 있다. -> 얘는 파이썬 리스트임

이 weights 속성을 조금 쉽게 사용하기 위해서 넘파이 배열로 변경시켜서 가중치를 시각화 시켰다.

conv = model.layers[0]

# 첫 번째 층: 합성층
conv_weights = conv.weights[0].numpy()
print(conv_weights.mean(), conv_weights.std()) # -0.021033935 0.23466988

# 가중치 그리기
import matplotlib.pyplot as plt
plt.hist(conv_weights.reshape(-1, 1))
plt.xlabel('weights')
plt.ylabel('count')
plt.show()

download1


가중치가 0을 중심으로 종모양의 분포를 띠고 있는 것을 알 수 있다. -> 이 가중치가 무엇을 의미하는가?

fig, axs = plt.subplots(2, 16, figsize=(15, 2))
for i in range(2):
  for j in range(16):
    axs[i, j].imshow(conv_weights[:, :, 0, i*16 + j], vmin=-0.5, vmax=0.5)
    axs[i, j].axis('off')
plt.show()

download2

32개의 커널의 가중치를 출력한 모습

📌 훈련하지 않은 모델의 가중치 표현

no_training_model = keras.Sequential()
no_training_model.add(keras.layers.Conv2D(32, kernel_size=3, activation='relu', padding='same', input_shape=(28, 28, 1)))

no_training_conv = no_training_model.layers[0]
no_training_weights = no_training_conv.weights[0].numpy()

plt.hist(no_training_weights.reshape(-1, 1))
plt.xlabel('weights')
plt.ylabel('count')
plt.show()

download2

초기 훈련하지 않은 모델의 경우 가중치는 균등 분포에서 랜덤하게 값을 선택하여 비교적 고른 분포를 보입니다.

fig, axs = plt.subplots(2, 16, figsize=(15, 2))
for i in range(2):
  for j in range(16):
    axs[i, j].imshow(no_training_weights[:, :, 0, i*16 + j], vmin=-0.5, vmax=0.5)
    axs[i, j].axis('off')
plt.show()

download3


커널의 가중치 역시 전반적으로 고른 색을 띄우고 있는 것을 확인할 수 있다. -> 따.라.서 합성곱 신경망이 패션 MNIST 데이터셋의 분류 정확도를 높이기 위해 유용한 패턴을 학습했다는 것을 알 수 있다.

📍 특성 맵 시각화하기

inputs = keras.Input(shape=(784, ))
hidden = dense(inputs) # 첫 번째 층
outputs = dense2(hidden) # 두 번째 층
model = keras.Model(input, outputs) # 출력층까지 연결

이런식으로 함수형 API가 사용이 되는데 왜 이게 가중치를 시각화하는데 필요하냐면 시각화하기위해서는 출력층의 가중치가 필요한 것이 아닌, 첫 번째 층, 두 번째 층 등의 중간에 있는 층의 특성 맵이 필요하다. 이때, output 속성을 사용해서 특성 맵을 얻을 수 있다.

함수형 API를 사용해서 특성 맵 시각화 하기!

conv_acti = keras.Model(model.input, model.layers[0].output)

(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()
plt.imshow(train_input[0], cmap='gray_r')
plt.show()

download1

신발에 대한 가중치를 시각화 해볼 예정

inputs = train_input[0:1].reshape(-1, 28, 28, 1) / 255.0
feature_maps = conv_acti.predict(inputs)
print(feature_maps.shape)

>>> (1, 28, 28, 32)

합성곱 층을 output으로 가진 모델을 이용하여서 부츠에 대한 특성 맵을 만들었다.

fig, axs = plt.subplots(4, 8, figsize=(15, 8))
for i in range(4):
  for j in range(8):
    axs[i, j].imshow(feature_maps[0, :, :, i * 8 + j])
    axs[i, j].axis('off')
plt.show()

download2

32개의 필터로 인해서 입력 이미지에서 강하게 활성화된 부분을 보여준다. 앞에서 출력해보았던 필터가 감지한 색상이 강하게 활성화된 것을 확인할 수 있다.

conv2_acti = keras.Model(model.input, model.layers[2].output)
feature_maps = conv2_acti.predict(train_input[0:1].reshape(-1, 28, 28, 1)/255.0)

fig, axs = plt.subplots(8, 8, figsize=(12, 12))
for i in range(8):
  for j in range(8):
    axs[i, j].imshow(feature_maps[0, :, :, i * 8 + j])
    axs[i, j].axis('off')
plt.show()

download3

두 번째 합성곱 층의 필터 개수는 64개이므로 출력할 수 있는 특성 맵 역시 64개임을 알 수 있다. 두 번째 합성곱 층의 64개의 필터가 앞서 출력한 32개의 특성 맵과 각각 곱해져 두 번째 합성곱 층의 output이 되는데, 특성 맵에서 어떤 부위를 감지하는지 직관적으로 이해하기 어렵다. 즉, 앞부분에 있는 합성곱 층은 이미지의 시각적인 정보를 감지하고 뒤쪽에 있는 합성곱 층은 앞쪽에서 감지한 시각적인 정보를 바탕으로 추상적인 정보를 학습한다고 볼 수 있다.

댓글남기기