본문 바로가기
ML & DL/책 & 강의

[밑시딥1] CHAPTER 7 합성곱 신경망(CNN)

by 공부하는 무니 2023. 6. 26.
반응형

CNN은 이미지 인식과 음성 인식 등 다양한 곳에서 사용되는데, 특히 이미지 인식 분야에서 딥러닝을 활용한 기법은 거의 다 CNN을 기초로 한다.

7.1 전체 구조

CNN에는 합성곱 계층(convolutional layer)과 풀링 계층(pooling layer)이 있다. 

지금까지 본 신경망은 완전연결(fully-connected)이다. 이런 계층은 어파인 계층이라는 이름으로 구현했다. 

완전연결 계층(Affine 계층)으로 이뤄진 네트워크의 예

위 완전연결 신경망은 Affine-ReLU 조합이 4개가 쌓였고, 마지막 5번째 층은 Affine계층에 이어 소프트맥스 계층에서 최종 결과(확률)를 출력한다.

CNN으로 이뤄진 네트워크의 예: 합성곱 계층과 풀링 계층이 새로 추가(회색)

CNN에서는 합성곱 계층과 풀링 계층이 추가된다. CNN 계층은 'Conv-ReLU-(Pooling)' 흐름으로 연결된다(풀링 계층은 생략하기도 한다) 지금까지의 'Affine-ReLU' 연결이 'Conv-ReLU-(Pooling)'으로 바뀌었다고 보면 된다. 

위 그림에서 또 주목할 점은 출력에 가까운 층에서는 Affine-Softmax 조합을 그대로 사용한다는 것이다.

7.2 합성곱 계층

7.2.1 완전연결 계층의 문제점

완전연결 계층의 문제점은 바로 '데이터의 형상이 무시'된다는 것이다. 이미지의 경우 통상 가로,세로,채널(색상) 으로 3차원 데이터인데, 완전연결계층에 입력할 때는 1차원 데이터로 평탄화해줘야 한다. 이미지의 3차원 형상에는 소중한 공간적 정보가 담겨있는데 완전연결 계층은 형상을 무시하게 된다.

합성곱 계층은 형상을 유지한다. 그래서 CNN은 이미지와 같이 형상을 가진 데이터를 제대로 이해할 가능성이 있다. 

CNN에서 합성곱 계층의 입출력 데이터를 특징 맵(feature map)이라고 한다. 

7.2.2 합성곱 연산

합성곱 계층에서의 합성곱 연산은 이미지 처리에서 말하는 필터 연산에 해당한다.

합성곱 연산의 예: 합성곱 연산을 원 안의 *로 표시

필터를 커널이라고 부르기도 한다.

합성곱 연산의 계산 순서

합성곱 연산은 필터의 윈도우를 일정 간격으로 이동해가면서 입력 데이터에 적용한다. 입력과 필터에서 대응하는 원소끼리 곱한 후 그 총합을 구한다.(단일 곱셈-누산 fused multiply-add, FMA) 

완전연결 신경망에는 가중치 매개변수와 편향이 존재했다. CNN에서는 필터의 매개변수가 그동안의 '가중치'에 해당한다. 또한 CNN에서도 편향이 존재하는데, 편향까지 포함하면 아래와 같은 흐름이 된다.

합성곱 연산의 편향: 필터를 적용한 원소에 고정값(편향)을 더한다.

편향은 필터를 적용한 후의 데이터에 더해진다. 편향은 항상 하나(1x1)만 존재한다. 

7.2.3 패딩

합성곱 연산을 수행하기 전에 입력 데이터 주변을 특정 값(ex. 0)으로 채우는 것을 패딩(padding)이라고 한다. 아래 그림은 (4, 4) 크기의 입력 데이터에 폭이 1인 패딩을 적용한 모습이다.

합성곱 연산의 패딩 처리: 입력 데이터 주위에 0을 채운다(패딩은 점선으로 표시했으며 그 안의 값 '0'은 생략했다).

패딩은 주로 출력 크기를 조정할 목적으로 사용한다. 합성곱 연산을 거칠 때마다 크기가 작아지면 어느 시점에서는 출력 크기가 1이 되어버린다. 이는 더 이상은 합성곱 연산을 할 수 없다는 뜻이므로, 이런 사태를 막기 위해 패딩을 사용한다. 위의 그림에서는 패딩을 적용하니 (4, 4) 입력에 대한 출력이 같은 크기인 (4, 4)로 유지될 수 있었다.

