09_DL(Deep_Learning)

10_합성곱 신경망_시각화(부츠)

chuu_travel 2025. 4. 25. 16:40
728x90
합성곱 신경망_시각화(부츠)

 

 

from tensorflow import keras
import matplotlib.pyplot as plt

 

 

필터의 가중치

  • 입력 이미지의 2차원 영역에 적용되어 어떤 특징을 크게 두드러지게 표현하는 역할
    • 예) 물건의 테두리같은 특징적인 부분의 가중치는 높고 그 외 영역은 가중치가 낮게

 

# 저장해둔 cnn 모델 불러오기
model = keras.models.load_model("./model/best-cnn-model.keras")

 

# 모델 층 확인
model.layers
[<Conv2D name=conv2d, built=True>,
 <MaxPooling2D name=max_pooling2d, built=True>,
 <Conv2D name=conv2d_1, built=True>,
 <MaxPooling2D name=max_pooling2d_1, built=True>,
 <Flatten name=flatten, built=True>,
 <Dense name=dense, built=True>,
 <Dropout name=dropout, built=True>,
 <Dense name=dense_1, built=True>]

 

# 첫 번째 합성곱 층의 가중치 확인
conv = model.layers[0]
print(conv.weights[0].shape, conv.weights[1].shape)
(3, 3, 1, 32) (32,)

 

  • conv.weights[0]
    • 가중치
    • 가중치의 크기
      • 커널의 크기 : (3, 3, 1)
      • 필터의 개수 : 32
  • conv.weights[1]
    • 절편의 개수 = 필터의 개수

 

# 원활한 계산을 위해 넘파이 배열로 변환
conv_weights = conv.weights[0].numpy()

 

