* 합성곱 신경망 Convolutional neural network, CNN *

- 이미지 인식 분야에서 딥러닝을 활용한 기법은 거의 다 CNN을 기초로 함


7.1 전체 구조

- CNN도 이전 신경망과 같이 레고 블록처럼 계층을 조합하여 만들 수 있다

- 합성곱 계층 convolutional layer풀링 계층 pooling layer가 등장

- 기존의 신경망은 인접하는 계층의 모든 뉴런과 결합 = 완전연결 fully-connected 이라고하고, 완전히 연결된 계층을 Affine 계층이라는 이름으로 구현

   - 아래와 같이 Affine 계층 뒤에 활성화 함수를 갖는 ReLU(또는 sigmoid) 계층으로 이어짐

- CNN의 구조 : 합성공 계층과 풀링 계층이 추가됨

   - Conv-ReLU-(Pooling) 흐름, 풀링 계층은 생략되기도 함

   - 출력에 가까운 층에서는 Affine-ReLU 구성을 사용할 수 있음

   - 마지막 출력 계층에서는 Affine-Softmax 조합을 그대로 사용


7.2 합성곱 계층

7.2.1 완전연결 계층의 문제점

- 완전연결 계층에 입력할 때는 3차원 데이터를 평평한 1차원 데이터로 평탄화 -> 데이터의 형상 무시

   - MNIST 데이터셋 1 x 28 x 28  -> 1줄로 세운 784개 데이터를 입력으로..

- 완전연결 계층은 형상을 무시하고 모든 이력 데이터를 동등한 뉴런(같은 차원의 뉴런)으로 취급하여 형상에 담긴 정보를 살릴 수 없다.

- 합성곱 계층은 형상을 유지!!

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

   - 입력 데이터를 입력 특징 맵(input feature map IFM)

   - 출력 데이터를 출력 특징 맵(output feature map OFM)

7.2.2 합성곱 연산 (이미지 처리에서 말하는 필터 연산)

- 합성곱 연산은 입력 데이터에 필터를 적용한다. (필터는 커널이라고도 한다.)

- 필터의 윈도우를 일정 간격으로 이동해가며 입력 데이터에 적용

- 입력과 필터에서 대응하는 원소끼리 곱한 후 그 총합을 구한다 = 단일 곱센-누산(fused multiply-add, FMA)

- 위의 예 : 15 = 1*2 + 2*0 + 3*1 + 0*0 + 1*1 + 2*2 + 3*1 + 0*0 + 1*2

- 그 결과를 출력의 해당 장소에 저장, 이 과정을 모든 장소에서 수행하면 합성곱 연산의 출력 완성

- 완전연결 신경망에는 가중치 매개변수와 편향이 존재

- CNN에서는 필터의 매개변수가 그동안의 가중치에 해당, 편향도 존재함. 포함하면 아래와 같음

※ 합성곱 효과

- 필터는 그 특징이 데이타에 있는지 없는지를 검출

- 위의 곡선과 비슷한 특징들을 추출

7.2.3 패딩

- 합성곱 연산을 수행하기 전에 입력 데이터 주변을 특정 값(예컨대 0, zero padding)으로 채우기도 한다. = 패딩 padding

- 패딩의 목적 : 출력 크기 조정

   - (4, 4) 입력 데이터에 (3, 3) 필터를 적용하면 OFM은 (2, 2)가 된다 -> 합성곱을 거칠 때마다 크기가 작아져 어느 시점에서는 1이 될거다.

  - 이러한 사태를 막기위해, 입력 데이터의 공간적 크기를 고정한 채로 다음 계층에 전달할 수 있다.

7.2.4 스트라이드

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

- 이전에 본 건 스트라이드 1

- 스트라이드를 키우면 출력 크기가 작아짐, 패딩을 크게하면 출력 크기가 커짐

- 이러한 관계에서 OFM 크기를 구하는 걸 수식화하면?

   - (4, 4) 입력 데이터에 (3, 3) 필터를 패딩 0, 스트라이드 1로 적용하면 OFM은 (2, 2)가 된다

   - 

   - 딥러닝 프레임워크 중에는 값이 딱 나누어 떨어지지 않을 때, 가장 가까운 정수로 반올림 하는 경우도 있다.

※ 움직이는 데모 : http://cs231n.github.io/convolutional-networks/

http://aikorea.org/cs231n/convolutional-networks/

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

- 채널 방향으로 특징 맵이 늘어남

- 계산순서

- 입력 데이터의 채널 수와 필터의 채널 수가 같아야 한다!!

http://taewan.kim/post/cnn/

7.2.6 블록으로 생각하기

- 3차원의 합성곱 연산은 데이터와 필터를 직육면체 블록으로 생각하면 쉽다!

