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 |