1. Upsampling w/ Interpolation Methods
데이터의 효율적인 연산을 위해 차원을 축소하는 과정을 'Downsampling'이라고 하고,
반대로 데이터의 크기를 역으로 늘리는 (차원을 확대하는) 과정을 'Upsampling'이라 한다.
Upsampling을 이용하면 Feature Map에서 시작하여 이미지를 생성할 수 있다. 이때, Upsampling 과정 중 추가로 데이터를 생성하는 방법도 여러가지가 있는데, 이를 보간법이라 한다.
보간법(interpolation)에는 크게 4가지의 종류가 있다.
1. Nearest Neighbor(Unpooling): 복원해야 할 값을 가까운 값으로 복제 (각 원소를 복사해서 넣음)
2. Bed of Nails(Unpooling): 복원해야 할 값을 0으로 처리 (1st 위치에 input을 넣고 나머지는 0으로 처리)
3.Max Unpooling: Max Pooling한 값의 position을 따로 기억해 놓았다가 해당 위치에 input을 복원
4. Transposed Convolution: Convolution을 통해 얻어낸 Feature Map과 원본 이미지를 각각 input 데이터와 정답 데이터로 삼아 학습을 통해 원본 이미지에 가깝게 새로운 이미지를 생성
Upsampling은 다양하게 활용가능하다. 예를 들어, 저해상도의 이미지를 고해상도로 변환하거나 (High-Resolution)
전체 이미지에서 추출한 Feature Map 부분을 강조하는 효과를 낼 수도 있고,
임의의 이미지에 특정한 패턴을 입힐 수도 있다.
새로 생성한 이미지를 가지고 모델을 더 잘 훈련시킬 수도 있는데, 이게 GAN의 핵심 아이디어이기도 하다.
2. Transposed Convolution vs Deconvolution
Transpose Convolution
Transpose Convolution (이하 TC)를 활용하면 엄밀한 의미의 deconvolution까진 아니지만 비슷한 효과를 얻을 수 있다.
TC 말고도 여러 가지 deconvolution 방법론이 있지만 그 자체로 하나의 분야이므로 여기서는 자주 언급되는 transpose convolution만 간단하게 살펴보자.
TC의 기본 아이디어는 Convolution을 통해 얻어낸 Feature Map과 원본 이미지를 각각 input 데이터와 정답 데이터로 삼아 학습을 통해 원본 이미지에 가깝게 새로운 이미지를 생성하는 것이다.
바로 여기서 Deconvolution과 개념적 차이가 생긴다.
Deconvolution 연산은 합성곱 연산 과정에서 사용한 커널을 그대로 재사용한다. 즉, 학습 과정이 일어나지 않는다.
반면 Transpose Convolution은 연산 과정에서 커널 값이 업데이트된다.
Deconvolution: Convolution의 역과정으로, Output Feature Map을 Input으로 하여 원본 이미지를 Output으로 복원한다.
해당 과정에서 Kernel Size나 Output Size가 고정되어 있으며 동시에 Kernel Weight는 Freeze (학습 X)되어 있다.
Transposed Convolution: Kernel Size와 Output SIze가 고정되어 있다는 점에서 Deconvolution과 비슷하지만
원본 이미지를 되돌리지 못하고 최대한 가깝게 나오도록 학습을 통해 Kernel Weight를 조정한다.
위 그림을 보면 Transpose Convolution 과정을 쉽게 이해할 수 있다.
파란색이 input(Original Image)이고 청록색이 output(Feature Map) 이미지이다.
합성곱 연산 과정을 역으로 따라가기 때문에 TC 연산에 사용되는 필터의 크기는 합성곱 연산에서 사용한 필터 크기와 같아야 한다.
연산 과정을 자세히 살펴보면 피처 맵의 각 원소 주변을 보간하여 input 데이터로 사용하는 것을 알 수 있다.
3. Convolution
일반적인 Convolution Layer부터 알아보자.
일반적인 Convolutional Layer는 input $H \times W$에 다음의 2가지 Parameter로 결정된다.
- Padding(P): 원본 Input Image 주위를 둘러싸는 0들의 숫자를 결정한다.
Padding $p$시 Output은 원본 이미지를 $(H + 2P) \times (W + 2P)$의 size로 확장시킨다
- Stride(S): Kernel(Filter)이 한 번에 이동하는 칸 수를 의미한다.
1) Input Image를 $p$만큼 zero-padding 처리해준다.
2) Padding된 Image에 Kernel을 위치시키고, Kernel과 Kernel에 대응되는 Input Image지역과의 내적으로 Output pixel을 계산한다.
3) 이후 Kernel을 Stride $s$만큼 이동시키며 2)의 과정을 반복한다.
일반적인 Convolutional Layer는 Down-Sampling의 효과가 있고, Output의 spatial dimension은 Input보다 작다.
아래는 다양한 padding $p$과 stride $s$에 따른 Output Feature Map의 생성과정이다.
일반적인 Convolutional Layer에서는 Output 한 변의 길이를 다음의 식을 통해 구할 수 있다.
$O = \frac {I - F + 2P} {S} + 1$
$O$: Output Size
$I$: Input Size
$F$: Filter(Kernel) Size
$P$: Padding
$S$: Stride
일반적으로 Convolution Layer에서 주로 활용하는 Parameter는 다음과 같다.
(Kernel_Size, Stride, Padding)
$(3, 1, 1)$: Kernel SIze 유지
$(3, 2, 1)$: Kernel Size를 절반으로 Down-Sampling
4. Transposed Convolution
Transposed Convolutional Layer는 반대로 주로 Upsampling을 실행한다.
즉, Input보다 Output의 차원이 더 크다.
일반적인 Convolution과 마찬가지로 padding과 stride를 통해 정의할 수 있다.
이런 padding과 stride들은 이론적으로 output(원본 이미지)에서 input(feature map)을 만들어내기 위한 값이다.
예를 들어, output에 동일한 stride와 padding의 값을 가지고 일반적인 Convolution을 한다면
input과 동일한 spatial dimension을 만들어낼 것이다.
즉, Transposed Convolution을 수행했을 때 Ouput의 Size가 $O = (I - 1) \times S + K - 2P$이 나와야 한다.
$O = \frac {I - F + 2P} {S} + 1$의 일반적인 Convolution 식의 Input $I$와 Output $O$을 바꿔서 넣는다면
Transposed Convolution의 Output에 대한 식이 위와 같이 나온다.
Transposed Convolution은 아래와 같이 4개의 단계를 따른다.
1) 새로운 parameter인 $z$와 $p'$를 계산해낸다.
$z = s - 1, p' = k - p - 1, s' = 1$
2) Input(Feature Map)의 각 Pixel사이에 $z (=s - 1)$개의 0을 삽입한다.
이 행위는 Input의 size를 $(s \times (H - 1) + 1) \times (s \times (W - 1) + 1)$으로 증가시킨다.
추가된 $s - 1$개의 zero들이 $H-1$set 만큼 존재하고, 기존에 있던 input의 pixel들은 $H$만큼 존재하므로
$(s - 1) \times (H-1) + H = s \times (H - 1) + 1$이 된다. $W$도 마찬가지이다.
위와 같이 하는 이유는 Input의 각 pixel이 stride $s$만큼 떨어져 있어야 하기 때문이다.
즉, Transposed Convolution에서는 $s$가 Kernel이 이동하는 간격이 아니라 Input의 pixel끼리 떨어진 간격을 의미한다.
3) 2)에서 변형된 Input에 $p'(=k - p - 1)$ 만큼의 zero-padding을 수행한다.
상단 맨 왼쪽에 위치하는 Kernel이 Input의 pixel을 하나 포함하도록 최대한 테두리를 추가한다.
그렇기 때문에 Kernel size $k$에 대해 $p + 1$을 빼준 $k - (p + 1)$이 zero-padding으로 들어간다.
아래 왼쪽 예시를 보면, 왼쪽 상단에 위치한 Kernel이 Input의 Pixel을 Kernel의 오른쪽 하단($1$)에서 포함하지만,
오른쪽 예시에서는 Kernel의 중앙$(p + 1)$에서 Input Pixel을 포함한다.
padding $p = 0$일 경우 input pixel은 무조건 Kernel의 오른쪽 하단에 위치하지만 $(p' = k - 1)$
$p \neq 0$일 경우 input pixel은 padding $p$만큼 밀려서 Kernel의 다른 위치에 존재할 수 있다. $(p' = k - (p + 1))$
4) 3)까지 변형된 Input에 stride $s'$ 1로 고정된 일반적인 Convolution을 수행한다.
4)의 과정에서 stride $s'$가 1인 일반적인 Convolution을 수행하는 것이다.
즉, 기존에 설정한 stride $s$는 input의 pixel들이 서로 얼마나 떨어져 있을지에 대한 값이지
Kernel이 얼마나 움직일지 정하는데 해당되는 값이 아니다.
따라서 stride $s$가 아닌 $s'$으로 Convolution을 수행한다고 보면 된다.
conv2d | conv2d_transpose | |
input size | i | i' |
output size | o | o' |
kernel | k | k' = k |
stride | s | s' = 1 |
padding | p | p' = k - p - 1 |
Kernel size는 일반적인 Convolution과 Transposed Convolution은 동일하다.
아래는 stride $s$와 padding $p$에 따른 Transposed Convolution의 결과를 나타낸 것이다.
즉, 정리하자면 Transpose Convolution에서 Output size $O$는 다음과 같다.
$O = (I - 1) \times S + K - 2P$
$O$: Output Size
$I$: Input Size
$F$: Filter(Kernel) Size
$P$: Padding
$S$: Stride
일반적으로 Convolution Layer에서 주로 활용하는 Parameter는 다음과 같다.
(Kernel_Size, Stride, Padding)
$(3, 1, 1)$: Kernel SIze 유지
$(4, 2, 1)$: Kernel Size를 2배로 Up -Sampling
$(2, 2, 0)$: Kernel Size를 2배로 Up -Sampling w/ No Padding
5. Matrix Multiplication Perspective
기존의 Convolution 연산은 다음과 같다.
이러한 Convolution 연산 과정을 Matrix Multiplication의 형태로 변환하면 다음과 같다.
그럼 이제 반대로 Output Matrix를 입력으로 넣어주고 Input Matrix를 출력으로 얻기 위해 기존의 Kernel Matrix를 Transpose 한다.
이를 Convolution Transpose Matrix라 한다.
Deconvolution Filter를 Matrix 연산에 맞게 바꿔준 후 Upsampling 한다.
기존의 Convolution 연산이 $AB = C$ 라면,
Deconvolution 연산은 $B = A^{-1}C$ 가 되고
Transposed Convolution 연산은 $\hat {B} = A^{T}C$이다.
일반적으로 Orthogonal Matrix가 아니므로 $A^{-1} \neq A^{T}$, 따라서 Deconvolution과 Transposed Convolution은 다르다.
6. References
Transposed Convolutional Layer은 무엇인가?
오토인코더(Autoencoder), 합성곱 오토인코더(Convolutional Autoencoder)
toch.nn.ConvTranspose2d는 어떻게 작동할까요?
CS231n의 Transposed Convolution은 Deconvolution에 가까운 Transposed Convolution이다
Convolution Transpose/ conv2d_transpose