Yet Never Lose Faith

- Good to Great , Jim Collins

How To Preprocess Image Data 자세히보기

Deep Learning/[Books] Do it! 정직하게 코딩하며 배우는 딥러닝 입문

합성곱 신경망 - 합성곱 연산과 교차상관 연산

Kellyyyy 2020. 11. 12. 08:07

 

 

 

 

이번 포스팅에서는 합성곱신경망을 구현하기 전에 합성곱 연산에 대한 개념을 짚어본다.


합성곱 연산  vs  교차상관 연산

 

합성곱은 두 함수에 적용하여 새로운 함수를 만드는 수학 연산자이다. 두 배열 x와 w가 있을 때, 둘 중 한 배열의 원소 순서를 뒤집은 후 왼쪽 부터 각 배열 원소끼리 곱한 후 더하는 연산이다. 수식으로는 x * w로 표기한다. 

 

 

 

위와 같은 방식으로 끝까지 진행하면 아래와 같이 새로운 배열이 생성된다.

 

[36,48,49,28,21,20] 배열 생성

 

합성곱 연산을 파이썬으로 수행해보자. 원본 배열을 뒤집는 방법은 2가지 정도가 있는데, numpy의 flip() 함수나 파이썬의 슬라이스 연산자를 사용하는 방법이다.

 

import numpy as np
w = np.array([2,1,5,3])
x = np.array([2,8,3,7,1,2,0,4,5])

w_r = np.flip(w)
print(w_r)

w_r = w[::-1]
print(w)

for i in range(6) :
  print(np.dot(x[i:i+4], w_r))
  
# 63
# 48
# 49
# 28
# 21
# 20

 

교차상관 연산과 합성곱 연산의 차이점은 교차상관 연산은 미끄러지는 배열을 뒤집지 않는다는 점이다. (뒤집은 배열을 연산하는 과정을 미끄러진다고 표현한다고 한다.) 

 

합성곱 신경망에서는 합성곱 연산보다 교차상관 연산을 사용한다고 알려져있다. 그 이유는 어차피 모델 초기화 과정에서 가중치 배열을 무작위로 초기화하기 때문에 뒤집는 것이 큰 의미가 없기 때문이다.


Practice! 

 

합성곱 연산과 교차상관 연산을 파이썬으로 구현해보았다.

싸이파이에서는 합성곱을 위한 함수 convolve()와 교차상관을 위한 함수 correlate()를 제공한다.

 

# 합성곱 연산
from scipy.signal import convolve
convolve(x, w, mode='valid')

# array([63, 48, 49, 28, 21, 20])

# 교차상관 연산
from scipy.signal import correlate
correlate(x,w,mode='valid')

# array([48, 57, 24, 25, 16, 39])

 

합성곱 신경망에서는 주로 교차상관 연산자를 사용하므로 이후부터는 correlate()로 예시로 들어보겠다!

 

 

 

correlate()의 파라미터는 총 4개인데, 내가 자세히 살펴볼 파라미터는 세 번째 파라미터 mode이다. mode는 출력값의 사이즈를 결정하는 파라미터이다. full, valid 그리고 same 방식이 있는데 이 차이에 대해서 알아보자.

 

이 세 가지 방식을 이해하기 위해서는 패딩이라는 개념을 알아야한다. 패딩은 원본 배열에 양 끝에 빈 원소를 추가하는 것을 말한다.


Padding

 

1. 밸리드 패딩 (mode = valid)

 

밸리드 패딩은 원본배열에 패딩을 추가하지 않고 미끄러지는 배열이 원본 배열의 끝으로 갈 때까지 교차상관을 수행한다. 지금까지 예시를 든 연산방식이 밸리드 패딩을 적용한 합성곱 및 교차상관 연산이었다.

* 참고로 합성곱 신경망에서 미끄러지는 배열은 합성곱의 가중치, 필터 또는 커널이라고 부른다. 

 

밸리드 패딩의 특징은 출력배열의 크기는 원본배열의 크기보다 항상 작다는 점이다. 또한 원본배열의 원소가 합성곱 연산에 참여하는 정도가 다르다는 특징이 있다. 위 그림을 보면 첫 번째 원소는 연산에 1번만 참여하지만 네 번째 원소는 4번의 연산에 참여한다. 

 

