🌌 Deep Learning/논문 리뷰 [KOR]

[딥러닝 논문리뷰 + 코드] CoordConv: An intriguing failing of convolutional neural networks and the CoordConv solution (NeurIPS 2018)

복만 2022. 4. 12. 15:11

NeurIPS 2018에서 발표된 논문이다. 매우 간단한 toy set에서 standard convolution layer의 맹점을 보였으며, coordinate 정보를 extra channel에 포함시키는 매우 간단한 방식으로 convolution layer의 성능을 높일 수 있는 CoordConv를 제안하였다.

 

Paper: https://proceedings.neurips.cc/paper/2018/file/60106888f8977b71e1f15db7bc9a88d1-Paper.pdf

Code: https://github.com/uber-research/coordconv

 

 

Abstract

본 논문에서는, convolution 구조가 잘 동작하지 않는 example인 coordinate transform problem을 제시한다. 이는 (x, y) Cartesian space에서 one-hot pixel space로의 mapping을 학습하는 task이다.

 

또한, 이에 대한 매우 간단한 해결책인 CoordConv를 제안한다. 이는 extra channel을 이용해 input coordinate 정보를 convolution layer에 제공하는 방법으로, 모델이 선택적으로 translation invariance의 정도를 학습할 수 있다. 이 방법으로 GAN, Faster R-CNN, Reinforcement Learning등의 성능을 높일 수 있음을 보인다.

 

 

1. Introduction

CNN의 misguided inductive bias를 보완하기 위해, specialized layer들을 개발해 모델의 성능을 높인 사례가 여럿 존재한다 (Faster R-CNN, DRAW, ...).

 

본 논문에서는, 두 가지 종류의 spatial representation 간의 변환 (dense Cartesian representation <-> pixel-based representation) 을 통해 CNN의 generic inability를 조사한다. 이러한 task는 매우 쉬워보이지만, 의외로 conv. layer로만 구성된 모델들은 이를 잘 수행하지 못한다.

 

본 논문의 main contribution들은 다음과 같다.

  1. Simple toy dataset인 Not-so-Clevr을 제작하였다. 이는 캔버스 위에 랜덤하게 위치한 정사각형들로 구성된 데이터셋이다. (Section 2)
  2. Conv. filter들에게 Cartesian space에서의 현재 위치를 알려줄 수 있는 CoordConv를 제안한다. 이는 coordinate 정보를 담고 있는 extra channel을 feature map에 추가해주는 방법이다.
  3. 가장 간단한 scenario부터 시작하여, coordinate transform problem에 대한 실험을 진행한다. 
    • Supervised coordinate classification: (x, y) coordinate가 주어졌을 때, 해당하는 위치를 image에서 찾는 문제.
    • Supervised coordinate regression: image에서 하나의 위치가 주어졌을 때, 해당하는 (x, y) coordinate를 예측하는 문제.
  4. Supervised Rendering: 정사각형의 center coordinate가 주어졌을 때, 해당 정사각형이 그려진 image를 그리는 문제 (Section 4.3)
  5. GAN, Faster-R-CNN, Reinforcement Learning에서 CoorConv의 효과를 조사하였다.

 

 

2. Not-so-Clevr dataset

Not-so-Clevr dataset은 Sort-of-CLEVR dataset의 single-object, grayscale version으로, 다음과 같이 구성되어 있다. (Sort-of-CLEVR datset에 대한 설명은 여기를 참고)

  • 9x9 squares place on 64x64 canvas
  • possible center positions are 3,136 (= # examples)
  • for each example square $i$, the dataset contains three fields:
    • $C_i \in \mathbb{R}^2$: its center location in (x, y) Cartsian Coordinates
    • $P_i \in \mathbb{R}^{64\times64}$: a one-hot representation of its center pixel
    • $I_i \in \mathbb{R}^{64\times64}$: the resulting 64x64 image of the square painted on the canvas

 

이 데이터셋에 대해 두 가지 종류의 train/text split을 이용해 실험을 진행했다.

Uniform: random하게 모든 sample을 80/20 비율로 split한다.

Quadrant: 4개의 사분면 중 3개는 train으로, 나머지 하나는 test로 사용한다.

 

 

 

3. The CoordConv layer

Conv. layer이 잘 동작하는 이유는 크게 세 가지로 볼 수 있다: 1) 상대적으로 적은 수의 parameter, 2) moden GPU에서의 빠른 연산속도, 3) translation invariant한 function을 학습하기 때문.

 