- 3차원 데이터를 다차원 배열로 나타낼 때는 (채널, 높이, 너비) 순서로 쓴다. (C, H, W), 필터도 (C, FH, FW)

- 출력 데이터를 한 장의 OFM... = 채널이 1장인 OFM -> 출력으로 다수의 채널을 내보려면? 필터를 여러개 사용!!

- 즉, 필터의 갯수가!!!!!! OFM의 채널수가 된다!!!!!!!!

- 이 완성된 블록을 다음 계층으로 넘기겠다는 것이 CNN의 처리 흐름

- 필터의 수도 고려 = 4차원 데이터 (출력 채널 수, 입력 채널 수, 높이, 너비)

   - 채널 수 3개, 크기 5x5 필터가 20개 있다면 (20, 3, 5, 5)

- 편향은? 채널 하나에 값 하나씩 (FN, 1, 1),  (FN, OH, OW) 블록의 대응 채널의 원소 모두에 더해짐

7.2.7 배치 처리 (입력 데이터를 한 덩어리로 묶어 배치 처리)

- 각 계층에 흐르는 데이터의 차원을 하나 늘려 4차원 데이터로 저장 = (데이터 수, 채널 수, 높이, 너비) 순으로 저장

- 신경망에 4차원 데이터가 하나 흐를 때마다 데이터 N개에 대한 합성곱 연산이 이뤄진다 = 즉 N회 분의 처리를 한 번에 수행


7.3 폴링 계층

- 풀링 : 세로, 가로 방향의 공간을 줄이는 연산

- 최대 풀링(max pooling) : 최대값을 구하는 연산, 2x2 대상 영역에 대하여 가장 큰 원소를 꺼냄

- 풀링의 윈도우 크기와 스트라이드는 같은 값으로  설정하는 것이 보통

- 평균 풀링(average pooling) : 대상 영역에서 평균을 계산. 주로 이미지 인식 분야에서는 최대 풀링을 사용함

- 풀링 계층의 특징

   1. 풀링 계층은 합성곱 계층과 달리 학습해야 할 매개 변수가 없다. 대상 영역에서 취하는 명학한 처리!

   2. 채널 수가 변하지 않는다. 입력 데이터 채널 수가 3이라면 풀링 후 출력 데이터의 채널 수도 3이다

   3. 입력의 변화에 영향을 적게 받는다(강건하다). 입력 데이터가 조금 변해도 풀링의 결과는 잘 변하지 않는다.


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

7.4.1 4차원 배열

- 데이터 형상 (10, 1, 28, 28) = 높이 28, 너비 28, 채널 1개인 데이터가 10개

>>> x = np.random.rand(10, 1, 28, 28)

>>> x.shape

(10, 1, 28, 28)

>>> x[0].shape  # 10개 중 첫 번째 데이터에 접근하기

(1, 28, 28)

>>> x[0, 0] # 또는 x[0][0] # 첫 채널의 공간 데이터에 접근하기

7.4.2 im2col로 데이터 전개하기

- 합성곱 연산을 곧이곧대로 구현하려면 for문을 겹겹이 써야하겠지... 귀찮.. 성능도 떨어져.. 대신 im2col 사용

- im2col는 입력 데이터를 필터링하기 좋게 전개하는(펼치는) 함수

- im2col : image to column, 이미지에서 행렬로..

- 3차원 입력 데이터에 im2col을 적용하면 2차원 행렬로 바뀜

- im2col은 필터링하기 좋게 입력 데이터를 전개한다. 그림 7-18 을 보자..

- 전개한 다음에는 합성곱 계층의 필터를 1열로 전개하고 두 행렬의 곱을 계산한다.

- 결과도 2차원 행렬이니 출력 데이터를 4차원으로 변형(reshape)한다.

7.4.3 합성곱 계층 구현하기

- 이 책에서는 im2col 함수를 미리 만들어서 제공 (common/util.py)

def im2col(input_data, filter_h, filter_w, stride=1, pad=0):

    """다수의 이미지를 입력받아 2차원 배열로 변환한다(평탄화).

    

    Parameters

    ----------

    input_data : 4차원 배열 형태의 입력 데이터(이미지 수, 채널 수, 높이, 너비)

    filter_h : 필터의 높이

    filter_w : 필터의 너비

    stride : 스트라이드

    pad : 패딩

    

    Returns

    -------

    col : 2차원 배열

    """

- im2col 테스트

x1 = np.random.rand(1, 3, 7, 7)  # 7x7에 채널 3

col1 = im2col(x1, 5, 5, stride=1, pad=0)

print(col1.shape)


x2 = np.random.rand(10, 3, 7, 7)  # 배치 크기 10

col2 = im2col(x2, 5, 5, stride=1, pad=0)

print(col2.shape)

------------------------ 필터 크기 스트라이드 패딩을 고려하여 2차원 배열로 전개...

