Deep Learning

[Deep Learning] Convolutional Neural Network

빛나유 2017. 6. 10. 10:09

오랜만에 포스팅한다. 포스팅을 하다보니까 Data Mining 폴더에 Machine learning 관련된 포스팅을 하게 되고 그러다보니 Deep Learning까지 하게 됐다. 뭔가 분류가 잘 안 맞는 것 같지만 그렇다고 몇 개 있지도 않은 Deep learning 포스팅만 따로 분류하기도 좀 그렇고. 그냥 이렇게 하련다.


오늘은 Convolutional Neural Network에 대해서 이야기해보려고 한다. Convolutional Neural Network은 줄여서 CNN이라고 하고 앞으로 CNN으로 용어 통일하려고 한다.


CNN은 Neural Network의 한 종류이다. 기본적으로 Neural Network가 들어가면 데이터가 이쪽 계층에서 저쪽 계층으로 그리고 그 다음 계층으로 흘러가는 형태의 Network가 있다. 그 Network가 다양한 구조를 하고 있을 수 있는데 CNN도 CNN 나름의 독특한? 구조를 하고 있다. 보통 숲을 보고 나무를 보는 것이 좋은 경우도 있지만 무언가 디테일한 것을 공부할 때는 나무를 보고 숲을 보는 것이 더 좋을 때가 있다. CNN을 이전에 계속 보다가 이해를 못 했었는데 나무를 보고 숲을 보는 전략을 선택하니까 이해가 편하더라. 


이 포스팅에서도 CNN의 나무를 먼저 보고 숲을 보려고 한다. 어짜피 알고리즘은 숫자로 연산하는 과정이다. 그 과정이 무슨 역할인지를 이해하는 것이 중요하긴 하지만 일단 숫자로 연산을 어떻게 하는지(나무 보기) 알아보고 그 연산이 전체 CNN에서 어떤 역할인지를(숲 보기) 알아보자.

CNN의 나무를 보기 위해서 우리는 하나의 데이터를 예시로 보여주려고 한다. 그 데이터는 사진 이미지이다. 사진 이미지는 0부터 256 사이의 숫자로 되어있다. 픽셀 수에 따라서 굉장히 여러 숫자로 이루어진 데이터가 될 수도 있지만 여기에서는 아주 적은 개수의 픽셀로 예를 들어보자. 10x10개의 픽셀 데이터로 해보자.


이 데이터를 가지고 CNN이 어떻게 동작하는지를 알아보려고 한다. 재밌는 숫자놀이를 해보자. 우선 5x5 크기의 랜덤 메트리스 하나를 준비하자. 이 메트리스를 필터1이라고 해보자. 그러면 우리는 필터1을 이용해서 10x10데이터 전체를 스캔해보자. 아래와 같이 스캔해보자.


스캔할 때 연산은 그냥 단순 곱셈과 덧셈이다. 각 숫자를 곱하고 그 곱한 값을 더하여 하나의 숫자로 만들어낸다. 즉 스캔을 한 결과는 하나의 숫자가 된다.


자 고정된 값을 가지고 있는 5x5 메트리스인 필터1을 10x10 메트리스 데이터에 전체적으로 스캔을 돌리면 스캔한 결과가 몇 개가 나올까? 10x10개가 나온다. 스캔을 한 번 하면 그 결과는 숫자 하나이기 때문에 10x10번의 스캔을 하면 10x10 메트리스가 생성된다. 이 메트리스를 스캔1 메트리스라고 하자.


이렇게 나온 스캔1 메트리스에  ReLu 함수를 적용한다. ReLu 함수의 정의는 아래와 같다.

ReLu(x) = max(0, x)


간단한 함수다. x값을 0과 비교해서 둘 중에 큰 값을 리턴해주는 함수이다. ReLu 함수도 숫자 하나에 대해서 숫자 하나를 리턴해주기 때문에 10x10 메트리스에 대해서는 10x10 ReLu 함수 결과가 나온다.

(애초에 데이터가 모두 0보다 큰 데이터들이라 결과는 입력과 똑같다)


이 메트리스를 2x2 메트리스 단위로 요약해보자. 요약이라는 말은 단순히 2x2 메트리스에서 가장 큰 값으로 바꿔보자는 이야기이다. 아래의 그림과 같이 하면 된다.


CNN에서 위와 같은 요약을 풀링이라고(pooling) 한다. 위의 결과는 가장 큰 값으로 요약을 하는, 즉 가장 큰 값으로 풀링을 하는 것이므로, max pooling이라고 한다. 즉 풀링하는 방법에 따라서 min pooling, mean pooling도 있을 수 있다는 것이다.(안 쓰지만)자, 이제 메트리스를 풀링했으니까 이제 5x5로 크기가 줄어들었다. 이 메트리스를 풀링1 메트리스라고 하자.


지금까지 한 과정을 CNN에서 사용하는 용어로 설명해보자. 이미지에 대해서 하나의 필터로 스캔한 것을 Convolve 한다고 한다. 그것에 대해서 ReLu 함수를 적용한 과정은 Activate 한다고 하고, max pooling을 적용하는 부분은 풀링한다고 한다.


