im2col (Image to Column)

CNN은 3차원의 데이터 (주로 이미지)를 학습시키는데 특화되어있는 신경망이다.

차원이 큰 데이터에 대해서도 정보를 잃지 않기 위해 합성곱을 사용하기 때문에 for문을 여러개를 사용해야 한다.

 

import numpy as np

x=np.array([[[1,2,3,0],
                [0,1,2,3],  # --> red 행렬
                [3,0,1,2],
                [2,3,0,1]],
              [[2,3,4,1],
               [1,2,3,4],  # --> green 행렬
               [4,1,2,3],
              [3,4,1,2]],
             [[3,4,5,2],  # --> blue 행렬
              [2,3,4,5],
              [5,2,3,4],
              [4,5,2,3]]])

print (x.ndim)  # 3
print (x.shape)  # (3,4,4)  (차원,행,열)

f=np.array([[[2,0,1],
               [0,1,2],
               [1,0,2]],
               [[3,1,2],
                [1,2,3],
                [2,1,3]],
                [[4,2,3],
                [2,3,4],
                [3,2,4]]])

print ( f.ndim )  #  3
print ( f.shape ) #  ( 3, 3, 3 )

output = np.zeros([x.shape[1]-f.shape[1]+1,x.shape[2]-f.shape[2]+1])

fh,fw = f.shape[1], f.shape[2]

for i in range(output.shape[0]):
    for j in range(output.shape[1]):
        for k in range(x.shape[0]) :
            output[i,j]+=np.sum(x[k][i:fw+i,j:fh+j]*f[k])
            
print(output)

 

위의 함수를 보다시피, for문을 여러번 사용해야 합성곱 연산을 할 수 있다. 하지만 이런 식이라면 연산 속도가 매우 떨어질 것이다.

수만건의 데이터를 처리해야하는 CNN은 이러한 연산속도 저하 문제를 어떻게 해결할까?

 

그에 대한 해결이 im2col 함수이다.

 

3차원 데이터를 im2col 함수에 넣은 후의 출력 데이터

위의 이미지는 im2col의 동작을 단적으로 보여주고 있다. im2col은 쉽게 말해서 다차원의 데이터를 행렬로 변환하여 행렬 연산을 하도록 해주는 함수를 말한다.

다차원 데이터의 합성곱(convolution)은 im2col을 통해 행렬로 변환된 데이터의 내적과 같다.

 

 

 

합성곱 계층(Convolution Layer)에서의 im2col

여기 (7,7,3) 인 입력데이터와 (5,5,3)인 필터가 있다고 하자. C는 RGB로 3이다.

 

 

우리는 원래대로라면 이 3차원 입력데이터와 필터에 대해 합성곱을 진행해야 한다. 하지만 im2col을 사용하면 행렬의 내적으로 합성곱과 같은 결과를 낼 수 있다.

어떻게 3차원 데이터를 2차원 행렬로 변환시킬 수 있을까?

 

7x7xC 입력 데이터는 필터에 의해 9개로 나눠진다.

 

위의 그림이 우리가 기본적으로 알고 있던 합성곱에 대한 개념이다. 입력 데이터(7,7,3)는 필터 사이즈(5,5,3)만큼 가로로 3번, 세로로 3번 총 9개(3x3)로 나뉘어 필터와 합성곱 연산을 한다. 아래는 9개로 나뉜 데이터의 사이즈(filter 사이즈와 같음)를 함께 보여주는 그림이다.

 

9개로 나뉜 데이터의 size는 (5,5,3)으로 filter size와 같다.

 

filter size만큼 나뉘어진 원본 데이터를 행렬로 변환하면 다음과 같다.

 

 

 

입력 데이터는 필터에 의해 총 9개의 데이터로 쪼개졌고, 그 데이터 하나 하나를 행렬로 만들어 준다. 쪼개진 데이터는 (5,5,3)의 크기를 갖고 이것을 행렬로 만들면 세로는 1(데이터 1개라는 의미), 가로는 5x5xC의 크기로, 행렬 1개(1,5x5xC)로 3차원의 데이터를 나타낼 수 있다.

 

입력데이터를 im2col로 변환한 최종 결과 행렬

 

이러한 과정을 쪼개진 데이터 개수인 9만큼을 반복해서 나타낸 행렬은 입력 데이터에 대한 정보를 모두 갖게 된다.

이 과정을 filter에 대해서도 진행한다.

 

filter에 대해서 im2col을 진행한 결과 행렬

 

우리는 (5,5,C)의 모양을 가진 필터 하나를 사용하기 때문에 im2col을 진행하면 행렬 1개가 나온다.

 

 

3차원의 데이터를 합성곱하는 결과는 각각의 데이터를 im2col 함수를 사용해 모든 데이터를 잃지 않으면서 2차원 행렬로 변환시켜 행렬연산을 진행하는 것과 같은 결과를 도출한다. 컴퓨터는 행렬 연산에 매우 특화되어 있기 때문에 im2col을 사용하여 행렬 연산을 진행하면 비록 연산해야하는 데이터 수는 늘어났지만(원래는 입력데이터가 1개 뿐이었지만 입력데이터 1개를 9개로 나눴기 때문에 연산해야하는 데이터 수는 결과적으로 늘었다.) 연산 속도는 빠르다. 하지만 연산해야하는 데이터 수가 늘어났기 때문에 연산 메모리가 증가한다는 단점도 존재한다.

 

im2col로 변환한 데이터와 필터의 연산 과정

 

이렇게 행렬로 변환한 입력 데이터와 필터의 행렬 연산 이후, 우리는 출력된 데이터(행렬)를 다시 원래의 데이터(3차원)로 변환해주는 작업을 한다.

이러한 흐름이 합성곱 계층의 구현 흐름이다.

 

그리고 더 정확하게 말하자면 데이터들은 정확히는 3차원이 아니라 4차원이다. 여기를 보면 알다시피 입력 데이터는 (N,C,H,W)로 구성되어있으며 N은 데이터의 갯수를 의미하는 배치 사이즈를 뜻한다. 따라서 정확히는 입력 데이터와 filter 데이터, 출력 데이터 모두 4차원이지만 이해를 돕기위해 입력 데이터 1개와 필터 1개를 예시로 하여 3차원으로 설명하였으니 오해가 없길 바란다.

 

 

+ Recent posts