Context Encoders를 활용한 배경 채우기(1)
동기
삼성에서 만든 갤럭시 S21에는 사진에서 사물을 지우는 기능이 있습니다. 광고를 보고 그 기능을 구현해 보고 싶어서 이 프로젝트를 시작했습니다. 기능을 구현하기 위해서는 사물을 검출하는 과정도 필요하지만 일단 지워진 부분을 배경으로 덮어씌우는 inpainting을 만들어 봤습니다.
개요
이미지의 손상된 부분을 복구하거나 그럴듯한 이미지로 채우는 기술이 Image inpainting입니다. 현재 다양한 방법이 나와있지만 널리 응용되고 있는 기술은 pix2pix입니다. pix2pix에서 참고하였다고 언급한 context encoder논문을 기초로 모델을 만들었습니다. 주로 참고한 논문은 아래 세가지 논문입니다.
Generative Adversarial Nets
https://arxiv.org/abs/1406.2661
UNSUPERVISED REPRESENTATION LEARNING WITH DEEP CONVOLUTIONAL GENERATIVE ADVERSARIAL NETWORKS
https://arxiv.org/abs/1511.06434
Context Encoders: Feature Learning by Inpainting
https://arxiv.org/abs/1604.07379
Context Encoder논문은 L2 loss와 GAN에서 사용된 adversarial loss를 사용하였더니 이미지의 빈 부분을 잘 그려넣는다는 내용입니다. 네트워크는 Context Encoder논문에 있는 아래 그림과 같습니다.
그림 1 [Network]
source>Context Encoders: Feature Learning by Inpainting
GAN
그림1에서 윗부분에 있는 Encoder와 Decoder가 합쳐서 하나의 생성기(Generator)역할을 하고 우측 아래 box안의 네트워크가 구별기(Discriminator)역할을 합니다. GAN에 대해 간단히 설명하자면 Generator는 가짜 이미지를 생성하고 Discriminator는 입력되는 이미지가 진짜인지 가짜인지 판별하는 구조입니다. 두 네트워크가 서로 성능을 향상하도록 경쟁시켜 결국 Generator가 실제와 유사한 이미지를 생성하게 합니다. 기존 GAN에서 그림1의 Encoder와 Decoder 중간에 있는 4000개의 벡터를 latent vector라고 합니다. 개수는 경우에 따라 달라질 수 있는데 latent vector를 조정하면 다양한 이미지를 생성할 수 있습니다.
Context Encoder와 기본 GAN의 차이
가장 기본적인 GAN은 latent vector부터 네트워크가 시작하는데 Context Encoder는 입력된 이미지의 정보를 활용하여 빈 공간을 채우는 작업을 해야 하므로 Encoder부분이 필요합니다. 또 GAN은 Generator와 Discriminator의 성능과 관련된 adversarial loss만 사용하지만 Context Encoder에서는 원본 이미지와 복구된 이미지의 픽셀 차이를 L2 loss로 계산하여 사용하였습니다. 마지막으로 Context Encoder는 초기 GAN과 달리 Convolution을 사용한 DCGAN의 모델을 기본으로 사용하였습니다. 추가로 모델뿐만 아니라 hyper parameter와 훈련 기법도 DCGAN을 참고했다고 나와있습니다.
The encoder and discriminator architecture is similar to that of discriminator in [33], and decoder is similar to generator in [33]. However, the bottleneck is of 4000 units (in contrast to 100 in [33]); see supplementary material. We used the default solver hyper-parameters suggested in [33]. -Context Encoder-
[33]이 DCGAN논문입니다.
Dataset
논문에서 Dataset으로 ImageNet과 ParisStreetView를 사용했다고 합니다. 그러나 저는 배경을 inpainting하는 모델을 만들 예정이므로 자연 풍경과 도시 풍경 이미지를 사용했습니다. 자연 이미지는 kaggle에서 구할 수 있었습니다.
https://www.kaggle.com/arnaud58/landscape-pictures?select=00000001.jpg
그리고 도시 이미지는 google street view에서 얻었습니다.
https://www.crcv.ucf.edu/data/GMCP_Geolocalization/
다만 google street view이미지의 좌측 상단에는 방향을 나타내는 기호가 있어 해당 영역을 제외하기 위해 이미지를 잘라 사용했습니다.
Mask
논문에서 원본 이미지를 마스킹 하는 방법으로 그림2처럼 (a)가운데 사각형, (b)무작위 사각형, (c)무작위 모형을 사용했습니다.
그림 2 [Mask]
source>Context Encoders: Feature Learning by Inpainting
저는 갤럭시21에서 나온 기능처럼 임의의 물체를 지우고 배경으로 채워 넣는 것이 목표이므로 그림2의 (C)와 같이 무작위 영역 마스킹과 관련된 내용을 참고했습니다.
we experimented with removing arbitrary shapes from images, obtained from random masks in the PASCAL VOC 2012 dataset [12]. We deform those shapes and paste in arbitrary places in the other images (not from PASCAL), again covering up to 1/4 of the image. -Context Encoder-
위에 제시된 논문 내용처럼 지워질 임의의 영역으로 Pascal Voc의 segmentation라벨을 사용했습니다. 다만 논문은 Pascal 2012에 있는 영역을 사용했는데 저는 작은 용량을 위해 Pascal 2007에 있는 segmentation라벨을 사용했습니다. 또 논문처럼 마스크가 차지하는 비율이 전체 이미지 크기의 1/4 이하인 마스크만 선택되도록 하였습니다.
선택된 마스크는 마스크 영역이 1, 나머지 영역이 0인 이미지이고 원본 이미지에 적용될 때 마스크 영역을 이미지의 픽셀 값의 평균으로 채워 넣었습니다.
그림 3 [Mask Example]
source>Context Encoders: Feature Learning by Inpainting
그림3은 마스킹의 예시입니다. 오른쪽이 원본, 가운데가 마스크, 왼쪽이 적용된 모습입니다. 흰색 마스크가 회색으로 바뀐 이유는 이미지 픽셀의 평균으로 채워 넣었기 때문입니다. 가장 왼쪽의 이미지가 네트워크에 입력될 이미지가 됩니다.
Model
기본적인 구조는 그림1과 같이 하였습니다. 그림1의 구조를 가지기 위해 Encoder에서 kernel_size=4, stride=2, padding=1의 convolution을 5회 적용하고 4000개의 bottleneck을 출력하는 층은 kernel_size=4, stride=1, padding=0을 적용하였습니다. Decoder는 Encoder의 정반대 순서로 구성하였습니다.
그림1에서는 최종 출력이 64x64이미지이지만 이는 가운데 사각형 마스크 부분만 출력하는 것입니다. 임의의 모양 마스크에 해당하는 영역을 출력하기 위해서 처음 이미지와 같은 크기의 예측, 즉 전체 그림을 그린 후 마스크 된 부분을 원본 이미지에 붙여 넣는 방식을 사용했습니다. 따라서 그림1보다 transposed conv layer를 한 층 더 추가하여 Encoder와 Decoder가 대칭입니다.
Discriminator는 Encoder와 구조가 같지만 마지막에 4000체널이 아닌 확률을 나타내는 값 1개가 출력된다는 점이 차이가 있습니다. Activation함수는 Sigmoid함수를 사용했습니다.
Convolution층과 Transposed convolution층 사이에 Batchnorm과 Activation 함수는 DCGAN논문과 같게 한다고 하였으므로 아래 논문 내용과 같이 구성하였습니다.
source>Context Encoders: Feature Learning by Inpainting
DCGAN point
DCGAN에서 제시한 hyper parameters중 적용된 내용을 이야기하고 넘어가겠습니다.
1.replaces deterministic spatial pooling functions (such as maxpooling) with strided convolutions
maxpooling을 없애고 convolution의 stride를 2로 바꾼 것으로 크기를 조절할 수 있습니다.
2.eliminating fully connected layers on top of convolutional features
fully connected layers대신 출력 차원이 4000x1x1이 되도록 하는 convolution을 사용했습니다.
3.Directly applying batchnorm to all layers however, resulted in sample oscillation and model instability. This was avoided by not applying batchnorm to the generator output layer and the discriminator input layer.
Generator 출력층과 와 Discriminator 입력층에는 batchnorm을 하지 않았습니다.
4.The ReLU activation (Nair & Hinton, 2010) is used in the generator with the exception of the output layer which uses the Tanh function.
Within the discriminator we found the leaky rectified activation (Maas et al., 2013) (Xu et al., 2015) to work well
Encoder에는 LeakyReLU, Decoder에는 ReLU를 사용했습니다. 단 LeakyReLU의 기울기는 0.2로 논문에 나와있습니다.
Loss
Loss는 reconstruction loss와 adversarial loss를 사용합니다.
reconstruction loss는 Generator의 출력 이미지에서 마스크 부분이 원래의 이미지와 얼마나 유사한지 나타내는 loss입니다.
유사한 정도로 L2 norm의 제곱을 사용하였습니다.
F는 Generator의 출력, M은 마스크로 마스크 영역이 1입니다. 즉 F안에 있는 식이 마스크가 적용된 이미지입니다.
adversarial loss는 discriminator를 얼마나 잘 속이는 지 나타내는 loss입니다. 전체 형식은 GAN에 나오는 loss와 유사합니다.
D는 discriminator의 출력을 의미하며 discriminator가 log(D(x))로 진짜 이미지를 진짜로 예측하도록 하고 log(1-D(F((1-M)*x)))로 가짜를 가짜로 예측하도록 합니다.
전체 loss는 감소하도록 학습시키는데 이는 generator가 가짜 이미지를 진짜처럼 만들도록 합니다.
실제 학습에서는 generator와 discriminator를 번갈아 가며 훈련시키고 log(1-D(F((1-M)*x)))의 초기 기울기가 작기 때문에 log(1-D(F((1-M)*x)))를 최소화시키는 대신 log(D(F((1-M)*x)))를 최대화시키도록 generator를 학습시킵니다. 자세한 내용은 아래 링크를 참고하시기 바랍니다.
최종적으로 사용되는 loss는 두 loss를 합해서 사용합니다. 논문에서 inpainting에 λrec와 λadv를 각각 0.999, 0.001으로 사용했다고 하여 그대로 적용했습니다.
Training
Optimizer로 generator와 discriminator모두 Adam을 사용했습니다. 논문의 Inpainting 부분에서Generator의 learning rate는 discriminator의 10배라고 하였고, Feature Learning 부분에서 사용한 learning rate는 0.0001이므로 저는 generator의 lr = 0.001, discriminator의 lr = 0.0001로 적용하였습니다.
Batch size는 DCGAN논문에서 제시한 대로 128로 하였고 Image size는 Context Encoder에서 제시한 대로 128x128로 하였습니다. learning rate decay나 dropout, weight initialization등은 적용하지 않았습니다.
Inpainting을 위한 반복 횟수는 논문에 제시되지 않았지만 Feature learning을 위한 학습은 100K iteration때 수렴했다고 나와있습니다. 일단 해당 값을 사용하여 학습을 시작하고 loss가 줄어드는 추세와 inpainting결과를 봐서 중단 시점을 조절했습니다.
기본적인 설명은 여기까지 입니다. 전체 코드와 학습 결과는 다음 포스팅에서 다루겠습니다.
References
Generative Adversarial Nets
https://arxiv.org/abs/1406.2661
UNSUPERVISED REPRESENTATION LEARNING WITH DEEP CONVOLUTIONAL GENERATIVE ADVERSARIAL NETWORKS
https://arxiv.org/abs/1511.06434
Context Encoders: Feature Learning by Inpainting
https://arxiv.org/abs/1604.07379
참고한 블로그
라온피플 블로그
Leave a comment