데이터분석-머신러닝-AI/강의 정리

[혼자 공부하는 머신러닝+딥러닝] 22강. 합성곱 신경망의 시각화 - 가중치, 특성치 시각화

bluebamus 2023. 11. 27.

https://www.youtube.com/watch?v=_lDVf8jDKHg&list=PLJN246lAkhQjoU0C4v8FgtbjOIXxSs_4Q&index=25

 

 - 가중치 시각화

   - 합성곱 신경망은 이미지 처리를 잘하기 때문에 무엇으로 학습했는지 시각적으로 보기 좋다.

   - 입력값에 필터를 이용해 특성맵을 만들 경우 가주치가 높은 영역은 높은 출력 값을 가지게 되고 가중치가 낮은 영역은 낮은 출력값을 가지게 된다.

 

 - 층의 가중치 분포

      - 데이터 준비

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

model.layers

[<keras.layers.convolutional.conv2d.Conv2D at 0x7a0182544820>,
 <keras.layers.pooling.max_pooling2d.MaxPooling2D at 0x7a020cc2d840>,
 <keras.layers.convolutional.conv2d.Conv2D at 0x7a0179a19060>,
 <keras.layers.pooling.max_pooling2d.MaxPooling2D at 0x7a0179a189a0>,
 <keras.layers.reshaping.flatten.Flatten at 0x7a01790ad450>,
 <keras.layers.core.dense.Dense at 0x7a01790ad390>,
 <keras.layers.regularization.dropout.Dropout at 0x7a01790ae2f0>,
 <keras.layers.core.dense.Dense at 0x7a01790aeb90>]

   

      - 첫 번째 합성곱 층의 가중치를 확인해 본다.

         - 층의 가중치와 절편은 층의 weights 속성에 저장되어 있다.

conv = model.layers[0]

print(conv.weights[0].shape, conv.weights[1].shape)

(3, 3, 1, 32) (32,)

 

 1. 가중치 시각화 하기

   - 가중치 분포 히스토그램으로 나타내보기

      - 0을 중심으로 종 모양으로 분포되는 것을 확인할 수 있다.
      - 입력값이 0인 입력 데이터(의미 없는 값)는 출력값 또한 0이 된다. 

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

 

   - 커널 그림으로 나타내기

      - 이번에는 32개의 커널을 16개씩 두 줄에 출력해 보기로 한다.

         - vmin과 vmax를 이용해 픽셀의 최댓값과 최솟값을 지정하여 컬러맵으로 표현할 범위를 정한다.

         - 픽셀의 특정 부분이 밝고 어두운 것을 토대로 가중치 값이 무작위가 아닌 특정 패턴을 가지고 있다는 걸 예상할 수 있다.

fig, axs = plt.subplots(2, 16, figsize=(15,2))

for i in range(2) :
  for j in range(16) :
  	# 32개의 커널을 16개씩 두 줄에 출력
    axs[i, j].imshow(conv_weights[:,:,0,i*16+j], vmin=-0.5, vmax=0.5)
    axs[i, j].axis('off')

plt.show()

 

   - 훈련되지 않은 합성곱 신경망의 가중치

      - 훈련되지 않은 합성곱 신경망의 가중치를 확인해 보자

         - 입력 데이터 없이 층만 만들어서 가중치를 확인한다.

         - 3 x 3 커널을 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]

print(no_training_conv.weights[0].shape)

(3, 3, 1, 32)

 

      - 가중치의 평균은 0에 근접하고 표준편차는 0.08에 근접하다.

      - 위에서 훈련된 합성곱 신경망의 결과와 비교하면 평균은 비슷하지만 표준편차는 매우 작다는 것을 알 수 있다.

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

print(no_training_weights.mean(), no_training_weights.std())

-0.010310263 0.0773888

 

      - 그래프로 확인하자

         - 0에 가까운 균등분포가 되어 있다.

         - 텐서플로우가 신경망의 가중치를 처음 초기화 할때 균등 분포에서 갠덤하게 값을 선택하기 때문에 이런 분포가 만들어 지는 것이고 이후 훈련을 하고 나면 입력 데이터를 기반으로 위에서 확인한 정규분포 그래프를 확인할 수 있다.

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