7.2.4 스트라이드

필터를 적용하는 위치의 간격을 스트라이드(stride)라고 한다. 

스트라이드가 2인 합성곱 연산

입력 크기를 (H, W), 필터 크기를 (FH, FW), 출력 크기를 (OH, OW), 패딩을 P, 스트라이드를 S라고 하면 출력 크기는 다음 식으로 계산된다.

위 식의 결과가 정수로 나눠떨어지는 값이어야 한다는 점에 주의하자. 출력 크기가 정수가 아니면 오류를 내는 등의 대응을 해주어야 한다. 딥러닝 프레임워크 중에는 값이 딱 나눠떨어지지 않으면 가장 가까운 정수로 반올림하는 등 에러를 내지 않고 진행하도록 구현된 경우도 있다.

7.2.5 3차원 데이터의 합성곱 연산

3차원 데이터 합성곱 연산의 예
3차원 데이터 합성곱 연산의 계산 순서

3차원 합성곱 연산에서 주의할 점은 입력 데이터의 채널 수와 필터의 채널 수가 같아야 한다는 것이다. 모든 채널의 필터의 크기도 같아야 한다. 

7.2.6 블록으로 생각하기

3차원의 합성곱 연산은 데이터와 필터를 직육면체 블록이라고 생각하면 쉽다. 

3차원 데이터를 다차원 배열로 나타낼 때는 (채널, 높이, 너비) 순서로 쓴다. 

합성곱 연산을 직육면체 블록으로 생각한다. 블록의 형상에 주의할 것!

위 예에서 출력 데이터는 채널이 1개인 특징 맵이다. 만약 출력으로 채널이 여러 개인 특징맵을 만드려면 어떻게 해야 할까? 필터를 여러 개 사용하면 된다. 

여러 필터를 사용한 합성곱 연산의 예

따라서 합성곱 연산에서는 필터의 수도 고려해야 하기 때문에 필터의 가중치 데이터는 4차원 데이터이며 (출력 채널 수, 입력 채널 수, 높이, 너비) 순으로 쓴다. 

그리고 합성곱 연산에서도 편향이 쓰인다. 아래 그림은 편향을 더한 모습이다.

합성곱 연산의 처리 흐름(편향 추가)

7.2.7 배치 처리

합성곱 연산도 마찬가지로 배치 처리를 해보자. 각 게층을 흐르는 데이터의 차원을 하나 늘려 4차원 데이터로 저장한다. (데이터 수, 채널 수, 높이, 너비)순으로. 데이터가 N개일 때 배치 처리하면 아래와 같다.

합성곱 연산의 처리 흐름(배치 처리)

각 데이터의 선두에 배치용 차원을 추가했다. 

7.3 풀링 계층

풀링은 세로, 가로 방향의 공간을 줄이는 연산이다. 예를 들어 아래와 같이 2x2영역을 원소 하나로 집약하여 공간 크기를 줄인다.

최대 풀링의 처리 순서

위 그림은 2x2 최대 풀링(max pooling)을 스트라이드 2로 처리하는 처리 순서이다. 최대풀링은 최댓값을 구하는 연산이다. 참고로 풀링의 윈도우 크기와 스트라이드는 같은 값으로 설정하는 것이 보통이다.

최대풀링 외에도 평균 풀링 등이 있다. 이미지 인식 분야에서는 주로 최대 풀링을 사용하므로, 이 책에서 풀링 계층이라고 하면 최대 풀링을 말하는 것이다.

7.3.1 풀링 계층의 특징

학습해야 할 매개변수가 없다. 

- 풀링은 대상 영역에서 최댓값이나 평균을 취하는 등 명확한 처리이므로 특별히 학습할 것이 없다.

채널 수가 변하지 않는다.

- 풀링 연산은 입력 데이터의 채널 수 그대로 출력해서 내보낸다. 채널마다 독립적으로 계산하기 때문이다.

풀링은 채널 수를 바꾸지 않는다.

입력의 변화에 영향을 적게 받는다(강건하다)

- 입력 데이터가 조금 변해도 풀링의 결과는 잘 변하지 않는다. 

입력 데이터가 가로로 1원소만큼 어긋나도 출력은 같다(데이터에 따라서는 다를 수도 있다)

