본문 바로가기
파이썬 & 머신러닝

[머신러닝 응용] Convolutional layer로 곱을 표현하기

by 두재 2022. 1. 14.

최근 인공 지능이 급부상함에 따라 함께 뜬 유명한 키워드는 CNN일 것입니다. 아마 인공 지능을 조금이라도 공부해보셨다면 CNN을 들어봤을텐데, 정확하게 이해하지 못하고 사용하는 경우도 많을 것이라고 생각합니다. 특히, 점점 인공 지능에 대한 정확한 이해 없이 누구나 쉽고 간편하게 인공 지능 모델을 만들고 테스트할 수 있도록 여러 툴들이 개발되고 간소화되고 있기도 합니다.

 

뉴럴 네트워크에는 그 형태나 사용하는 테크닉에 따라 Convolutional neural network, Recurrent neural network, Graph neural network 등 다양한 이름들이 있는데 사실 정확하게 구분이 되지 않않을때가 많습니다. 어찌 되었건 그 중 가장 널리 알려지고 주로 사용되는 이름이자 분류는 CNN일 텐데요, CNN은 이미지나 영상을 다루는 데에 특화되어 있습니다. 그래서 인공 지능을 이용해 개와 고양이를 구분하거나, 멋있는 그림을 그린다거나, 자율 주행 자동차의 카메라로 찍은 영상에서 사람과 다른 자동차를 구분하는 등 정말 멋있는 일들에 주로 사용됩니다.

 

기본적으로 Convolutional neural networkConvolutional layer를 사용하는 뉴럴 네트워크입니다. 그리고 convolutional layerConvolution operator를 사용하는 layer입니다. Convoltuion은 뉴럴 네트워크 이전에도 원래 신호 처리에서 많이 사용되던 연산입니다. 신호 처리에서 사용되는 컨볼루션에 대해서는 제가 예전에 정리해놓은 글이 있어 링크를 첨부해드립니다.

2019.06.10 - [Matlab] - [이미지처리] 2. 이미지에 각종 효과 적용하기 (Conv2, Spatial filter; Gamma, Blur)

 

[이미지처리] 2. 이미지에 각종 효과 적용하기 (Conv2, Spatial filter; Gamma, Blur)

이미지 처리에는 공간 필터라는 것이 존재합니다. 이번 글에서는 Convolution에 대해 잠깐 소개를 하고 2차원 Convolution에 대해 알아본 후, 매트랩에서 이를 사용해 볼 것입니다. 음성 신호를 필터를

honeyjamtech.tistory.com

 

Convolution & Cross-Correlation

쉽게 정리해보자면, Convolution이란 두 개의 신호가 있을 때 한 신호를 한 칸씩 옮겨가며 두 신호를 곱하고 더하는 연산입니다. 엄밀하게는, Convolution의 식은 다음과 같고 두 개의 함수 fg를 가지고 표현한 어떠한 적분의 형태로 표현됩니다.

convolution 식

주로 f와 g 중 한 개는 신호, 다른 한 개는 kernel 혹은 filter라고 불립니다. 여기서 f와 g를 교환하더라도 같은 값을 가지므로 convolution 연산은 교환 법칙이 성립합니다.

https://glassboxmedicine.com/2019/07/26/convolution-vs-cross-correlation/

사실 전통적인 신호 처리에서 사용되는 Convolution과 인공 지능의 Convolutional Neural Network (CNN)에서의 Convolution은 약간 다릅니다. CNN에서의 Convolution은 사실 Cross-correlation이 맞습니다. Convolution과 Cross-correlation은 굉장히 비슷한데 아주 아주 작은 차이가 있습니다.

Convolution의 식은 다음과 같고

https://tensorflow.blog/2017/12/21/convolution-vs-cross-correlation/

Cross-Correlation의 식은 다음과 같습니다.

https://tensorflow.blog/2017/12/21/convolution-vs-cross-correlation/

보시면 적분에서 g 안에 있는 타우가 플러스냐 마이너스냐로 차이가 있는 것을 볼 수 있습니다. 이 둘을 쉽게 말로 설명해보자면, Convolution은 g라는 신호를 뒤집은 후에 f와 element-wise multiplication을 하고 sum을 하는 과정을 반복하는데 Cross-Correlation은 g라는 신호를 뒤집지 않고 f와 element-wise multiplication을 하고 sum을 하는 과정을 반복합니다.

 

CNN에서의 Convolution