2. 풀패딩 (mode = full)

풀 패딩은 원본 배열의 원소가 연산에 동일하게 참여하도록 하기 위해서 원본 배열에 양 끝에 가상의 원소를 추가한 방식이다. 이때 가상의 원소로는 0을 사용하기 때문에 제로 패딩이라고 부른다. 

 

 

파이썬으로 작성해보자!

correlate(x,w,mode='full')
# array([ 6, 34, 51, 48, 57, 24, 25, 16, 39, 29, 13, 10])

 

3. 세임 패딩 (mode = same)

 

세임패딩은 풀패딩과 동일하게 제로패딩을 추가하지만, 출력배열의 길이가 원본배열의 길이와 같아지도록 추가하는 방식을 말한다. 원본배열의 길이가 9이므로 원본 배열 왼쪽 끝에는 2개, 오른쪽 끝에는 1개의 제로패딩을 추가했다.

 

 

correlate(x,w,mode='same')
# array([34, 51, 48, 57, 24, 25, 16, 39, 29])

 

지금까지는 1차원 배열을 예시로 사용했는데 입력데이터가 2차원 배열인 경우도 합성곱 및 교차상관 연산을 수행할 수 있다.

 

 

 

 

싸이파이의 correlate2d() 함수를 사용하면 2차원 합성곱도 구현할 수 있다.

 

x = np.array([[1,2,3]
              ,[4,5,6]
              ,[7,8,9]])
w = np.array([[2,0],[0,0]])

from scipy.signal import correlate2d
correlate2d(x,w ,mode='valid')
# array([[ 2,  4],
#       [ 8, 10]])

 

만약 same 패딩 방식을 선택했다면 원본 배열의 아래쪽 모서리에 제로 패딩이 추가된다.

 

 

하지만 대부분의 이미지 데이터는 너비, 높이, 채널까지 가진 3차원 배열이다. 입력데이터가 여러개일 때 데이터 번호까지 입력으로 받기 위해서는 4차원 배열을 교차상관 연산 해야한다.

 

입력데이터는 보통 (입력 데이터 수, 샘플의 높이, 샘플의 너비, 컬러 채널의 차원)으로 구성된다.

 

 

 

 

이때 합성곱을 수행하기 위해서는 입력과 곱해지는 가중치도 동일한 차원으로 구성되어야한다. 가중치 배열은 (가중치 너비, 가중치 높이, 채널, 가중치의 개수)로 구성된다. 이때 채널이 여러개인 입력데이터에 대해서 가중치를 합성곱 할 때, 채널 방향으로 가중치가 이동하지는 않는다. 채널은 채널끼리 합성곱 연산이 진행된다!!  

 

 

계산 방식은 아래와 같다.

 

텐서플로의 conv2d()를 이용하면 4차원 배열에 대한 합성곱 연산을 쉽게 할 수 있다. x와 w를 reshape()을 통해 4차원으로 변환한 뒤 세임 패딩을 적용하여 합성곱을 수행했다. 결과값을 편하기 보기 위해서 입력데이터 개수 차원과 컬러차원을 제거하고 (3,3) 크기로 변환하여 출력했다.

 

import tensorflow as tf
x_4d = x.astype(np.float).reshape(1,3,3,1)

# x_4d : array([[[[1.],
#         [2.],
#         [3.]],
#
#        [[4.],
#         [5.],
#         [6.]],
#
#        [[7.],
#         [8.],
#         [9.]]]])

w_4d = w.reshape(2,2,1,1)
c_out = tf.nn.conv2d(x_4d, w_4d, strides=1, padding='SAME')
c_out.numpy().reshape(3,3)

# array([[ 2.,  4.,  6.],
#        [ 8., 10., 12.],
#        [14., 16., 18.]])

 

Reference.

 

도서 <Do it! 정직하게 코딩하며 배우는 딥러닝 입문> 이지스 퍼블리싱, 박해선 지음