7.4 합성곱/풀링 계층 구현하기

합성곱 계층과 풀링 계층을 파이썬으로 구현해보자. 

7.4.1 4차원 배열

CNN계층 사이를 흐르는 데이터는 4차원이다. 

여기에서 첫 번째 데이터에 접근하려면 x[0]이라고 쓴다. 두 번째 데이터는 x[1]이다.

첫 번째 데이터의 첫 채널의 공간 데이터에 접근하려면 다음과 같이 적는다.

이렇게 CNN은 4차원 데이터를 다루므로 복잡할것 같지만 im2col이라는 트릭이 문제를 단순하게 만들어준다.

7.4.2 im2col로 데이터 전개하기

합성곱 연산을 곧이곧대로 구현하려면 for 문을 겹겹이 써야하는데, im2col로 간단히 구현해보자.

im2col은 입력 데이터를 필터링하기 좋게 전개하는 함수이다. 

(대략적인) im2col의 동작

im2col은 필터링하기 좋게 입력 데이터를 전개한다. 아래 그림과 같이 입력 데이터에서 필터를 적용하는 영역을 한 줄로 늘어놓는다. 이 전개를 필터를 적용하는 모든 영역에서 수행하는 것이 Im2col이다

필터 적용 영역을 앞에서부터 순서대로 1줄로 펼친다.

필터 적용 영역이 겹치면 im2col로 전개한 후의 원소 수가 원래 블록의 원소 수보다 많아진다. 그러면 im2col을 사용하면 메모리를 더 많이 소비하는 단점이 있다. 그러나 컴퓨터는 큰 행렬을 묶어서 계산하는 데 탁월하다. 따라서 문제를 행렬 계산으로 만들면 여러 라이브러리를 활용해 효율을 높일 수 있다. 

im2col로 입력 데이터를 전개한 다음에는 합성곱 계층의 필터를 1열로 전개하고, 두 행렬의 곱을 계산하면 된다. 

합성곱 연산의 필터 처리 상세 과정: 필터를 세로로 1열로 전개하고, im2col이 전개한 데이터와 행렬 곱을 계산한다. 마지막으로 출력 데이터를 변환(reshape)한다.

위와 같이 im2col 방식으로 출력한 결과는 2차원 행렬이다. CNN은 데이터를 4차원 배열로 저장하므로 2차원인 출력 데이터를 4차원으로 reshape한다. 

7.4.3 합성곱 계층 구현하기

7.4.4 풀링 계층 구현하기

7.5 CNN 구현하기

합성곱 계층과 풀링 계층을 조합하여 손글씨 숫자를 인식하는 CNN을 구현하자.

단순한 CNN의 네트워크 구성

위 그림의 CNN 네트워크는 Convolutional-ReLU-Pooling-Affine-ReLU-Affine-Softmax 순으로 흐른다. 이를 SimpleConvNet이라는 이름의 클래스로 구현해보자.

 

7.6 CNN 시각화하기

7.6.1 첫 번째 층의 가중치 시각화하기

앞에서 MNIST데이터셋으로 학습한 CNN의 첫 번째 층의 합성곱 계층의 가중치: (30, 1, 5, 5) 

필터 30개, 채널 1개, 5 x 5 크기. 채널이 1개라는 것은 필터를 회색조 이미지로 시각화할 수 있다는 것이다. 

합성곱 계층의 필터(1층째)를 이미지로 나타내보자.

# coding: utf-8
import numpy as np
import matplotlib.pyplot as plt
from simple_convnet import SimpleConvNet

def filter_show(filters, nx=8, margin=3, scale=10):
    """
    c.f. https://gist.github.com/aidiary/07d530d5e08011832b12#file-draw_weight-py
    """
    FN, C, FH, FW = filters.shape
    ny = int(np.ceil(FN / nx))

    fig = plt.figure()
    fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)

    for i in range(FN):
        ax = fig.add_subplot(ny, nx, i+1, xticks=[], yticks=[])
        ax.imshow(filters[i, 0], cmap=plt.cm.gray_r, interpolation='nearest')
    plt.show()


network = SimpleConvNet()
# 무작위(랜덤) 초기화 후의 가중치
filter_show(network.params['W1'])

# 학습된 가중치
network.load_params("params.pkl")
filter_show(network.params['W1'])

