Etc/Deep Learning

5장 합성곱 신경망Ⅰ(3) 실습 - 특성맵 시각화

z.zzz 2021. 8. 8. 19:10

1. 새로운 모델 생성

합성곱층, 최대풀링층 쌍을 4개 쌓고, 완전연결층을 순차적으로 쌓음

model = tf.keras.models.Sequential([
     tf.keras.layers.Conv2D(input_shape=(100, 100, 3), activation='relu', kernel_size=(5, 5), filters=32),
     tf.keras.layers.MaxPooling2D(),
     tf.keras.layers.Conv2D(activation='relu', kernel_size=(5, 5), filters=64),
     tf.keras.layers.MaxPooling2D(),
     tf.keras.layers.Conv2D(activation='relu', kernel_size=(5, 5), filters=64),
     tf.keras.layers.MaxPooling2D(),
     tf.keras.layers.Conv2D(activation='relu', kernel_size=(5, 5), filters=64),
     tf.keras.layers.MaxPooling2D(),
     tf.keras.layers.Flatten(),
     tf.keras.layers.Dense(128, activation='relu'),
     tf.keras.layers.Dense(64, activation='relu'),
     tf.keras.layers.Dense(32, activation='relu'),
     tf.keras.layers.Dense(2, activation='softmax')
])

Conv2D : 합성곱층

     - input_shape : (행, 열, 채널 수)

     - activation = 'relu' : 은닉층에 주로 쓰이는 활성화 함수

     * 활성화 함수 : 각 노드에 가중치를 곱하고 bias를 더한 값이 넘어갈때 특정 조건을 만족하면 활성화 함수에 의해 활성화 되었다는

                        신호를(활성화 함수를 거친 출력값) 다음 노드로 보내 활성화하고, 조건을 만족하지 못했으면 해당 노드를 비활성화함

     - 가중치 : 커널 크기 × 필터 수 (예: (5 × 5) × 64 = 1600개)

Dense : 밀집층, 완전연결층

     - 첫번째 인자 : 출력 노드(뉴런)의 

https://dsbook.tistory.com/59

 

2. 특성맵 정의

특성맵 = 합성곱층입력 이미지 필터를 연산해서 얻은 결과

  ⇒ 합성곱층의 입력과 출력을 확인하면, 특성 맵에 대한 시각화가 가능할 것

ins = model.inputs        #모델 입력으로 (None, 100, 100, 3)의 형태를 가짐(1에서 정의)
outs = model.layers[0].output         #첫번째 계층에 대한 출력 형태 : (None, 96, 96, 32)
feature_map = Model(inputs=ins, outputs=outs)     #ins, outs를 모델 입력과 출력으로 사용, 특성 맵을 정의
feature_map.summary()

첫번째 계층의 모델

   - CNN의 output shape : (batch_size, height, width, depth(channel))

 

3. 이미지 전처리 및 특성맵 확인

img = plt.imread('../chap5/data/cat.jpg')
img = cv2.resize(img, (100, 100))        #이미지 크기 조정
input_img = np.expand_dims(img, axis=0)      #이미지 차원 조정
print(input_img.shape)     #입력 이미지 형태 출력

feature = feature_map.predict(input_img)     #이미지를 모델에 적용
print(feature.shape)     #특성 맵에 대한 형태 출력

fig = plt.figure(figsize=(50, 50))
for i in range(16):    #이미지 16개 출력
     ax = fig.add_subplot(8, 4, i+1)     #subplot(m, n, p)는 , p로 지정된 위치에 좌표축을 만듦
     ax.imshow(feature[0, :, :, i])

원본 이미지
첫번째 계층 출력 결과

 

→ 입력층과 가까운 계층으로 입력 이미지의 형태가 많이 유지되고 있음

expand_dims()

nums = np.array([2, 5])      #nums.shape=(2, )
axis_0 = np.expand_dims(nums, axis=0)
axis_1 = np.expand_dims(nums, axis=1)

expand_dims 예시

 

4. 여섯 번째 계층에 대한 특성맵

ins = model.inputs    //모델 입력으로 (None, 224, 224, 3)의 형태
outs = model.layers[6].output      //여섯 번째 계층에 대한 출력으로 None, 1000)
feature_map = Model(inputs=ins, outputs=outs)
...

여섯번째 계층 출력 결과

원래 입력 이미지의 형태X

=> 출력층에 가까울 수록 원형은 사라지고 이미지 특징만 전달되는 것을 확인 가능

 

 

 


conv2D 참고 : https://tykimos.github.io/2017/01/27/CNN_Layer_Talk/conv

활성화 함수 참고 : https://dsbook.tistory.com/59

 

Q. 완전연결층(dense)을 여러개 쌓는 것은 출력노드를 점차적으로 줄이기 위한 것인가?(그렇다면 한번에 줄이는건 안되나?)