이제 위에서 설명한 단순한 숫자놀이가 각각 무엇을 의미했는지 알아보자. 제일 처음에 10x10 데이터는 그저 데이터에 불과하다. (실제 tensorflow 등으로 구현을 할 때는 100 크기의 input을 받아서 10x10으로 reshape해주는 과정을 거친다.) 이 10x10 데이터를 필터1로 쭉 스캔을 해서 10x10 스캔1 메트리스를 얻는다. 이 스캔 결과 메트리스에 ReLu 함수를 적용하여 또 다른 10x10 메트리스를 얻는다. 이 메트리스를 2x2 크기로 풀링을 해서 5x5 크기의 풀링1 메트리스를 얻는다. 이 과정을 그림으로 간략하게 설명해보면 아래와 같다.


일반적으로 CNN에서 필터를 여러 개를 갖는다. 필터1 때문에 스캔1, 풀링1 메트리스가 나왔으니까 필터가 N개 있으면 스캔1부터 스캔 N까지 있을 것이고, 풀링1부터 풀링N까지 있을 것이다.


CNN의 전체적인 그림은 위와 같다. 지금까지 계속 설명을 하면서 필터라는 용어를 사용했는데, 필터라는게 무엇일까? 우리가 지금까지 사용한 5x5 필터는 그 모양이 있는지 확인하는 모양틀 같은 거라고 생각하면 된다. 예를 들어 아래와 같은 필터는 십자가 모양을 확인하는 필터이다.


위의 필터를 이용하여 주어진 그림을 쭉 스캔하면 십자가 모양에 가까운 부분이 있을 수록 스캔 결과가 큰 값이 나올 것이다. (물론 그냥 일반적으로 말한 것 뿐이다) 물론 실제 CNN에서 위와 같이 완벽한 필터를 처음부터 랜덤으로 만들어서 한다는 것은 아니다. 처음에는 필터가 랜덤하게 초기화되지만 트레이닝이 진행되면서 랜덤하게 초기화된 필터가 점점 제 모양을 찾아간다.


지금까지 CNN이 CNN이라고 불릴 수 있는 핵심 부분을 설명했다. 그런데 아직 절반 밖에 설명하지 않았다. Convolution layer 다음에 있는 부분은 아직 설명하지 않았다. 그 다음 부분을 지금부터 설명하려고 한다. 그런데 이 부분 부터는 이미 예전에 자세하게 설명한 부분이다. Fully Connected Layer라고 불리는데 일반적인 input layer, hidden layer, output layer를 가지는 부분이다. 이 부분이 왜 있을까? 실제로 분류를 해주기 위해서이다. CNN은 보통 이미지 분류와 같은 영역에서 큰 성과를 나타낸다. 이미지 분류!! 예를 들어서 어떤 주어진 이미지에 대하여 책이 있다? 없다? 혹은 주어진 그림이 0이다? 1이다? 2다? 3이다? (MNIST 데이터셋) 등등을 분류해야 하기 때문에 Fully Connected Layer를 통해서 실제 분류를 해내는 것이다. 그러면 Fully Connected Layer 이전에 있었던 Convolution Layer는 무슨 역할인가? 주어진 이미지 데이터에 대하여 올바른 피처를 뽑아내는 역할을 하는 것이다. 여기서 말하는 올바른 피처가 N개의 필터를 통해서 검출되는 것이다. 


이것이 CNN의 전부이다. 그런데 여기서 하나 더 알아야 하는 것이 있다. 바로 체널이다. 체널이 무엇이냐? 하나의 데이터를 이루는 층이다. 예를 들어 컬러 사진을 놓고 생각해보자. 보통 R(Red), G(Green), B(Blue) 값으로 하나의 이미지가 세 개의 층을 갖는다. 세 개의 층에 대해서 Convolution Layer, ReLu Layer, MaxPooling Layer를 거치면 어떻게 되는지 숫자로 알아보자.


아래의 예제는 5x5 RGB 이미지에(5x5x3) 대하여 체널 3개를 가지고 있는 3x3 필터 하나를(3x3x3) 적용하여 그 결과로 5x5x1 메트리스를 갖는 과정을 설명한 그림이다.


# 과정


# 결과


위의 그림이 더 명확하다고 생각하지만, 그래도 과정을 설명해보자. 입력 데이터에 대한 R, G, B를 각각 R필터 G필터 B필터와 Convolve한다. 그 결과를 합쳐서 5x5개 중 하나의 결과가 나오는 것이다. 즉 그 과정을 25번 반복해야 최종 결과를 가질 수 있다는 것이다. 위의 결과에 대한 코드는 아래와 같다.


포스팅하는데 진짜 오래 걸렸다. 이것만 하는 것이 아니라 개인적으로 벌려놓은 일이 참 많은데.. 같이 하느라 포스팅이 참 늦어졌다. 게다가 포스팅하다가 갑자기 내용이 헷깔려서 다시 공부하고 하느라.. 그래도 결국은 끝냈다. 다음 포스팅은 RNN과 LSTM 정도가 되지 않을까?