CoordConv는 앞 두개의 성질은 계속 보존하지만, 마지막 translation invariant는 학습을 통해 이를 보존할지를 결정한다. 이는 모델의 일반화 성능을 저해하는 것처럼 보일 수도 있으나, 실은 network capacity의 작은 부분을 non-translational invariant aspect에 할당하는 것은 오히려 일반화 성능을 높일 수 있다고 한다.

 

CoordConv layer의 구조는 다음과 같다.

 

  • feature map에 coordinate 정보로 채워진 extra channel을 concatenate한다. 이 때 coordinate 정보는 i coordinate, j coordinate로 나눠서, 각 위치마다 번호를 붙힌다. 예를 들어, i coordinate의 첫 번째 row는 모두 1로 채워져 있고, 두 번째 row는 모두 2로 채워져 있고, 이런 식이다.
  • 이 coordinate 정보들은 concatenate 하기 전에 [-1, 1] 범위로 normalize한다.
  • 이후 standard convolutional layer을 적용한다.
  • 본 논문에서는 i, j coordinate 정보만 이용했지만, 만약 필요하다면 추가적인 정보(ex: $r=\sqrt{(i-h/2)^2+(j-w/2)^2}$)를 줄 수도 있다.

 

 

코드로 보면 다음과 같다.

https://github.com/uber-research/CoordConv/blob/master/CoordConv.py:

from tensorflow.python.layers import base
import tensorflow as tf

class AddCoords(base.Layer):
    """Add coords to a tensor"""
    def __init__(self, x_dim=64, y_dim=64, with_r=False, skiptile=False):
        super(AddCoords, self).__init__()
        self.x_dim = x_dim
        self.y_dim = y_dim
        self.with_r = with_r
        self.skiptile = skiptile


    def call(self, input_tensor):
        """
        input_tensor: (batch, 1, 1, c), or (batch, x_dim, y_dim, c)
        In the first case, first tile the input_tensor to be (batch, x_dim, y_dim, c)
        In the second case, skiptile, just concat
        """
        if not self.skiptile:
            input_tensor = tf.tile(input_tensor, [1, self.x_dim, self.y_dim, 1]) #(batch, 64, 64, 2)
            input_tensor = tf.cast(input_tensor, 'float32')

        batch_size_tensor = tf.shape(input_tensor)[0] #get batch size

        xx_ones = tf.ones([batch_size_tensor, self.x_dim], dtype=tf.int32)                       # e.g. (batch, 64)
        xx_ones = tf.expand_dims(xx_ones, -1) #(batch, 64, 1)
        xx_range = tf.tile(tf.expand_dims(tf.range(self.y_dim), 0), [batch_size_tensor, 1])             # e.g. (batch, 64)
        xx_range = tf.expand_dims(xx_range, 1) #(batch, 1, 64)

        xx_channel = tf.matmul(xx_ones, xx_range) #(batch, 64, 64)
        xx_channel = tf.expand_dims(xx_channel, -1) #(batch, 64, 64, 1)

        yy_ones = tf.ones([batch_size_tensor, self.y_dim], dtype=tf.int32)                       # e.g. (batch, 64)
        yy_ones = tf.expand_dims(yy_ones, 1) #(batch, 1, 64)
        yy_range = tf.tile(tf.expand_dims(tf.range(self.x_dim), 0), [batch_size_tensor, 1])             # (batch, 64)
        yy_range = tf.expand_dims(yy_range, -1) #(batch, 64, 1)

        yy_channel = tf.matmul(yy_range, yy_ones) #(batch, 64, 64)
        yy_channel = tf.expand_dims(yy_channel, -1) #(batch, 64, 64, 1)

        xx_channel = tf.cast(xx_channel, 'float32') / (self.x_dim - 1)
        yy_channel = tf.cast(yy_channel, 'float32') / (self.y_dim - 1)
        xx_channel = xx_channel*2 - 1 #[-1,1]
        yy_channel = yy_channel*2 - 1

        ret = tf.concat([input_tensor, xx_channel, yy_channel], axis=-1) #(batch, 64, 64, c+2)

        if self.with_r:
            rr = tf.sqrt( tf.square(xx_channel) + tf.square(yy_channel))
            ret = tf.concat([ret, rr], axis=-1) #(batch, 64, 64, c+3)

        return ret

class CoordConv(base.Layer):
    """CoordConv layer as in the paper."""
    def __init__(self, x_dim, y_dim, with_r, *args,  **kwargs):
        super(CoordConv, self).__init__()
        self.addcoords = AddCoords(x_dim=x_dim, 
                                   y_dim=y_dim, 
                                   with_r=with_r,
                                   skiptile=True)
        self.conv = tf.layers.Conv2D(*args, **kwargs)

    def call(self, input_tensor):
        ret = self.addcoords(input_tensor)
        ret = self.conv(ret)
        return ret

 

