본문 바로가기

AI: ML,DL

[인공지능] 합성곱 신경망의 시각화[인공지능] 합성곱 신경망의 시각화

가중치 시각화

합성곱 레이어는 여러 개의 필터를 사용해 이미지의 특징을 학습한다. 필터에는 커널이라는 가중치가 존재하며, 가중치는 이미지의 2차원 영역에 적용되어 어떤 특징을 두드러지게 하는 역할을 한다. 어떠한 특징이 있는 곳에서는 가중치가 활성화되고 특징이 없다면 활성화 되지 않는다.

 

모델의 레이어 중 첫번째 합성곱 층에 대한 가중치를 조사하는 과정이다. 특징이 있는 곳에서는 가중치가 활성화되고 특징이 없다면 활성화 되지 않는다.

 

from tensorflow import keras
model = keras.models.load_model('best-cnn-model.h5')

print(model.layers)

conv = model.layers[0]
print(conv.weights[0].shape, conv.weights[1].shape)
# (3, 3, 1, 32) (32,) :가중치의 크기, 절편

conv_weights = conv.weights[0].numpy()
print(conv_weights.mean(), conv_weights.std())

import matplotlib.pyplot as plt
plt.hist(conv_weights.reshape(-1,1))
plt.xlabel('weight')
plt.ylabel('count')
plt.show()

해당 가중치의 평균 값은 0에 가깝고 표준 편차는 0.27이다.

 

다음은 32개의 커널을 그리는 코드이다.

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()

위에서 imshow() 메서드는 값이 클 수록 밝은 색을 띈다. 

 

아래는 훈련하지 않은 빈 합성곱 신경망을 만들고 해당 합성곱 레이어의 가중치가 어떻게 다른지 확인해보는 과정이다.

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]
print(no_training_model.weights[0].shape)
# (3,3,1,32)

no_training_conv_weights = no_training_model.weights[0].numpy()
print(no_training_conv_weights.mean(), no_training_conv_weights.std())
# -0.0040033553 0.08113038

plt.hist(no_training_conv_weights.reshape(-1,1))
plt.xlabel('weight')
plt.ylabel('count')
plt.show()

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_conv_weights[:,:,0,i*16+j],vmin=-0.5,vmax=0.5)
    axs[i,j].axis('off')
plt.show()

위를 보면 전체적으로 가중치가 -0.15~0.15 사이에 분포하며 값도 비슷한 편이다. 그리고 아래 커널을 그려봐도 훈련된 모델에 비해 전반적으로 색상이 비슷한 편이다.

 

 

함수형 API

신경망 모델을 만들 때는 Sequential 클래스를 활용했다. 하지만 딥러닝에는 보다 복잡한 모델이 많다. 입력이 두개, 출려깅 두개일 수도 있다. 이런 경우에 사용하는 게 함수용 API이다.

 

아래와 같이 Dense 층을 만들고 우리는 기존 모델 클래스에 add() 메서드를 호출하여 추가했다.

dense1 = keras.layers.Dense(100, activation='sigmoid')
dense2 = keras.layers.Dense(10, activation='softmax')

 

하지만 아래와 같이 함수처럼 호출할 수도 있다.

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

주의할 점은 input 레이어(입력층)을 함수형 API에서는 직접 정의해야한다. 기존 Sequential과 같은 클래스에서는 input 레이어가 이미 추가된 상태로 객체화된다.

 

 

특성맵 시각화

패션 MNIST을 읽은 뒤 훈련 세트의 첫 샘플을 그리면 아래와 같다.

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

아래는 위 샘플을 conv_acti 모델에 주입하여 Conv2D 레이어가 만드는 특성 맵을 출력하는 코드이다.

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

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

 

두 번째 합성곱 층에서 만든 특성맵을 확인해보자.

conv_acti2 = keras.Model(model.input, model.layers[2].output)

inputs = train_input[0:1].reshape(-1,28,28,1)/255.0
feature_map = conv_acti2.predict(inputs)

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

이처럼 두번째 합성곱 층의 틉성맵은 시각적으로 이해하기 어렵다. 이런 현상은 합성곱 층이 많이 쌓일 수록 심해진다. 이는 합성곱 신경만의 앞부분의 합성곱 층은 시각적인 정보를 감지하고 뒤쪽 합성곱 층은 앞쪽에서 감지한 시각적인 정보를 기반으로 추상적인 정보를 학습한다고 볼 수 있다.

 

 

참고

  • 혼자 공부하는 머신러닝+딥러닝(박해선 저)