핵심 키워드
- #가중치 시각화 #특성 맵 시각화 #함수형 API
- 합성곱 층의 가중치와 특성 맵을 시각화하여 신경망이 이미지에서 어떤 것을 학습하는지 이해해보자
가중치 시각화
- 가중치 시각화
합성곱 층은 여러 개의 필터를 사용해 이미지에서 특징을 학습하며
가중치는 입력 이미지의 2차원 영역에 적용되어 어떤 특징을 크게 두드러지게 표현하는 역할을 함
예를 들어 아래와 같은 가중치는 둥근 모서리가 있는 영역에서 크게 활성화되고 그렇지 않은 영역에서는 낮은 값을 만듦
이 필터의 가운데 곡선 부분의 가중치 값은 높고 그 외 부분의 가중치 값은 낮을 것
- 층의 가중치 분포
앞에서 만든 모델이 어떤 가중치를 학습했는지 확인하기 위해 체크포인트 파일을 읽어 들인 후,
케라스 모델에 추가한 층을 출력하기 위해 layers 속성을 출력
model.layers 리스트에 이전 절에서 추가했던 Conv2D, MaxPooling2D 층이 번갈아 연속 등장하고
그 다음 Flatten 층과 Dense 층, Dropout 층이 차례대로 등장하며 마지막에 Dense 출력층이 놓여 있는 것을 볼 수 있음
첫 번째 합성곱 층의 가중치를 조사하기 위해 층의 가중치와 절편이 저장되어 있는 weights 속성을 사용
layers 속성의 첫 번째 원소(0)를 선택해 weights의 첫 번째 원소(가중치)와 두 번째 원소(절편)의 크기를 출력하면
커널의 크기가 (3, 3)이고 입력이 깊이가 1, 필터의 개수가 32개이므로 weights의 첫 번째 원소인 가중치의 크기는 (3, 3, 1, 32)
weights의 두 번째 원소는 절편의 개수를 나타내므로 필터마다 1개의 절편이 있으므로 (32, ) 크기가 됨
weights 속성을 다루기 쉽도록 numpy() 메소드를 사용해 넘파일 배열로 변환한 후
이 가중치가 어떤 분포를 가졌는지 직관적으로 이해하기 쉽도록 1차원 배열로 변환한 후 히스토그램을 그려보면
0을 중심으로 종 모양 분포를 띠고 있는 것을 알 수 있음
위와 달리, 훈련하지 않은 빈 합성곱 신경망을 만들어 가중치 배열을 만들고 히스토그램으로 표현하면
이전 그래프와 달리 대부분의 가중치가 -0.15 ~ 0.15 사이에 있고 비교적 고른 분포를 보이는 것을 볼 수 있음
이런 이유는 텐서플로가 신경망의 가중치를 처음 초기화할 때
0은 아니되, 0에 가까운 작은 실수값으로 초기화하기 위해 균등 분포에서 랜덤하게 값을 선택하기 때문임
이를 통해 합성곱 신경망이 분류 정확도를 높이기 위해 유용한 패턴을 학습했음을 알 수 있음
- 층의 가중치 시각화
첫 번째 합성곱 층의 32개의 커널을 16개씩 두 줄로 출력하기 위해 맷플롯립의 subplots() 함수를 사용해 순서대로 커널 출력
결과 그래프를 보면 이 가중치 값이 무작위로 나열된 것이 아닌 어떤 패턴을 볼 수 있음
예를 들어 첫 번째 줄 맨 왼쪽 가중치는 오른쪽 3픽셀의 값이 높으므로, 이 가중치는 오른쪽에 놓인 직선을 만나면 크게 활성화됨
imshow() 함수는 배열에 있는 최댓값과 최솟값을 사용해 픽셀의 강도를 표현하므로 그 배열의 최댓값이면 가장 밝은 노란색
그러므로 만약 두 배열을 imshow() 함수로 비교하려면 바람직하지 않으므로 어떤 절댓값으로 기준을 정해서
픽셀을 강도를 나타내야 비교하기 쉬우므로 vmin과 vmax로 맷플롯립의 컬러맵으로 표현할 범위를 지정
위와 달리 훈련하지 않은 합성곱 신경망의 가중치 값을 맷플롯립의 imshow() 함수를 사용해 그림으로 출력하면
전체적으로 가중치가 밋밋하게 초기화된 것을 볼 수 있음
함수형 API
- 함수형 API
지금까지는 신경망 모델을 만들 때 케라스 Sequential 클래스를 사용했으나
이번에는 함수처럼 호출할 수 있도록 함수형 API를 사용
함수형 API는 케라스의 Model 클래스를 사용해 모델을 만듦
예를 들어 Dense 층 2개로 이루어진 완전 연결 신경망을 함수형 API로 구현하기 위해서는 2개의 Dense 층 객체를 만들고
이 객체를 Sequential 클래스 객체의 add() 메소드에 전달하지 않고 함수처럼 호출하도록 함
이럴 경우 입력값 inputs를 Dense 층에 통과시킨 후 출력값 hidden을 만들어 주며
두 번째 층을 호출할 때 첫 번째 층의 출력을 입력으로 사용할 수 있음
그 다음 inputs 와 outputs을 Model 클래스로 연결해 주면 됨
즉, 입력에서 출력까지 층을 호출한 결과를 계속 이어주고 Model 클래스에 입력과 최종 출력을 지정하는 것
그런데 여기서 inputs는 어디서 온 걸까요?
이전 절에서 plot_model() 함수로 모델의 층을 도식화하는 InputLayer 클래스가 맨 처음으로 나왔음
Sequential 클래스는 InputLayer 클래스를 자동으로 추가하고 호출해주지만 Model 클래스는 수동으로 만들어 호출해야 함
그러므로 케라스의 Input() 함수를 사용해 InputLayer 클래스 객체를 쉽게 다루도록 하며
입력의 크기를 지정하면 shape 매개변수와 함께 사용해 이 함수를 호출하면 InputLayer 클래스 객체를 만들어 출력을 반환해줌
이렇게 모델을 만들게 되면 중간에 다양한 형태의 층을 연결할 수 있음
- 모델 객체의 층
특성 맵 시각화를 만드는데 함수형 API를 사용하는 이유로는 model 객체의 특정 층의 출력을 반환할 수 있기 때문임
model 객체의 입력과 Conv2D의 출력을 알아내어 새로운 모델을 얻을 수 있다면 첫 번째 Conv2D의 출력을 얻을 수 있을 것
그러므로 model 객체의 predict() 메소드를 호출하면 입력부터 마지막 층까지 모든 계산을 수행한 후 최종 출력만을 반환하지만
이를 이용하면 우리가 필요한 첫 번째 Conv2D 층이 출력한 특성 맵을 얻을 수 있음
이를 위해 첫 번째 층의 출력은 Conv2D 객체의 ouput 속성에서 얻고, model 객체의 입력은 input 속성으로 입력을 참조하여
model.input과 model.layer[0].output을 연결하는 새로운 conv_acti 모델을 만들 수 있고
conv_acti의 predict() 메소드를 호출하면 첫 번째 Conv2D의 출력을 반환받을 수 있음
특성 맵 시각화
- 첫 번째 특성 맵 시각화
패션 MNIST 데이터셋을 읽은 후 훈련 세트에 있는 첫 번째 샘플을 그려보면 앵클 부츠가 나오게 됨
이 샘플을 conv_acti 모델에 주입하여 Conv2D 층이 만드는 특성 맵을 출력해보겠음
이를 위해 슬라이싱 연산자를 사용해 첫 번째 샘플을 선택하고 (784, ) 크기를 (28, 28, 1) 크기로 변경하고 255로 나누어 전처리
그 후 conv_acti.predict() 메소드가 출력한 feature_maps의 크기를 확인해보면
세임 패딩과 32개의 필터를 사용한 합성곱 층의 출력이며, 샘플을 하나 입력했으므로 (1, 28, 28, 32)
그리고 이를 맷플롯립의 imshow 함수로 특성 맵을 그려보면
이 특성 맵은 32개의 필터로 인해 입력 이미지에서 강하게 활성화된 부분을 보여주게 됨 (가중치와 곱해져 나온 활성화 출력)
이를 앞서 32개의 필터의 가중치를 출력한 그림과 비교해보도록 함
첫 번째 필터는 오른쪽에 있는 수직선을 감지하며, 첫 번째 특성 맵은 이 필터가 감지한 수직선에 강하게 활성화되어있음
세 번째 필터는 전체적으로 밝은색이므로 전면이 모두 칠해진 영역에서 감지되며, 세 번째 특성 맵에서 이를 확인할 수 있음
마지막 필터는 전체적으로 낮은 음수이므로 이 필터와 큰 양수가 곱해지면 더 큰 음수가 되고, 배경처럼 0에 가까운 값과
곱해지면 작은 음수가 될 것이므로 부츠의 배경이 상대적으로 크게 활성화될 수 있음을 마지막 특성 맵에서 볼 수 있음
이렇게 어떤 가중치 패턴을 학습해 어떤 출력이 만들어지는지를 짐작할 수 있음
- 두 번째 특성 맵 시각화
두 번째 합성곱 층이 만든 특성 맵도 같은 방식으로 확인할 수 있으므로
model 객체의 입력과 두 번째 합성곱 층인 model_layer[2]의 출력을 연결한 conv2_acti 모델을 만듦
그리고 첫 번째 샘플을 conv2_acti 모델의 predict() 메소드에 전달하면 첫 번째 풀링 층에서 가로세로 크기가 절반으로 줄었고, 두 번째 합성곱 층의 필터 개수는 64개이고 샘플을 하나 입력했으므로 feature_maps의 크기는 (1, 14, 14, 64)
그리고 이를 imshow() 함수로 그려보게 되면, 이 특성 맵은 이해하기 어려운 결과를 나타냄
이는 합성곱 신경망의 앞부분에 있는 합성곱 층은 이미지의 시각적인 정보(저수준 특성)를 감지하고
뒤쪽에 있는 합성곱 층은 앞쪽에서 감지한 시각적인 정보를 바탕으로 추상적인 정보(고수준 특성)를 학습하기 때문이며
이를 통해 합성곱 신경망이 패션 MNIST 이미지를 인식하여 10개의 클래스를 찾아낼 수 있었던 것임
'ML > 혼자 공부하는 머신러닝 + 딥러닝' 카테고리의 다른 글
[혼공머신] 09. 텍스트를 위한 인공 신경망 - 순환 신경망으로 IMDB 리뷰 분류하기 (0) | 2022.07.20 |
---|---|
[혼공머신] 09. 텍스트를 위한 인공 신경망 - 순차 데이터와 순환 신경망 (0) | 2022.07.19 |
[혼공머신] 08. 이미지를 위한 인공 신경망 - 합성곱 신경망을 사용한 이미지 분류 (0) | 2022.07.13 |
[혼공머신] 08. 이미지를 위한 인공 신경망 - 합성공 신경망의 구성 요소 (0) | 2022.07.12 |
[혼공머신] 07. 딥러닝을 시작합니다 - 신경망 모델 훈련 (0) | 2022.07.07 |