plt.show()

 

 2. 함수형 API

   - 케라스의 Sequential 클래스를 사용하면 InputLayer 클래스를 자동으로 추가해 주기 때문에 이전 강좌들에서는 신경을 쓰지 않았었다. 

   - 함수형 API에서는 InputLayer를 명시적으로 만들어줘야 한다.

   - 케라스는 InputLayer 클래스 객체들을 사용자가 쉽게 다룰 수 있도록 Input() 메서드를 제공한다.

 

   - 신경망 모델을 만들 때 케라스의 Sequential 클래스를 사용해왔다. 하지만 딥러닝에서는 좀 더 복잡한 모델이 많이 있으며 이런 경우 함수형 API를 사용한다.

   - 함수형 API는 케라스의 Model 클래스를 사용하여 모델을 만든다.

   - 사용 방법으로 Dense를 이용해 생성한 클래스를 함수처럼 인자를 정의하고 호출하면 된다.

   - 여러개의 입력 혹은 출력을 가진 다양한 구조를 만들 수 있다. 

   - Model()을 이용해 생성된 결과물은 Sequential 클래스를 이용해 만든 케라스 모델과 동일하다.

   - 예시로 Dense층 2개로 만들어진 완전 연결 신경망을 함수형 API를 이용해 구현해 보도록 한다.

inputs = keras.Input(shape=(784,))

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

hidden = dense1(inputs)
outputs = dense2(hidden)

model = keras.Model(inputs, outputs)

 

   - 모델 객체의 층

      - 모델의 중간에서 출력을 별도로 반환받아 확인해보는 과정을 수행한다.

      - 합성곱층의 활성화출력을 시각화 하는 방법으로 함수형 API를 사용하기로 한다.

         - 특성 맵을 시각화하기 위해서는 첫 번째 층 Conv2D의 출력이 필요하고 이 정보는 Conv2D 객체의 output 속성에서 얻을 수 있다. 그리고 input속성으로 모델의 입력을 얻을 수 있다.

 

      - input 확인

print(model.input)

KerasTensor(type_spec=TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='conv2d_input'), name='conv2d_input', description="created by layer 'conv2d_input'")

 

      - 이러한 방법들을 이용해 model.input과 model.layers[0].output 을 연결하는 새로운 conv_acti 모델을 만든다.

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

   

      - model 객체의 predict() 메서드를 호출하면 입력부터 마지막 층까지의 계산을 수행한 최종 출력을 반환받을 수 있다.

      - conv_acti의 predict() 메서드를 호출하여 Conv2D의 출력을 받환 받고 이를 이용해 특성 맵을 시각화 한다.

 

 3. 특성 맵 시각화

   - 케라스 패션 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 층이 만드는 특성맵을 출력하자.

      - 28 x 28 크기의 필터 32개로 구성되어 있다.

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)

 

   - 필터 32개를 시각화 해보자

      - 이 특성 맵은 32개의 필터로 인해 입력 이미지에서 강하게 활성화된 부분을 보여준다.

      - 이러한 이미지 확인 작업은 이전 가중치의 시각화와 비교하여 어떤 부분들이 크게 활성화 되었는지를 비교 확인할 수 있다.

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

 

      - 두 번째 합성곱 층이 만든 특성 맵도 시각화 해보자

         - 두 번째 합성곱이 만든 특성 맵은 시각적으로 이해하기 어렵다.

         - 뒤쪽에 있는 합성곱층은 앞쪽에서 감지한 시각적 정보를 바탕으로 추상적인 정보를 학습하기에 사람의 시각으로 판단하기 어려운 경우가 대부분이다. 

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

feature_maps = conv2_acti.predict(inputs)

print(feature_maps.shape)
(1, 14, 14, 64)



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

 

      - 합성곱 신경망은 낮은층에서 저수준 특성을 학습한다.

         - 단순 모양, 패턴, 색깔 등

      - 층이 깊어질수록 고수준 특성을 학습힌다.

         - 추상적인 특성을 학습한다.

 

 

 

 - reference :

 

https://velog.io/@katinon/%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A0-%ED%95%A9%EC%84%B1%EA%B3%B1-%EC%8B%A0%EA%B2%BD%EB%A7%9D%EC%9D%98-%EC%8B%9C%EA%B0%81%ED%99%94

 

[혼공머신] 합성곱 신경망의 시각화

혼자 공부하는 머신러닝+딥러닝 책에 기반한 정리글입니다.전체 소스코드는 아래 Github 링크에서 확인할 수 있습니다.Github 링크이번 편에서는 저번 편에서 저장한 합성곱 신경망 모델을 읽어 들

velog.io

 

댓글