conv_weights
array([[[[ 2.68509537e-01,  3.98671301e-03, -1.34202555e-01,
           2.26991381e-02, -1.61807805e-01,  1.41456425e-01,
           8.40340257e-02, -5.91420792e-02,  8.30178335e-02,
          -1.52722999e-01, -1.92740276e-01,  3.41112167e-01,
           5.81143536e-02,  1.51849529e-02, -2.43479699e-01,
          -3.34581196e-01,  9.78106037e-02, -9.84926745e-02,
           1.20031491e-01, -3.64511497e-02,  1.04661845e-01,
           1.67219803e-01, -3.55258398e-02, -8.97972938e-03,
          -1.77619278e-01, -4.82102633e-01, -2.21281499e-01,
           2.43143499e-01, -7.25867808e-01,  8.06739926e-02,
           1.91355154e-01,  1.53868357e-02]],

...

 

 

print(conv_weights.mean(), conv_weights.std())
-0.00686185 0.21702722

 

 

# 가중치 히스토그램
plt.figure()
plt.hist(conv_weights.reshape(-1, 1))
plt.xlabel("weight")
plt.ylabel("count")
plt.show()
# 학습이 안된상태에서는 직사각형의 균등한 분포, 학습을 진행할 수록 종모양의 분포가 됨

 

 

  • 0을 중심으로 종 모양의 분포
# 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()

# 밝은색이 높은것, 어두운색이 낮은것

 

  • 밝은 부분이 높은 값
    • 가중치가 높은 영역에 이미지가 겹치면 크게 활성화 됨
      • 예) 오른쪽 세로로 한 줄의 가중치가 높다면 오른쪽에 놓인 직선을 만나면 크게 활성화
  • i : 행 인덱스(0 ~ 1)
  • j : 열 인덱스(0 ~ 15)
    • conv_weights[:, :, 0, 0] 부터 conv_weights[:, :, 0, 31] 까지 출력
  • imshow()
    • 배열의 최댓값과 최솟값으로 픽셀의 강도를 표현
      • 배열의 최댓값은 가장 밝은 색으로
      • 배열의 최솟값은 가장 어두운 색으로 표현
    • vmax, vmin
      • 컬러맵으로 표현할 색의 범위 지정

 

 

훈련하지 않은 합성곱 신경망과 비교

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

 

# 훈련하지 않은 합성곱 층의 가중치를 저장
no_training_conv = no_training_model.layers[0]
print(no_training_conv.weights[0].shape)
(3, 3, 1, 32)

 

no_training_weights = no_training_conv.weights[0].numpy()
print(no_training_weights.mean(), no_training_weights.std())
0.0016037128 0.07975823

 

# 훈련하지 않은 합성곱 층 히스토그램
plt.figure()
plt.hist(no_training_weights.reshape(-1, 1))

plt.xlabel("weight")
plt.ylabel("count")
plt.show()

# 훈련되지 않은 값은 종모양에 가깝지 않다

  • 대부분의 가중치가 -0.15 부터 0.15까지 고르게 분포함
    • 텐서플로에서 가중치를 초기화할 때 균등분포에서 랜덤하게 값을 선택하기 때문에

 

# 32개의 커널을 모두 시각화
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()

  • 훈련된 모델에 비해 패턴이 뚜렷하지 않음

 

케라스의 함수형 API

  • Sequential 클래스 : 층을 차례대로 쌓은 단순한 모델을 구성
  • 복잡한 모델은 구성하기 힘들기 때문에 함수형API(functional API)를 사용
  • 케라스의 Model클래스를 사용하여 모델을 생성
  • layers객체를 함수처럼 호출하여 동작

 

함수형 API로 다층 퍼셉트론 모델 구현 예제

# 입력층 생성
inputs = keras.Input(shape = (784,))

 

# 은닉층과 출력층 객체 생성
dense1 = keras.layers.Dense(100, activation = "sigmoid")
dense2 = keras.layers.Dense(10, activation = "softmax")

 

# 은닉층 호출
hidden = dense1(inputs)
  • inputs를 Dense층에 통과시킨 후 출력값 hidden을 만드는 구조 생성
# 출력층 호출
outputs = dense2(hidden)

 

# Model 클래스로 inputs와 outputs를 연결
test_model = keras.Model(inputs, outputs)

 

test_model.summary()

 

 

########## 예제 끝 ##########

 

 

합성곱 신경망 모델 특성맵 시각화

  • 함수형 API를 이용해 첫 번째 합성곱 층의 출력(특성맵)을 시각화

 

# 훈련된 합성곱 모델의 입력층
print(model.inputs[0])
<KerasTensor shape=(None, 28, 28, 1), dtype=float32, sparse=False, ragged=False, name=input_layer>

 

 

# 합성곱층과 입력층을 함수형 API로 연결
conv_acti = keras.Model(model.inputs[0], model.layers[0].output)

 

conv_acti.summary()

 

 

# 데이터 준비
(x_train, y_train), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()

 

plt.figure()
plt.imshow(x_train[0], cmap = "gray_r")
plt.show()

 

# 위의 데이터를 첫 번째 합성곱 층에 통과
inputs = x_train[[0]].reshape(-1, 28, 28, 1) / 255

 

feature_maps = conv_acti.predict(inputs)

 

 

print(feature_maps.shape)
(1, 28, 28, 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()

  • 32개의 필터로 인해 입력 이미지에서 강하게 활성화된 부분들을 시각화
    • 필터가 수직선을 감지한다면 수직선 부분이 강하게 활성화
    • 전체적으로 모두 감지하는 필터는 아이템의 전체를 활성화
    • 전체적으로 음수값인 필터는 배경과 같은 0에 가까운 값과 곱해지면 작은 음수, 큰 수가 곱해지면 큰 음수가 됨
    • 배경을 잘 활성화함

 

# 두 번째 합성곱 층의 특성맵 확인
conv2_acti = keras.Model(model.inputs[0], model.layers[2].output)
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()

  • 특성맵을 시각적으로 이해하기 난해함
    • 합성곱 층을 많이 쌓을 수록 심해짐
    • 앞부분의 합성곱 층은 이미지의 시각적인 정보를 감지하고
    • 뒷부분의 합성곱 층은 앞쪽에서 감지한 시각적인 정보를 바탕으로 추상적인 정보를 학습

 

 

풀링 결과물 비교

pool_model = keras.Model(model.inputs[0], model.layers[1].output)
pool_feature_maps = pool_model.predict(inputs)

 

 

print(pool_feature_maps.shape)
(1, 14, 14, 32)

 

fig, axs = plt.subplots(4, 8, figsize = (15, 8))

for i in range(4):
    for j in range(8):
        axs[i, j].imshow(pool_feature_maps[0, :, :, i * 8 + j])
        axs[i, j].axis("off")

plt.show()

 

# 화질이 떨어짐을 알 수 있음
# ->성능이 좋아지고 연산 속도가 빨라짐
728x90

'09_DL(Deep_Learning)' 카테고리의 다른 글

12_CIFAR10  (0) 2025.04.28
11_CNN_MNIST  (0) 2025.04.25
09_합성곱 신경망(컬러 이미지 분류)  (0) 2025.04.24
08_합성곱 신경망_구성요소  (0) 2025.04.24
07_보스턴 집값 예측  (0) 2025.04.24