CNN에서 Convolution은 cross-correlation의 형태로 이루어집니다. 그러나 흔히들 convolutional layer라고 말을 하죠. 이는 이제 그냥 편하게 부르게 굳어진 것인데, Convolutional layer가 사실은 cross-correlation처럼 연산을 하지만 실제 convolution이라고 볼수도 있기 때문입니다. 약간 헷갈릴수도 있는데 본질은 cross-correlation과 convolution이 단순히 한 신호를 뒤집느냐 안 뒤집느냐의 차이밖에 없다는 점에 있습니다. 위에서 가져온 f와 g라는 신호를 CNN 상황에 대입을 하자면, f는 이미지 (혹은 feature)이고 g는 Convolutional layer에 있는 weight (=filter)가 되겠죠.

현재는 Convolutional layer가 cross-correlation을 하는 것이라고 제가 설명을 했지만, 이는 layer의 weight를 g라는 함수로 볼 때 그렇게 됩니다. 그런데 만약 layer의 weight를 x와 y 방향으로 뒤집고 이를 g라고 생각한다면 Convolutional layer가 실제로 convolution을 하는 것이 됩니다. 어떻게 보면 말장난처럼 보일 수 있는데, 여기서 결론은 다음처럼 내릴 수 있을 것입니다.

  • 실제 pytorch나 tensorflow와 같은 implementation에서는 convolutional layer가 input과 filter 사이의 cross-correlation을 계산하도록 되어있다.
  • 그런데 사실 layer의 filter를 뒤집어서 그게 그 layer의 filter야! 라고 말한다면 윗줄에서 말한 operation이 cross-correlation에서 convolution이 된다.
  • 실제로 사람들이 layer의 filter를 뒤집어서 말을 하지는 않기 때문에 실제로는 cross-correlation을 하는게 맞는데, 사실 cross-correlation이나 convolution이나 별 차이는 없으니 그렇게 중요한 건 아닐 수 있다.

 

 


 

CNN layer에서 Channel의 개념

CNN의 convolutional layer에는 channel이라는 것을 볼 수 있습니다. 정말 CNN 모델의 첫 convolutional layer라면 이미지를 input으로 받을 때 Grayscale 이미지라면 channel이 1일테고, RGB 이미지라면 channel이 3일 것입니다. 지금까지는 channel의 의미를 어느 정도는 직관적으로 알 수 있습니다.

그런데 convolutional layer를 보면 input_channel과 output_channel이 있고 output_channel은 정말 아무 숫자나 다 됩니다. 또 대부분의 CNN에서는 굉장히 많은 convolutional layer들이 여러 개가 순차적으로 이루어져 있습니다. 이 곳에서는 이제 feature의 channel을 말하는 것이죠. 결국 feature에서 channel의 의미를 알아야 되는데 사실 별 게 없습니다.  channel은 그 feature에서의 각 (x, y)위치에 대한 representation을 몇 차원으로 할 지에 해당합니다. 여기서 (x, y)위치는 feature의 xy 사이즈로 이미지의 xy 위치에 해당하는 좌표는 아닙니다. 만약 channel의 개수가 크면 CNN에서 각 위치에 해당하는 부분을 더욱 고차원의 공간으로 매핑할 수 있으며 그 convolutional layer의 parameter의 개수를 키우고 CNN의 크기를 키워줍니다. 때문에 뉴럴 네트워크가 표현할 수 있는 함수의 다양성이 증가하고 학습이 잘 되었다는 가정 하에 학습 퍼포먼스는 더욱 증가하지만 연산 시간이 오래 걸리고 메모리를 많이 차지합니다.

 

CNN layer 작동 방식

사실 channel의 개념이 조금 어려울 수 있긴 한데, 그러면 Convolutional layer가 어떻게 작동하는지를 살펴봅시다.

https://d2l.ai/chapter_convolutional-neural-networks/channels.html

Convolutional layer는 선언될 때부터 input_channel과 output_channel을 요구하는데 이는 이 두 파라미터가 그 layer의 파라미터의 차원을 결정하기 때문입니다. 위 그림은 input_channel이 2, output_channel이 1인 상황입니다. 이 경우 convolutional layer의 kernel은 xy 방향으로는 2픽셀이고 이러한 2x2 정사각형이 2개가 있습니다. 여기서 2개가 있는 이유는 input_channel이 2이기 때문입니다. 지금은 output_channel이 1이지만, 만약 output_channel이 n이라면 위에 그려져있는 kernel이 n개가 생기고 위 사진에 해당하는 연산을 n번하여 output의 channel 차원이 n개가 됩니다.

