관리 메뉴

클라이언트/ 서버/ 엔지니어 "게임 개발자"를 향한 매일의 공부일지

이미지를 위한 인공 신경망 6 - 합성곱 신경망의 시각화 2 : 함수형 API 및 특성 맵 시각화 본문

인공지능/딥러닝

이미지를 위한 인공 신경망 6 - 합성곱 신경망의 시각화 2 : 함수형 API 및 특성 맵 시각화

huenuri 2024. 10. 27. 23:56

합성곱 신경망의 학습을 시각화하는 두 번째 방법은 합성곱 층에서 출력된 특성 맵을 그려보는 것이다. 이를 통해 입력 이미지를 신경망 층이 어떻게 바라보는지 엿볼 수 있다. 합성곱 층의 출력을 만들기 전에 케라스 함수형 API에 대해 먼저 알아보겠다.


 

 

 

 

함수형 API

지금까지는 신경망 모델을 만들 때 케라스 Sequential 클래스를 사용했다. 이 클래스는 층을 차례대로 쌓은 모델을 만든다. 딥러닝에서는 좀 더 복잡한 모델이 많이 있다. 예를 들어 입력이 2개일 수도 있고 출력이 2개일 수도 있다. 이런 경우는 Seqeuntial 클래스를 사용하기 어렵다. 대신 함수형 API를 사용한다.

함수형 API는 케라스의 Model 클래스는 사용하여 모델을 만든다. 간단한 예를 들어보겠다. 7장에서 만들었던 Dense 층 2개로 이루어진 완전 신경망을 함수형 API로 구현해 본다. 먼저 2개의 Dense 층 객체를 만든다.

 

 

 

이 객체를 Sequential 클래스 객체의 add() 메서드에 전달할 수 있다. 하지만 다음과 같이 함수처럼 호출할 수 있다.

 

 

 

바로 호출하면 오류가 뜨고 먼저 입력 데이터를 생성해야 한다. 파이썬의 모든 객체는 호출 가능하다. 케라스의 층은 객체를 함수처럼 호출했을 때 적절히 동작할 수 있도록 미리 준비해 놓았다. 앞의 코드를 실행하면 입력값 inputs를 Dense 층에 통과시킨 후 출력값 hidden을 만들어 준다.

 

그다음 두 번째 층을 호출한다. 이때는 첫 번째 층의 출력을 입력으로 사용한다.

 

 

model 객체의 predict() 메서드를 호출하면 입력부터 마지막 층까지 모든 계산을 수행한 후 최종 출력을 반환한다. 하지만 우리가 필요한 것은 첫 번째 Conv2D 층이 출력한 특성 맵이다. 케라스 모델은 input 속성으로 입력을 참조할 수 있다. 

 

 

 

이제 model.input과 model.layers[0].output을 연결하는 새로운 conv_acti 모델을 만들 수 있다.

 

 

책에 있는 코드가 많이 달라서 계속 수정 중이다. 입력을 초기화하는 코드를 작성했고, input이 아닌 inputs를 썼다. 왜냐하면 변수로 inputs를 지정했기 때문이다.

 

model 객체의 predict() 메서드를 호출하면 최종 출력층의 확률을 반환한다. 하지만 conv_acti의 pridect() 메서드를 호출하면 첫 번째 COnv2D의 출력을 반환한다.

이제 준비를 마쳤으니 특정 맵을 시각화하겠다.


 

 

 

 

특성 맵 시각화

케라스로 패션 MNIST 데이터셋을 읽은 후 훈련 세트에 있는 첫 번째 샘플을 그려보겠다.

 

 

 

 

이 샘플을 conv_acti 모델에 주입하여 Conv2D 층이 만드는 특성 맵을 출력 해보겠다. 크기를 변경하고 255로 나눈다.

 

 

이 코드를 실행하는데 얼마나 어려웠는지 모른다. 수십 번의 실패 끝에 드디어 완성했다. 너무나도 안 돼서 중단했던 코드를 다시 한번 더 시도했더니 이번에는 잘 되고 있다. 역시 사람은 실수와 실패를 통해 많이 배우는 것 같다.

 

 

 

 