학습 전과 후의 1번째 층의 합성곱 게층의 가중치: 가중치의 원소는 실수이지만, 이미지에서는 가장 작은 값(0)은 검은색, 가장 큰 값(255)은 흰색으로 정규화하여 표시함

학습 전 필터는 무작위로 초기화되고 있어서 규칙성이 없다. 그러나 학습을 마친 필터는 규칙성 있는 이미지가 나온다. 

어떤 규칙성..? 해당 필터는 무엇을 보고 있는가? -> 엣지와 블롭(국소적으로 덩어리진 영역) 등을 보고 있다.

가로 엣지와 세로 엣지에 반응하는 필터: 출력 이미지 1은 세로 엣지에 흰 픽샐이 나타나고, 출력 이미지2는 가로 엣지에 흰 픽셀이 많이 나온다.

위 그림은 학습된 필터 2개를 선택해서 입력 이미지에 합성곱 처리를 한 결과이다. 

7.6.2 층 깊이에 따른 추출 정보 변화

첫번째 층의 합성곱 계층에서는 엣지나 블롭과 같은 저수준의 정보가 추출된다고 본다면, 겹겹이 쌓인 CNN의 계층에서는?

-> 계층이 깊어질수록 추출되는 정보(정확히 말하자면, 강하게 반응하는 뉴런)는 더 추상화된다.

CNN의 합성곱 계층에서 추출되는 정보. 1번쨰 층은 에지와 블롭, 3번째 층은 텍스처, 5번째 층은 사물의 일부, 마지막 완전연결계층은 사물의 클래스에 뉴런이 반응한다.

처음 층은 단순한 엣지에 반응하고, 이어서 텍스처에 반응하고, 층이 깊어질수록 더 복잡한 사물의 일부에 반응하도록 변화한다. 즉 뉴런이 반응하는 대상이 단순한 모양에서 고급 정보로 변화해간다. 사물의 '의미'를 이해하도록 변화하는 것.

7.7 대표적인 CNN

LeNet: CNN 원조

AlexNet: 딥러닝이 주목받도록 이끌었음!

7.7.1 LeNet

LeNet은 손글씨 숫자를 인식하는 네트워크로, 1998년에 제안되었다. 

LeNet의 구성

합성곱 게층과 풀링 계층(정확히는 단순히 '원소를 줄이기'만 하는 서브샘플링 계층)을 반복하고, 마지막으로 완전연결 계층을 거치면서 결과를 출력한다.

LeNet과 (현재의) CNN을 비교하면 다음과 같다.

- 활성화 함수. LeNet은 시그모이드 함수, CNN은 ReLU

- LeNet은 서브샘플링을 해서 중간 데이터의 크기를 줄이지만, 현재 CNN은 최대 풀링이 주류이다.

7.7.2 AlexNet

LeNet 보다는 훨씬 최근인 2012년에 발표된 AlexNet.

AlexNet의 구성

AlexNet은 합성곱 계층과 풀링 계층을 거듭하다가 마지막으로 완전연결 계층을 거쳐 결과를 출력합니다. LeNet에서 큰 구조는 바뀌지 않지만, AlexNet에서는 아래와 같은 변화를 주었다.

- 활성화 함수로 ReLU를 사용한다.

- LRN(Local Response Normalization)이라는 국소적 정규화를 실시하는 계층을 이용한다.

- 드롭아웃을 사용한다.

 

네트워크 구성 면에서는 LeNet과 AlexNet에 큰 차이는 없다. 변한 것이 있다면 이를 둘러싼 환경과 컴퓨터 기술의 진보이다. 빅데이터와 GPU 보급으로 인해 딥러닝이 크게 발전하였다.

7.8 정리

  • CNN은 지금까지의 완전연결 계층 네트워크에 합성곱 계층과 풀링 계층을 새로 추가한다.
  • 합성곱 계층과 풀링 계층은 im2col (이미지를 행렬로 전개하는 함수)을 이용하면 간단하고 효율적으로 구현할 수 있다.
  • CNN을 시각화해보면 계층이 깊어질수록 고급 정보가 추출되는 모습을 확인할 수 있다.
  • 대표적인 CNN에는 LeNet과 AlexNet이 있다.
  • 딥러닝의 발전에는 빅 데이터와 GPU가 크게 기여했다.
반응형

댓글