여기서 알아야 할 것은 convolutional layer의 한 kernel은 input으로 들어오는 데이터의 channel 정보들을 함께 보고 처리한다는 것입니다. 디테일하게는 input과 kernel의 각 채널별로 convolution (실제로는 cross-correlation)을 하고 각 채널별로 얻은 데이터를 또 더해줍니다. 여기서 보시면 2개의 input channel로부터 output이 만들어지는 과정은 kernel의 원소들과의 곱channel-wise 합이 있습니다.

 

 


두 개의 input channel을 element-wise 곱하고 싶으면?

그렇다면 convolutional layer를 가지고 위 하늘색 그림에서의 두 개의 input channel을 곱한 것을 output으로 내보내고 싶으면 어떻게 해야할까요? (물론 이 경우 padding을 조절하여 output의 xy크기를 동일하게 맞춰야하겠죠.)

바로 exponential 지수 함수를 사용하면 됩니다.

 

우선 그냥 convolutional layer로 실험한 것을 보여드리겠습니다.

실험 세팅은 다음과 같습니다. (Pytorch 기준입니다.)

  1. 두 개의 텐서 a, b를 만든다. 각각은 xy 사이즈가 동일하고 각각 직사각형이 채워져 있다. 직사각형을 채운 값은 둘이 다르다. a와 b의 차원은 다음과 같다. (1, 1, 100, 100).
  2. input data를 다음과 같이 만든다. input=torch.cat((a, b), dim=1). 차원은 다음과 같다. (1, 2, 100, 100).
  3. target을 다음과 같이 만든다. target = a * b. 단순히 a와 b의 element-wise multiplication이다. 차원은 다음과 같다. (1, 1, 100, 100).
  4. Neural network를 단 1개의 convolutional layer로 만든다. nn.Conv2d(2, 1, kernel_size=3, padding=1).
  5. L2 loss를 이용하여 학습을 진행한다. loss = torch.norm((out - (a * b)), p=2)

이 실험에서는 과연 저 convolutional layer가 channel끼리의 element-wise multiplication를 모델링할 수 있는지를 보는 것입니다.

그림을 보면 a와 b가 있고, hadamard product (element-wise multiplication과 같은 말입니다.)인 target이 있고 뉴럴 네트워크 아웃풋이 있습니다. 보시면 타겟과 전혀 안 맞는 것을 알 수 있고, 학습 때 사용하는 로스 값을 찍어보아도 학습이 되지 않는 것을 볼 수 있습니다.

 

다음에는 지수 함수를 이용하는 방법을 소개해드리겠습니다.

위의 실험 과정 중 4번째인 "Neural network를 단 1개의 convolutional layer로 만든다. nn.Conv2d(2, 1, kernel_size=3, padding=1)."를 다음과 같이 바꿉니다.

Neural network는 단 1개의 convolutional layer인데, 그 layer를 통과시킨 후에 추가로 exponential 함수를 통과하도록 한다.

이전에는 다음과 같았다면

out = net(torch.cat((a, b), dim=1)
loss = torch.norm((out - (a * b)), p=2)

지금은 다음과 같은 코드로 되어 있는 것이죠.

out = torch.exp(net(torch.cat((a, b), dim=1))
loss = torch.norm((out - (a * b)), p=2)

아주 미세한 차이지만, exp(a+b) = exp(a) * exp(b)라는 관계를 이용하는 것입니다.

이렇게 하면 Loss 값도 잘 줄어들고, neural network output이 타겟과 똑같아지는 것을 볼 수 있습니다.

 

 


결론

우선은 Convolutional이라는 연산과 CNN에서 convolutional layer의 작동 방식을 살펴 보았고, 작은 사이드 실험으로 convolutional layer가 channel별 정보를 덧셈을 통하여 output을 만든 다는 것을 보았습니다. 만약 channel별 정보의 곱셈이 필요할 경우 사용할 수 있는 exponential 함수를 활용한 트릭도 소개하였고요.

사실 exponential 함수는 특성 상 위에서 설명한 exp를 사용하는 블럭들을 여러 개 사용할 경우 굉장히 불안정할 수 있습니다. 그리고, 사실 첫번째 실험처럼 exp를 사용하지 않더라도 layer가 굉장히 많고 복잡하다면 덧셈들만을 이용하여 곱셈을 표현할 수 있을 것입니다. 물론 완벽한 곱셈을 표현할 수도 없을 뿐더러 고작 곱셈이라는 연산을 위해 너무 많은 것을 요구하겠죠.