Ch7 합성곱 신경망(CNN)
7.1 전체 구조
CNN = Convolutional Layer + Pooling Layer + Fully Connected Layer
(ex> CONV_1 ⇒ RELU ⇒ CONV_2 ⇒ RELU ⇒ POOL_3 ⇒ DROP_4 ⇒ FLATTEN_5 ⇒ FC_6 ⇒ DROP_7 ⇒ FC_8 ⇒ SOFTMAX )
\(\begin{align*}\end{align*}\)
7.2 합성곱 계층
패딩$\mathsf{^{padding}}$ : 필터 통과 후 데이터 사이즈 조절
스트라이드$\mathsf{^{stride}}$ : 필터가 이동하는 보폭
\(\begin{align*}\end{align*}\)
7.2.1 완전연결 계층의 문제점
완전연결 계층은 입력데이터가 다차원 이더라도 Flatten작업을 통해 그것의 형상을 무시하고 1차원 데이터로 만들어서 학습한다.
때문에 칼라 이미지 데이터처럼 다차원 형상의 데이터인 경우 인접한 데이터끼리 연관이 있을 가능성이 큰데 이를 무시해서 정확도가 더 낮을 수 있다.
반면 CNN은 입력 데이터의 형상을 보존하고 한 번에 데이터 전체를 보는 것이 아니라 부분 부분 필터를 적용하며 합성곱을 하기 때문에 인접한 데이터끼리의 연관성을 파악할 수 있다.
또한, 이러한 점 덕분에 음성 데이터의 처리에도 강점을 보이게 된다.
CNN에서 입출력 데이터를 특징맵$\mathsf{^{feature\ map}}$이라고 한다.
입력 특징 맵$\mathsf{^{input\ feature\ map}}$ : 합성곱 계층의 입력 데이터
출력 특징 맵$\mathsf{^{output\ feature\ map}}$ : 합성곱 계층의 출력 데이터
\(\begin{align*}\end{align*}\)
7.2.2 합성곱 연산
데이터와 필터의 형상을 (높이, 너비)로 표기 한다.
문헌에 따라 필터를 커널이라 칭하기도 한다.
합성곱 연산은 필터의 윈도우를 일정 간격으로 이동해가며 단일 곱셈-누산$\mathsf{^{fused\ multiply-add,\ FMA}}$를 한다.
필터에 매개변수가 그동안의 가중치와 같은 역할을 한다.
편향까지 포함한 흐름이다. 편향은 항상 (1,1)이다.
\(\begin{align*}\end{align*}\)
7.2.3 패딩
패딩 : 합성곱 연산을 수행하기 전에 입력 데이터 주변을 특정 값으로 채우는 것
아래는 zero padding이고 padding_size = 1
입력 데이터 형상 유지에 사용
\(\begin{align*}\end{align*}\)
7.2.4 스트라이드
스트라이드 : 필터가 움직이는 간격
필터 적용시 출력 크기 관계식
입력 크기 : (H, W)
필터 크기 : (FH, FW)
출력 크기 : (OH, OW)
패딩 : P
스트라이드 : S
\[OH={H+2P-FH\over S}+1\\ OW={W+2P-FW\over S}+1\]단, 출력 크기는 모두 정수여야 함.
\(\begin{align*}\end{align*}\)
7.2.5 3차원 데이터의 합성곱 연산
채널까지 고려한 3차원 데이터를 연산해 본다.
입력 데이터와 필터의 합성곱 연산을 채널마다 수행하고, 그 결과를 더해서 하나의 출력을 얻는다.
주의할점
- 입력 데이터의 채널 수 = 필터의 채널 수
- 모든 채널의 필터 크기가 같아야함
\(\begin{align*}\end{align*}\)
7.2.6 블록으로 생각하기
데이터 형상 = (채널, 높이, 너비)
위에서의 결과는 채널이 1개다.
따라서 특징 맵을 여러장 얻기 위해서는 필터를 여러장 사용하면 된다.
필터의 형상 = (필터 수 = 출력 채널 수, 채널 수 = 입력 채널 수, 높이, 너비)
필터를 FN개 만큼 만들어서 합성곱을 하면 출력 데이터의 형상에서 채널 수가 FN개가 된다.
다음은 편향을 적용한 그림 ( 편향은 브로드캐스팅으로 계산됨 )
\(\begin{align*}\end{align*}\)
7.2.7 배치 처리
한번에 여러개의 데이터를 학습하기 위해 배치 처리를 지원하게 하려면
데이터의 차원을 하나 늘려줘야 한다. ( 3차원 ⇒ 4차원 )
데이터 형상 = ( 데이터 수, 채널 수, 높이, 너비 )
정리 : 4차원 데이터가 하나 하른다 → N개에 대한 합성곱 연산이 이뤄진다 = N회 분의 처리를 한 번에 수행한다.
\(\begin{align*}\end{align*}\)
7.3 풀링 계층
세로, 가로 방향의 공간을 줄이는 연산
2X2 최대 풀링을 스트라이드 2로 처리 ( 보통 풀링 윈도우 크기와 스트라이드는 같은 값으로 설정 )
풀링의 종류는 최대 풀링 말고도 평균 풀링 같은 것이 있지만 이미지에서는 주로 최대 풀링 사용
\(\begin{align*}\end{align*}\)
7.3.1 풀링 계층의 특징
\(\begin{align*}\end{align*}\)
1. 학습해야 할 매개변수가 없다
풀링 계층은 오히려 매개변수를 줄인다.
\(\begin{align*}\end{align*}\)
2. 채널 수가 변하지 않는다
풀링 연산을 통해 각 채널의 높이와 너비는 작아져도
채녈마다 독립적으로 계산해서 채널 수는 그대로다.
\(\begin{align*}\end{align*}\)
3. 입력의 변화에 영향을 적게 받는다 ( 강건하다 )
입력 데이터가 조금 변해도 풀리의 결과는 잘 변하지 않는다.
\(\begin{align*}\end{align*}\)
7.4 합성곱 / 풀링 계층 구현하기
\(\begin{align*}\end{align*}\)
7.4.1 4차원 배열
CNN에는 4차원 데이터가 흐른다.
ex> (10, 1, 28, 28) ⇒ 높이 28, 너비 28, 채널 1개인 데이터가 10개
\(\begin{align*}\end{align*}\)
7.4.2 im2col로 데이터 전개하기
합성곱 연산의 가장 간단한 구현 방법은 for 문을 겹겹이 쓰는 것이다.
그렇게하면 numpy의 퍼포먼스가 떨어지기 때문에 좋은 방법이 아니다.
대신 im2col을 사용해서 쉽게 구현 가능하다.
그림은 3차원을 2차원으로 변환한 것이지만
4차원 데이터도 2차원으로 변환시켜준다.
im2col은 필터링하기 좋게 입력 데이터를 전개한다.
여기서는 스트라이드를 크게 잡아 필터의 적용 영역이 겹치지 않도록 했지만,
실제 상황에서는 영역이 겹치는 경우가 대부분이다.
필터 적용 영역이 겹치게 되면 im2col로 전개한 후의 원소 수가 원래 블록의 원소 수보다 많아진다.
그래서 im2col을 사용해 구현하면 메모리를 더 많이 소비하는 단점이 있다.
하지만 행렬 계산에 고도로 최적화된 선형 대수 라이브러리 등을 통해 다시 계산 효율을 높일 수 있다.
입력 데이터도 전개했으므로 필터도 전개해서 행렬 곱을 하면 된다.
CNN은 4차원 데이터가 흐르므로 다시 reshape한다.
ex> (1,3,7,7) — im2col(5,5,stride=1,pad=0) —> (9,75)
결과 ⇒ (입력 데이터 수 * 채널 하나에 들어가는 필터 수) X (필터 사이즈 * 입력 데이터의 채널 수)
class Convolution:
def __init__(self, W, b, stride=1, pad=0):
self.W = W
self.b = b
self.stride = stride
self.pad = pad
# 중간 데이터(backward 시 사용)
self.x = None
self.col = None
self.col_W = None
# 가중치와 편향 매개변수의 기울기
self.dW = None
self.db = None
def forward(self, x):
FN, C, FH, FW = self.W.shape
N, C, H, W = x.shape
out_h = 1 + int((H + 2*self.pad - FH) / self.stride)
out_w = 1 + int((W + 2*self.pad - FW) / self.stride)
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).transpose(0, 3, 1, 2)
self.x = x
self.col = col
self.col_W = col_W
return out
def backward(self, dout):
FN, C, FH, FW = self.W.shape
dout = dout.transpose(0,2,3,1).reshape(-1, FN)
self.db = np.sum(dout, axis=0)
self.dW = np.dot(self.col.T, dout)
self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW)
dcol = np.dot(dout, self.col_W.T)
dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)
return dx
\(\begin{align*}\end{align*}\)
7.4.4 풀링 계층 구현하기
합성곱과 다른점은 채널 독립적이라는 것.
class Pooling:
def __init__(self, pool_h, pool_w, stride=1, pad=0):
self.pool_h = pool_h
self.pool_w = pool_w
self.stride = stride
self.pad = pad
self.x = None
self.arg_max = None
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)
arg_max = np.argmax(col, axis=1)
out = np.max(col, axis=1)
out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)
self.x = x
self.arg_max = arg_max
return out
def backward(self, dout):
dout = dout.transpose(0, 2, 3, 1)
pool_size = self.pool_h * self.pool_w
dmax = np.zeros((dout.size, pool_size))
dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten()
dmax = dmax.reshape(dout.shape + (pool_size,))
dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)
return dx
과정
- 입력 데이터 전개
- 행별 최댓값 계산
- reshape
\(\begin{align*}\end{align*}\)
7.5 CNN 구현
\(\begin{align*}\end{align*}\)
정리
- 데이터 준비
- 데이터 강화 ( flip, move, rotate )
- training data, validation data, test data
- 데이터의 분포가 고르게 나눈다.
- 분류를 하려면 3가지 데이터에 각 클래스가 차지하는 비율이 비슷해야함
- 데이터의 분포가 고르게 나눈다.
- data normalization
- 모델 정의
- 어떤 층을 조합할건지
- 몇 층까지 쌓을건지
- 합성곱층은 filter를 몇개로 할건지, filter size는 몇개로 할건지, padding과 stride는 어떻게 할건지, 활성화 함수는 뭘 쓸건지
- 풀링층은 pooling size를 몇으로 할건지, padding과 stride는 몇으로 할건지
- Dropout은 몇%만큼 뉴런을 막을건지
- 전결합층은 뉴런을 몇개 사용할건지
- Regularization은 뭘로 할건지, 얼마나 할건지
- 모델 학습
- Optimizer는 뭘 사용할건지 learning rate는 몇으로 시작할건지
- batch size 는 몇으로 할지
- epochs는 몇으로 할건지, 조기종료 조건은 어떻게 할건지