* 합성곱 신경망 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/_