(9, 75)  # 2번째 차원의 원소수는 75로 필터의 원소수와 같다(3 x 5 x 5)

(90, 75)

- 합성곱 계층 클래스

class Convoultion:

def __init__(self, W, b, stride=1, pad=0):

self.W = W

self.b = b

self.stride = stride

self.pad = pad


def forware(self, x):

FN, C, FH, FW = self.W.shape

N, C, H, W = x.shape

out_h = int(1 + (H + 2*self.pad - FH) / self.stride)

out_w = int(1 + (W + 2*self.pad - FW) / self.stride)


                # IFM랑 Filter랑 계산 할 수 있게 각자 전개하고 dot으로 계산함

col = im2col(x, FH, FW, self.stride, self.pad)

col_W = self.W.reshape(FN, -1).T  # 필터 전개

out = np.dot(col, col_W) + self.b


                # 다시 형태 돌리기

out = out.reshape(N, out_h, out_w, -1).tanspose(0, 3, 1, 2)


return out

- reshape에 -1을 지정하면 다차원 배열의 원소 수가 변환 후에도 똑같이 유지되도록 적절히 묶어준다... (10, 3, 5, 5)의 원소 수 는 총 750개, reshape(10, -1)을 호출하면 750개의 원소를 10묶으로, 즉 형상이 (10, 75)인 배열로 만들어준다.

- 출력 데이터 형태 바꾸기 위해 transpose 호출, 다차원 배열의 축 순서를 바꿔주는 함수.. (N, H, W, C) 는 인덱스 (0, 1, 2, 3) 인데 이걸 (N, C, H, W)로 바꿔주려면 (0, 3, 1, 2)

- 이상 forward, backward는 common/layer.py 참고;;

7.4.4 풀링 계층 구현하기

- im2col을 사용해서 입력데이터를 전개하지만, 채널 쪽이 독립적

- 이렇게 전개한 행렬에서 행별 최댓값을 구하고 적절한 형상으로 성형

class Pooling: 

....

    def forward(self, x):

        N, C, H, W = x.shape

        out_h = int(1 + (H - self.pool_h) / self.stride)

        out_w = int(1 + (W - self.pool_w) / self.stride)

        # 전개

        col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)

        col = col.reshape(-1, self.pool_h*self.pool_w)

 ...

        # 최대값

        out = np.max(col, axis=1)  # 2차원 배열에서 axis=0은 열방향, axis=1은 행방향

        out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)

...


7.5 CNN 구현하기

- 합성곱 계층과 풀링 계층 조합해서 CNN 조립하기

- ch07/simple_convnet.py : conv - relu - pool - affine - relu - affine - softmax

- ch07/train_convnet.py : CNN으로 MNIST 데이트셋 학습 후 정확도


7.6 CNN 시각화하기

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

- 위의 예제에서 합성곱의 필터는 (30, 1, 5, 5), 필터 30개, 채널 1개 5x5 크기

- 필터의 크기가 5x5이고 채널이 1개라는 것은 이 필터를 1채널의 회색조 이미지로 시각화 할 수 있다는 뜻

- ch07/visualizee_filter.py

- 1번째 층 무엇을 보는 걸까? 에지(색상이 바뀐 경계선)와 블롭(blob, 국소적으로 덩어리진 영역) 등을 보고 있다.

- 예 : 가로 에지와 세로 에지에 반응하는 필터.. 흰 픽셀이 많이 나옴

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

- 계층이 깊어질 수로고 추출되는 정보(정확하는 반응하는 뉴런)는 더 추상화된다.

- 1번째 층은 에지와 블롭, 3번째 층은 텍스처, 5번째 층은 사물의 일부, 마지막 완전연결 계층은 사물의 클래스(개, 자동차 등)에 뉴런이 반응한다.

- 층이 깊어지면서 더 복잡하고 추상화된 정보가 추출된다.. 뉴런이 반응하는 대상이 단순한 모양에서 고급정보로 변화해간다. = 의미 이해


7.7 대표적인 CNN

7.7.1 LeNet

- 손글씨 숫자를 인식하는 네트워크로 1998년에 제안됨

- 합성곱 계층과 풀링 계층(원소를 줄이기만 하는 서브샘플링)을 반복하고 마지막으로 완전연결 계층을 거치면서 결과 출력

- LeNet의 활성화함수 는 시그모이드, 오늘날에는 ReLU..

7.7.2 AlexNet

- 2012년 발표됨

- 합성곱 계층과 풀링 계층을 거듭하고 마지막에 완전연결은 LeNet 구조와 같으나

- 활성화 함수로 ReLU 사용, LRN(Local response normalizaion)이라는 국소적 정규화를 실시하는 계층을 이용, 드랍아웃을 사용


- 다른 네트워크 8장에 조금 소개되는듯








- 로드맵

https://www.mindmeister.com/ko/812276967/_


+ Recent posts