Deep learning/모델 구현

17. CNN(4) - 합성곱/풀링 계층 구현하기

jwjwvison 2021. 4. 25. 09:10

이 포스팅은 밑바닥부터 시작하는 딥러닝을 공부하고 정리한것 입니다.


1. 4차원 배열

 CNN에서 계층 사이를 흐르는 데이터는 4차원이다. 예를 들어 데이터의 형상이 (10,1,28,28)이면, 이는 높이 28,너비 28, 채널 1개인 데이터가 10개라는 이야기이다.

 

 

2. im2col로 데이터 전개하기

 im2col은 입력 데이터를 필터링(가중치 계산) 하기 좋게 전개하는 함수이다. 아래 그림과 같이 3차원 입력 데이터에 im2col을 적용하면 2차원 행렬로 바뀐다. 정확히는 배치 안의 데이터 수까지 포함한 4차원 데이터를 2차원으로 변환한다.

구체적으로는 입력 데이터에서 필터를 적용하는 영역(3차원 블록)을 한줄로 늘어놓는다.

 위 그림에서는 보기 좋게끔 스트라이드를 크게 잡아 필터의 적용 영역이 겹치지 않도록 했지만, 실제 상황에서는 영역이 겹치는 경우가 대부분이다. 필터 적용 영역이 겹치게 되면 im2col로 전개한 후의 원소 수가 원래 블록의 원소 수보다 많아진다. 그래서 im2col을 사용해 구현하면 메모리를 더 많이 소비하는 단점이 있다.

 

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

 위 그림과 같이 im2col 방식으로 출력한 결과는 2차원 행렬이다. CNN은 데이터를 4차원 배열로 저장하므로 2차원인 출력 데이터를 4차원으로 변형한다. 이상이 합성곱 계층의 구현 흐름입니다.

 

3. 합성곱 계층 구현하기

import sys,os
sys.path.append(os.pardir)
from common.util import im2col

x1=np.random.rand(1,3,7,7)
col1=im2col(x1,5,5,stride=1,pad=0)
print(col1.shape)

class Convolution:
    def __init__ (self,W,b,stride=1,pad=0):
        self.W=W
        self.b=b
        self.stride=stride
        self.pad=pad
        
    def forward(self,x):
        FN,C,FH,FW=self.W.shape
        N,C,H,W=x.shape
        out_h=int(1+(H+2*self.pad-FW)/self.stride)
        out_w=int(1+(W+2*self.pad -FW)/self.stride)
        
        col=img2col(x,FH,FW,self.stride,self.pad)
        col_@=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)
        
        return out

 

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
        
    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)
        
        # 전개(1)
        col=im2col(x,self.pool_h,self.pool_W,self.stride,self.pad)
        col=co.reshape(-1,self.pool_h+self.pool_w)
        
        #최대값 (2)
        out=np.max(col,axis=1)
        
        #성형(3)
        out=out.reshape(N,out_h,out_w,C).transpose(0,3,1,2)
        
        return out