모델 사이에 이런 식으로 추가할 수 있다.

 

https://github.com/uber-research/CoordConv/blob/27fab8b86efac87c262c7c596a0c384b83c9d806/model_builders.py#L624

 

CoordConv의 특성들은 다음과 같다.

  1. Number of parameters
    • standard conv: $cc'k$
    • CoordConv: $(c+d)c'k^2$
    • $c$: # input channels; $c'$: # ouput channels; $k$: kernel size; $d$: #coordinate dimensions
  2. Translation invariance
    • 연결된 weight가 0으로 초기화/학습된 CoordConv의 경우, tranlsation invariant하다.
    • Weight가 0이 아닐 경우, 어느 정도의 translation dependence를 갖고 있는 것이다.
    • Locally connected layers with unshared weights도 translation dependence를 학습할 수 있지만, 훨씬 더 많은 수의 parameter을 필요로 한다. ($hwcc'k^2$ for spatial input size $h\times w$)

 

 

4. Supervised Coordinate Tasks

4.1. Supervised Coordinate Classification

(x, y) coordinate가 주어졌을 때, 해당하는 output pixel을 칠하는 task이다. 이는 단순한 multi-class classification problem이지만, high level latent를 pixel data로 변환시키는 generative model의 simplified version이라고 볼 수 잇다. 

 

  • Convolution의 경우, uniform split에서 100% test accuracy를 달성하지 못했다 (86%). Uniform split의 경우 train sample과 test sample이 서로 매우 유사함을 고려하면 이는 매우 놀라운 결과이다.
  • 또한, quadrant split의 경우 test set의 sample들은 train set에 없던 방향에 존재하는데, 이 경우 일반화를 거의 전혀 할 수 없었다.
  • Convolution의 경우 86% test accuracy를 달성하는 데에 1시간, 200k의 parameter가 필요했으나, CoordConv의 경우 완벽한 성능을 내는 데에 10-20초, 7.5k parameter만 필요했다.

 

 

다음은 training set과 test set에 대한 prediction들을 모두 더한 image이다. 이는 Conv model의 memorization과, 일반화 성능이 떨어짐을 보여준다.

 

 

4.2. Supervsied Coordinate Regression

이는 pixel-based에서 Cartesian으로의 변환을 수행하는 task이며, Supervised Coordinate Classification의 반대 방향이라고 보면 된다. 이는 VAE encoder이나 GAN discriminator과 유사하다고 볼 수 있다.

Conv network의 경우, 각 task에서 가장 나은 generalization 성능을 보이는 모델로 결정했는데, 다음과 같다.

  • uniform split: 4-layer conv. network w. fc layers (85k params)
  • quadrant split: a smaller fully-conv architecture (12k params)

반면 CoordConv는 standard conv layer 여러 개를 쌓고 마지막에 CoordConv layer 하나를 추가한 구조이다. (900 params)

 

결과는 역시 CoordConv가 월등히 좋다.

 

 

4.3. Supervised Rendering

이번엔 주어진 (x, y) location을 중심으로 하는 정사각형을 포함하는 64x64의 image를 생성하는 task이다. 결과는 다음과 같다.

 

 

 

5. Applicability to Image Classification, Object Detection, Generative Modeling, and Reinforcement Learning

ImageNet Classification

Classification은 straightforward translation invariance를 요구하는 task이기 때문에, CoordConv는 성능을 높이지 못할 것이다. 하지만 실험결과, 최소한 성능을 해치지는 않음이 관측되었다. 이는 CoordConv가 coordinate를 무시하도록 학습할 수 있기 때문이다.

 

Object Detection

Cartesian space에서의 pixel space와 output bounding boxe를 봐야 하기 때문에, CoordConv가 도움이 될 수 있다. 결과적으로 MNIST digit을 detection 하는 문제에서 Faster R-CNN의 mIOU 성능을 24% 높일 수 있었다.

 

Generative Modeling

Mode collapse 현상을, coordinate information을 담고 있는 high-level latent space에서 pixel space로의 변환이 잘 학습되지 않았기 때문으로 보고 CoordConv를 적용하였다.

간단한 colored shape를 생성하는 문제 (7a-d)의 경우 CoordConv GAN은 Conv GAN의 7%의 parameter만 사용하면서도, 2D Cartesian space 전체를 cover하는 sample들을 만들었다.

LSUN bedroom scenes (7e)의 경우, latent space interpolation에 대해 보다 smooth한 geometric transformations이 관측되었다.

 

 

Reinforcement Learning

일부 game에서는 성능이 높아졌으나, 그렇지 않은 game도 있었다.

 

반응형