이제 맷플롯립의 imshow 함수로 이 특성 맵을 그려보겠다. 32개의 특성 맵이 있으므로 4개의 행으로 나누어 그릴 것이다.

 

이 특성 맵은 32개의 필터로 인해 입력 이미지에서 강하게 활성화된 부분을 보여준다. 앞서 32개 필터의 가중치를 출력한 그림과 비교해 보겠다.

첫 번째 필터는 오른쪽에 있는 수직선을 감지한다. 첫 번째 특성 맵은 이 필터가 감지한 수직선이 강하게 활성화되었다. 세 번째 필터는 전체적으로 밝은 색이므로 전면이 모두 칠해진 영역을 감지한다. 세 번째 특성 맵에서 이를 확인할 수 있다. 

이와 반대로 마지막 필터는 전체적으로 낮은 음수값이다. 이 필터와 큰 양수가 곱해지면 더 큰 음수가 되고 배경처럼 0에 가까운 값과 곱해지면 작은 음수가 될 것이다. 즉 부츠의 배경이 상대적으로 크게 활성화될 수 있다.

 

 

두 번째 합성곱 층이 만든 특성 맵도 값은 방식으로 확인할 수 있다. 

 

 

 

 

 

계속 오류가 떠서 도저히 진행을 할 수 없었다. 이 오류 코드를 고치는데 1시간도 반도 훨씬 넘게 걸렸지만 도무지 풀 길이 없었다. 지금은 그냥 넘어가기로 했다.

 

 

 

 

 

원래 책에 나와있는 코드는 아니지만 다른 방식으로 문제를 해결해 보았다. 아마도 책 저자가 코드를 잘못 쓴 게 분명했다. 이런 코드가 정말 많았다. 제대로 확인을 하고 출판을 했더라면 좋았을 것을.. 책도 오타가 정말 많았지만 다음 판형에서 반영을 한 것 같았다. 그랬다면 코드의 오류도 당연히 있을 거라 생각하고 수정을 했어야 하는데 코드 오류는 수정하지 않은 것 같다.

어쨌든 난 이 단원의 코드를 수정하느라 4시간이 넘는 시간을 허비했다. 


 

 

 

 

단원 마무리하기

 

 

 

 

 

 

이번 8단원에서는 문제가 너무 어려워서 다 틀리거나 겨우 한 문제를 맞는 정도이다. 이번에도 아는 문제는 2번 딱 하나였다. 1번에서는 필터가 원 모양을 따라 높은 값을 가지고 있으므로 동심원 패턴이 많은 이미지에서 가장 크게 활성화될 것이다.

2번은 케라스의 층 객체는 함수처럼 호출할 수 있지만 모델 객체는 함수처럼 호출할 수 없기에 4번이 맞다. 3번에서 2번은 Sequential 클래스의 layer[0]은 첫 번째 은닉층이다. 첫 번째 은닉층의 출력은 두 번째 은닉층의 입력이다. 따라서 답은 2번이다.


 

 

 

학습을 마치고

해결하지 못한 코드가 있어서 마음이 별로 안 좋았다. 딥러닝은 생각보다 많이 어려운 분야였다. 하지만 문제가 생기면 이걸 정말 어떻게 서든 해결하고 싶은 욕구가 생긴다.

아무튼 조금 쉬었다가 다시 딥러닝 공부를 이어가 볼 것이다. 어쨌든 CNN을 공부하기 위한 기초 학습을 모두 마쳤다.

 

다시 이 부분을 공부하며 문제도 풀어보았다. 해결하지 못한 코드는 저자가 잘못 쓴 코드라 지금은 절대로 해결할 수 없는 문제였다. 나중에 딥러닝에 대해 이해력이 높아지면 그때는 반드시 해결할 수 있으리라 믿는다. 가끔은 이렇게 넘어가는 것도 개발자로서의 좋은 자질이다. 그래야 다음이 있기 때문이다.