Skip to main content

딥러닝을 사용한 Image Inpainting 소개

Created on February 18|Last edited on October 16
이는 여기에서 볼 수 있는 영어 기사를 번역한 것이다.


이 리포트에서 딥러닝을 사용하여 이미지의 누락된 부분을 정확히 채우는 “image inpainting”을 하는 방법에 대해 학습하겠습니다. 우선, image inpainting의 진정한 의미와 이것에 부합하는 가능한 사용 사례에 대해 논하겠습니다. 다음으로, 기존의 image inpainting 기술과 그 단점에 대해 살펴보겠습니다. 마지막으로 CIFAR10 데이터 세트와 함께 image inpainting을 수행할 수 있는 neural network를 훈련하는 방법에 대해 설명하겠습니다.
이 기사의 개요는 다음과 같습니다:
  • image inpainting 소개
  • image inpainting을 수행하는 다양한 방법
    • 기존의 컴퓨터 비전 기반 접근법
    • 딥러닝 기반 접근법 (Vanilla 오토인코더, Partial convolutions(부분 합성곱))
  • 향후 방향 및 엔딩 노트
커피 한 잔 마시면서 시작해봅시다! 좀 길 수도 있답니다.

This set of panels contains runs from a private project, which cannot be shown in this report




image inpainting이란 무엇인가요?

image inpainting은 이미지의 손상된 또는 누락된 부분을 재구성하는 기술로 비디오에도 쉽게 확장될 수 있습니다. image inpainting으로 인해 많은 사용 사례가 등장했습니다.

(NVIDIA의 web playground에서 수집된 image inpainting 결과)
어릴 적 할아버지, 할머니와 찍은 오래된 사진이 있는데 어떤 이유로 사진의 일부가 손상되었다고 가정해봅시다. 이 사진은 여러분에게 너무나 소중한 추억의 일부분이기 때문에, 이렇게 사진이 손상되는 것은 절대로 원하지 않으실 겁니다. image inpainting은 여기서 이러한 문제를 해결할 구세주가 될 수 있습니다.
image inpainting은 변질된 그림 복원을 위해 숙련된 아티스트를 고용할 예산이 충분치 못한 박물관 등에 매우 유용할 수 있습니다.
이제, 여러분께서 가장 좋아하는 사진 에디터를 생각해봅시다. 거기에 image inpainting 기능이 있다면 정말 좋지 않을까요?
image inpainting은 비디오에도 확장될 수 있습니다 (결국 비디오는 일련의 이미지 프레임입니다). 과압축(over-compression)으로 인해, 비디오의 특정 부분이 때때로 손상될 수 있습니다. 현대 image inpainting 기술은 이러한 문제도 아주 부드럽게 처리할 수 있습니다.
인공 이미지 인페인터의 핵심 목표는 손실된 부분을 시각적 및 의미적으로 그럴듯한 매력적 요소로 채운 이미지를 생산하는 것입니다. 하지만 이 작업은 정말로 어려운 일임을 인정할 수밖에 없습니다.
이제 image inpainting의 의미와 (다음에 공식적인 의미에 대해 더 상세히 살펴보겠습니다) 이의 사용 사례 일부 의미를 어느 정도 이해했으므로, 잠시 방향을 바꿔 이미지를 인페인트(inpaint, 복원)에 사용되는 몇 가지 일반적인 기술에 대해 살펴보겠습니다 (스포일러 경고: 고전적 컴퓨터 비전).

image inpainting 수행하기: 전통적인 방식

딥러닝이 없는 컴퓨터 비전 세계가 있습니다. Single Shot Detectors(SSD)가 등장하기 이전에도 객체 탐지는 여전히 가능했었습니다 (비록 그 정확성은 SSD가 수행할 수 있는 정도와는 거리가 멀지만). 마찬가지로, image inpainting 수행을 위한 소수의 고전적 컴퓨터 비전이 있습니다. 이번 섹션에서는 그중 두 가지에 대해 설명하겠습니다. 우선, 이러한 기술들이 기반을 두고 있는 중심 테마인 texture synthesis(텍스처 합성) 또는 patch synthesis(패치 합성)에 대해 살펴보겠습니다.
이미지에서 누락된 특정 영역을 인페인트하기 위해 누락되지 않은 주어진 이미지의 주변 영역에서 픽셀을 가져옵니다. 이러한 기술은 이미지의 배경을 인페인트 하는 데에는 좋지만, 다음과 같은 경우로는 일반화하지 못합니다:
  • 주변 영역에 누락된 부분을 채우기에 적합한 정보가 (픽셀 읽기) 없을 수 있습니다.
  • 누락된 영역은 렌더링할 객체의 속성을 추론하기 위해 인페인팅 시스템이 필요합니다.
후자의 경우, 기존의 시스템에서 좋은 결과를 얻었습니다. 그러나 이러한 객체가 구조에서 반복적이지 않은 경우, 인페인팅 시스템이 추론하기가 다시 어려워집니다.
이것을 생각해보면, 아주 세밀한 수준에서, image inpainting은 누락된 픽셀값 복원에 지나지 않습니다. 따라서, 다음과 같이 스스로 질문할 수 있습니다. 왜 이것을 missing value imputation(손실 값 대체) 문제로 이것을 처리할 수 없을까? 흠, 이미지는 임의의 픽셀값 더미가 아니라 픽셀값의 공간 모음입니다. 따라서 image inpainting 작업을 단지 손실 값 대체 문제로 취급하는 것은 다소 비합리적입니다. 잠시 후 다음 질문에 저희가 답하겠습니다. – 간단하게 누락 픽셀 예측에 CNN을 사용하는 것은 어떤가요?_
이제 다음의 두 가지 기술에 대해 살펴보겠습니다 - -
  • Navier-Stokes(나비에-스토크스) 방법: 이는 2021년 (논문) 거슬러 올라갑니다. 이 방법은 유체역학 및 편미분 방정식(partial differential equations) 개념을 통합하고 있습니다. 이는 이미지의 가장자리는 본질적으로 연속적이어야 한다는 사실에 기초하고 있습니다. 다음 그림을 살펴보시기 바랍니다 -

  • 연속성 제약(continuity constraint)과 함께 (가장자리와 같은 특징을 유지하는 방법을 말하는 다른 방식), 저자들은 인페인팅이 필요한 가장자리의 주변 영역에서 색 정보를 가져왔습니다.
  • Fast marching method(패스트 마칭 방법): 2004년, Alexandru Telesa는 이 아이디어를 이 논문에 제시했으며, 다음의 사항을 제안했습니다:
  • 누락된 픽셀 추정을 위해, 픽셀 주변(neighborhood)에서 정규화된 가중치 합(normalized weighted sum of pixels)을 가져옵니다. 이 주변은 boundary(경계)에 의해 매개변수화(parameterize)되고, 픽셀 세트가 인페인팅되면 이 경계가 업데이트됩니다.
  • 픽셀의 색을 추정하기 위해, 주변 픽셀의 gradients(경사)가 사용됩니다. 이 두 가지 방법이 생성할 수 있는 결과를 확인하고 싶으시면, 이 기사를 참조하시기 바랍니다. 이제 기존의 image inpainting 방식에 익숙해졌으므로, 현대적인 방식, 즉, 딥러닝을 활용한 방식으로 어떻게 이를 수행하는지 살펴보겠습니다.

image inpainting 수행하기: 현대적 방식

이 접근법에서, 이미지의 누락된 부분을 예측하도록 neural network를 훈련해 그 예측이 시각적 및 의미적으로 일치하도록 해보겠습니다. 잠시 한 걸음 물러서서 우리 (인간)이 어떻게 image inpainting을 하는지 한 번 생각해 봅시다. 이는 우리가 딥러닝 기반 접근법의 기초를 공식화하는 데 도움이 될 것입니다. 또한 image inpainting 작업에 대한 문제 설정 형성에도 도움이 될 것입니다.
이미지에서 누락된 부분을 재구성하는 경우, 세상에 대한 이해를 활용하고 작업 수행에 필요한 콘텍스트(context)를 결합합니다. 이는 우리가 특정 콘텍스트와 글로벌 이해를 우아하게 결합한 한가지 예입니다. 그렇다면, 이것을 딥러닝 모델에 주입할 수 있을까요? 한번 지켜보겠습니다.
우��� 인간은 오랜 시간에 걸쳐 습득한 지식 기반(세상에 대한 이해)에 의존합니다. 현재의 딥러닝 접근법은 어떤 의미에서든 지식 기반을 활용하는 것과는 거리가 멉니다. 그러나 우리는 딥러닝을 사용하여 이미지의 공간적 콘텍스트를 담아낼 수 있습니다. Convolutional Neural Networks 또는 CNN은 topology와 같은 그리드로 알려진 데이터를 처리하기 위한 전문 신경망입니다. 예를 들면, 이미지는 픽셀의 2D 그리드로 생각할 수 있습니다. 이는 누락된 픽셀 예측을 위해 심층 CNN 기반 아키텍처를 훈련하는 학습 기반 접근법이 될 것입니다.

CIFA10 데이터세트를 포함한 간단한 image inpainting 모델

ML/DL 개념은 실제로 구현함으로써 가장 잘 이해할 수 있습니다. 이번 섹션에서는, Deep Image Inpainting의 구현에 대해 여러분께 설명해 드리면서, 동시에 몇 가지 주요 요소에 대해 설명하겠습니다. 우선 데이터세트가 필요하며, 가장 중요한 것은 대상 작업에 맞게 데이터세트를 준비해야 합니다. 아키텍처에 대하여 논하기에 앞서, 이 DL 작업은 자기지도 학습(self-supervised learning) 환경에 있습니다.

간단한 데이터세트를 선택한 이유는 무엇인가요?

인페인팅은 이미지의 손실되거나 손상된 부분을 재구성하는 프로세스이므로, 어떠한 이미지 데이터세트를 가져와서 여기에 인위적인 손상을 추가할 수 있습니다. 이 특정 DL 작업의 경우, 작업 할 데이터 세트가 너무 많습니다. 그렇긴 해도, Image inpainting의 실제 적용이 고해상도 이미지 (예: 512 x 512 픽셀)에서 수행된다는 것을 발견했습니다. 그러나 [이 논문] http://openaccess.thecvf.com/content_cvpr_2018/papers/Yu_Generative_Image_Inpainting_CVPR_2018_paper.pdf()에 따르면, 한 픽셀이 64픽셀 떨어진 컨텐츠에 영향을 받는 것을 허용하려면, 적어도 dilation factor 2를 가진 3x3 convolutions의 6개의 레이어가 필요합니다.
따라서 이러한 고해상도 이미지를 사용하는 것은 이 목적에 부합하지 않습니다. ML/DL 개념을 toy 데이터세트에 적용하는 것이 일반적인 관행입니다. 컴퓨터 리소스를 줄이고 빠른 구현을 위해 저희는 CIFAR10 데이터세트를 사용하겠습니다.

데이터 준비

DL 작업의 시작 단계는 데이터 준비입니다. 저희의 경우, 앞서 언급했듯이, 인공적인 손상을 이미지에 추가할 필요가 있습니다. 이미지를 마스킹(masking)하는 표준 이미지 프로세싱 아이디를 사용하여 이를 수행할 수 있습니다. 이 작업은 자기지도 학습(self-supervised learning) 환경에서 수행되기 때문에, 모델을 훈련하려면 X와 y (X와 동일) 쌍이 필요합니다. 여기서 X는 마스킹된 이미지의 batches이고, y는 원본/ground truth 이미지입니다.

마스킹(masking)e을 단순화하기 위해, 우선 누락된 부분이 사각형 구멍이라고 가정했습니다. 이러한 아티팩트 과적합(overfitting)을 예방하기 위해, 사각형의 위치를 크기와 더불어 무작위로 지정했습니다.
이러한 사각형 구멍을 사용하면 적용 시에 모델의 유용성이 크게 제한됩니다. 이는 실제에서는 이미지의 손상이 단순한 사각형 모양이 아니기 때문입니다. 따라서 이 논문에서 영감을 얻어, 저희는 불규칙한 구멍을 마스크(masks)로 구현했습니다. OpenCV를 사용하여 임의의 길이와 두께의 선을 단순히 그렸습니다.
Keras 데이터 생성기(generator)를 사용하여 동일한 작업을 수행하겠습니다. 이는 필요한 batch size의 X 및 y 쌍의 무작위 batches 생성하고, 마스크(mask)를 X에 적용하여, 즉시 사용할 수 있도록 합니다. 고해상도 이미지의 경우, 데이터 생성기를 사용하는 것이 유일한 비용 효율이 높은 옵션입니다. 저희 데이터 생성기인 createAugment는 이 놀라운 블로그에서 영감을 얻었습니다. 읽어보시기 바랍니다.
class createAugment(keras.utils.Sequence):
# Generates masked_image, masks, and target images for training
def __init__(self, X, y, batch_size=32, dim=(32, 32),
n_channels=3, shuffle=True):
# Initialize the constructor
self.batch_size = batch_size
self.X = X
self.y = y
self.dim = dima
self.n_channels = n_channels
self.shuffle = shuffle
self.on_epoch_end()

def __len__(self):
# Denotes the number of batches per epoch
return int(np.floor(len(self.X) / self.batch_size))

def __getitem__(self, index):
# Generate one batch of data
indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]
# Generate data
X_inputs, y_output = self.__data_generation(indexes)
return X_inputs, y_output

def on_epoch_end(self):
# Updates indexes after each epoch
self.indexes = np.arange(len(self.X))
if self.shuffle:
np.random.shuffle(self.indexes)
위의 코드 블록의 방법은 따로 설명이 필요 없습니다. 우리 사용 사례를 위해 특별히 구현된 datageneration 과 createMask 방벱에 대해 설명해드리겠습니다. 이름에서 알 수 있듯이, 이 private mathod는 주어진 batch size의 batch에서 각 이미지에 대한 이진 마스크(binary masks)를 생성합니다. 이는 흰색 배경에 임의의 길이 및 두께의 검은 선을 그립니다. 마스킹된 이미지와 함께 마스크(mask)를 반환함을 확인할 수 있습니다. 왜 이 마스크가 필요할까요? 곧 확인해보겠습니다.
Keras의 model.fit에는 __getitem__을 내부에 호출하는 입력 및 대상 데이터가 필요합니다. traingencreateAugment의 인스턴스인 경우, 그러면 traingen[i]은 traingen.getitem(i)과 거의 동일하며, 여기서 i는 0 to len(traingen)입니다. 이 특수 방법은 내부적으로 Masked_images, Mask_batchy_batch의 batches를 준비하는__data_generation을 호출합니다.
def __data_generation(self, idxs):
# Masked_images is a matrix of masked images used as input
Masked_images = np.empty((self.batch_size, self.dim[0], self.dim[1], self.n_channels)) # Masked image

# Mask_batch is a matrix of binary masks used as input
Mask_batch = np.empty((self.batch_size, self.dim[0], self.dim[1], self.n_channels)) # Binary Masks
# y_batch is a matrix of original images used for computing error from reconstructed image
y_batch = np.empty((self.batch_size, self.dim[0], self.dim[1], self.n_channels)) # Original image
## Iterate through random indexes
for i, idx in enumerate(idxs):
image_copy = self.X[idx].copy()
## Get mask associated to that image
masked_image, mask = self.__createMask(image_copy)

## Append and scale down.
Masked_images[i,] = masked_image/255
Mask_batch[i,] = mask/255
y_batch[i] = self.y[idx]/255

return [Masked_images, Mask_batch], y_batch

아키텍처

인페인팅은 큰 이미지 생성 문제 집합입니다. 인페인팅의 목표는 누락된 픽셀을 채우는 것입니다. 이는 디블러링(deblurring), 디노이징(denoising), 아티팩트 제거 등과 같은 작업 또한 포함하는 픽셀을 생성 또는 수정하는 것으로 볼 수 있습니다. 이러한 문제를 해결하기 위한 방법은 일반적으로 입력을 출력에 복사하도록 훈련된 neural network인 오토인코더에 의존합니다. 이것은 입력을 설명하는 코드를 학습하는 인코더, h = f(x)와 재구성을 생성하는 디코더, r = g(h) 또는 r = g(f(x))로 구성됩니다.

Vanilla Convolutional 오토인코더

오토인코더는 입력을 재구성하도록 훈련됩니다. 즉, g(f(x)) = x입니다. 그러나 이것이 유일한 경우는 아닙니다. 우리는 이 오토인코더를 훈련하는 것이 차별적 기능을 수행하는 h로 이어지기를 바랍니다. 오토인코더가 주의 깊게 훈련되지 않은 경우, 유용한 핵심적인 특징을 학습하는 것이 아니라 데이터를 암기하는 경향을 보이는 것을 확인할 수 있습니다.
인코더와 디코더의 능력을 제한하기보다는 (shallow network), 정규화된(regularized) 오토인코더가 사용됩니다. 일반적으로 모델이 입력을 복사하는 기능 이외의 다른 속성 학습을 촉진하도록 손실 함수가 사용됩니다. 이러한 다른 속성에는 표현의 희소성, 노이즈 또는 누락된 값에 대한 견고성이 포함도리 수 있습니다. 이는 image inpainting이 오토인코더 기반 아키텍처의 이점을 누릴 수 있는 곳입니다. 이제 하나를 만들어 보겠습니다.


기준(baseline)을 설정하기 위해, 저희는 vanilla CNN을 사용하여 오토인코더를 구축하겠습니다. 우선 벤치마크 설정을 위해 간단한 모델을 생성하고 점진적으로 개선하는 것이 좋습니다. 오토인코더에 대한 개념을 다시 확인해보고 싶으시다면 PyImageSearch의 이 기사를 확인해보는 것이 좋은 시작점이 될 것입니다. 앞서 언급한 바와 같이, 목표는 복사(copying)를 마스터하는 것이 아니기 때문에, 모델이 누락된 포인트를 채우는 방법을 학습하도록 손실함수를 설계합니다. 우선 손실로 mean_square_error을 사용하고 dice coefficient(다이스 계수)를 평가 메트릭으로 사용합니다.
def dice_coef(y_true, y_pred):
y_true_f = keras.backend.flatten(y_true)
y_pred_f = keras.backend.flatten(y_pred)
intersection = keras.backend.sum(y_true_f * y_pred_f)
return (2. * intersection) / (keras.backend.sum(y_true_f + y_pred_f))
이미지 분할, 이미지 인페인팅 등과 같은 작업의 경우, 높은 색 클래스 불균형으로 인해 픽셀 단위 정확도는 좋은 메트릭이 아닙니다. 이해하기 쉽지만, accuracy score는 종종 오해의 소지가 있습니다. 일반적으로 사용되는 두 가지 대안은 IoU (Intersection over Union) 와 Dice Coefficient입니다. Union에(합집합) 의해 나눠진 예측된 픽셀과 ground truth 픽셀 사이의 겹쳐진 영역을 최대화한다는 점에서 둘 다 비슷합니다. 여기에서 이 내용에 대한 훌륭한 설명을 확인할 수 있습니다.
여러 epoch 또는 단계에 걸쳐 모델이 누락된 구멍을 채우는 방법을 어떻게 학습하는지를 지켜보는 것은 흥미롭지 않습니까?
각 epoch가 완료된 후, 크기 32의 동일한 test batch에서 model.predict()를 호출하는 간단한 데모 PredictionLogger 콜백을 구현했습니다. wandb.log()를 사용하여 마스킹된 이미지, 마스크(masks), prediction 및 ground truth 이미지를 쉽게 로그할 수 있었습니다. Fig 1은 이 콜백의 결과입니다. 다음은 이를 구현하는 전체 콜백입니다.
class PredictionLogger(tf.keras.callbacks.Callback):
def __init__(self):
super(PredictionLogger, self).__init__()
# The callback will be executed after an epoch is completed
def on_epoch_end(self, logs, epoch):
# Pick a batch, and sample the masked images, masks, and the labels
sample_idx = 54
[masked_images, masks], sample_labels = testgen[sample_idx]

# Initialize empty lists store intermediate results
m_images = []
binary_masks = []
predictions = []
labels = []
# Iterate over the batch
for i in range(32):
# Our inpainting model accepts masked imaged and masks as its inputs,
# then use perform inference
inputs = [B]
impainted_image = model.predict(inputs)

# Append the results to the respective lists
m_images.append(masked_images[i])
binary_masks.append(masks[i])
predictions.append(impainted_image.reshape(impainted_image.shape[1:]))
labels.append(sample_labels[i])

# Log the results on wandb run page and voila!
wandb.log({"masked_images": [wandb.Image(m_image)
for m_image in m_images]})
wandb.log({"masks": [wandb.Image(mask)
for mask in binary_masks]})
wandb.log({"predictions": [wandb.Image(inpainted_image)
for inpainted_image in predictions]})
wandb.log({"labels": [wandb.Image(label)
for label in labels]})



Run set
2


Partial convolutions(부분 합성곱)

이제 Vanilla CNN의 강력한 대안으로 Image Inpainting for Irregular Holes Using Partial Convolutions(부분 합성곱을 사용하여 불규칙한 이미지 인페인팅)에 대해 이야기해보겠습니다. 이미지의 구멍과 같은 누락된 데이터를 채우기 위해 Partial convolution이 제안되었습니다. 원래의 공식은 다음과 같습니다 – X는 현재 슬라이딩 (컨볼루션) 윈도우의 특징값이고, M은 해당 이진 마스크(binary mask)라고 가정합니다. 구멍은 0으로, 구멍이 아닌 것은 1로 나타낸다고 합시다. 수학적으로 partial convolution은 다음과 같이 나타낼 수 있습니다:

image.png

scaling factor sum(1)/sum(M)은 유효한 (마스킹 되지 않은) 입력의 다양한 양을 조정하기 위해 적절한 스케일링을 적용합니다. 각 partial convolution operation (부분 합성곱 연산) 후, 다음과 같이 마스크를 업데이트합니다: convolition이 하나 이상의 유효한 입력 (특징) 값에 대한 출력을 조정할 수 있는 경우, 해당 위치가 유효현 것으로 표시합니다. 이는 다음과 같이 표현할 수 있습니다:

image.png

입력이 유효한 픽셀을 포함하고 있는 경우, 여러 partial convolution 레이어를 통해 모든 마스크는 결국 모두 1이 됩니다. image inpainting 작업에서 Vanilla CNN을 partial convolution 레이어로 대체하려면 동일한 구현이 필요합니다.

안타깝게도, TensorFlow 및 Pytorch에는 공식적인 구현이 없기 때문에, 커스텀 레이어를 직접 구현해야 합니다. 이 커스텀 레이어를 구축하는 방법을 설명하고 있는 TensorFlow 튜토리얼이 바로 그 훌륭한 시작점입니다. 다행히도 저는 여기서 partial convolution의 Keras 구현을 찾을 수 있었습니다. 이 코드베이스는 제가 TF 2.x를 사용하도록 업그레이드한 Keras 백엔드로 TF 1.x을 사용했습니다. 저희는 이 블로그 게시물에 대한 GitHub repo와 함께 이 업그레이드된 구현을 제공해왔습니다. 여기서 PConv2D layer를 확인하시기 바랍니다.

코드로 모델을 구현하고, CIFAR 10 데이터세트에서 훈련해보겠습니다. 저희는 inpaintingModel 클래스를 구현했습니다. 모델을 빌드하려면 prepare_model() 방법을 호출해야 합니다.

def prepare_model(self, input_size=(32,32,3)):
	input_image = keras.layers.Input(input_size)
	input_mask = keras.layers.Input(input_size)

	conv1, mask1, conv2, mask2 = self.__encoder_layer(32, input_image, input_mask)
	conv3, mask3, conv4, mask4 = self.__encoder_layer(64, conv2, mask2)
	conv5, mask5, conv6, mask6 = self.__encoder_layer(128, conv4, mask4)
	conv7, mask7, conv8, mask8 = self.__encoder_layer(256, conv6, mask6)

	conv9, mask9, conv10, mask10 = self.__decoder_layer(256, 128, conv8, mask8, conv7, mask7)
	conv11, mask11, conv12, mask12 = self.__decoder_layer(128, 64, conv10, mask10, conv5, mask5)
	conv13, mask13, conv14, mask14 = self.__decoder_layer(64, 32, conv12, mask12, conv3, mask3)
	conv15, mask15, conv16, mask16 = self.__decoder_layer(32, 3, conv14, mask14, conv1, mask1)

	outputs = keras.layers.Conv2D(3, (3, 3), activation='sigmoid', padding='same')(conv16)

	return keras.models.Model(inputs=[input_image, input_mask], outputs=[outputs])

오토인코더이기 때문에, 이 아키텍처는 두 가지 요소 즉, 이미 논의한 인코더와 디코더를 갖고 있습니다. 이 인코더 및 디코더 conv 블록을 재사용하기 위해 저희는 간단한 효용함수(utility function) 2개, encoder_layerdecoder_layer를 빌드했습니다.

def __encoder_layer(self, filters, in_layer, in_mask):
	conv1, mask1 = PConv2D(32, (3,3), strides=1, padding='same')([in_layer, in_mask])
	conv1 = keras.activations.relu(conv1)

	conv2, mask2 = PConv2D(32, (3,3), strides=2, padding='same')([conv1, mask1])
	conv2 = keras.layers.BatchNormalization()(conv2, training=True)
	conv2 = keras.activations.relu(conv2)

	return conv1, mask1, conv2, mask2

def __decoder_layer(self, filter1, filter2, in_img, in_mask, share_img, share_mask):
	up_img = keras.layers.UpSampling2D(size=(2,2))(in_img)
	up_mask = keras.layers.UpSampling2D(size=(2,2))(in_mask)
	concat_img = keras.layers.Concatenate(axis=3)([share_img, up_img])
	concat_mask = keras.layers.Concatenate(axis=3)([share_mask, up_mask])

	conv1, mask1 = PConv2D(filter1, (3,3), padding='same')([concat_img, concat_mask])
	conv1 = keras.activations.relu(conv1)

	conv2, mask2 = PConv2D(filter2, (3,3), padding='same')([conv1, mask1])
	conv2 = keras.layers.BatchNormalization()(conv2)
	conv2 = keras.activations.relu(conv2)

	return conv1, mask1, conv2, mask2

오토인코더 구현의 본질은 Upsampling2DConcatenate 레이어에 있습니다. 이것에 대한 대안은 바로 Conv2DTranspose 레이어를 사용하는 것입니다.

저희는 default parameter인 mean_square_error를 손실로, dice_coef를 메트릭으로 사용하여 Adam optimizer를 통해 모델을 컴파일했습니다. model.fit()을 사용하여 모델을 훈련했고, WandbCallbackPredictionLogger 콜백을 사용하여 모델의 결과를 로그했습니다.




This set of panels contains runs from a private project, which cannot be shown in this report


여러분께서는 Vanilla CNN 기반 image inpainting이 partial convolution 기반 접근법보다 조금 더 낫다는 것을 알 수 있습니다. 이것은 partial convolution은 CIFAR10 데이터세트에 대하여 복잡한 아키텍처라는 사실로 요약할 수 있습니다. 이 레이어는 256x256픽셀 보다 더 고화질인 이미지용으로 설계되었습니다.
픽셀 당 reconstruction loss(재구성 손실)와 composition loss(컴포지션 손실)를 타깃으로 하는 손실 함수를 사용한 이 논문의 저자와 달리, (즉 예측된 구멍 값이 주변 콘텍스트로 어떻게 원활하게 전환되는가) 저희는 단순히 L2 손실을 사용했습니다. 구멍 픽셀에 대한 평균 및 분산만 계산되기 때문에 구멍은 batch normalization(배치 일반화) 레이어 문제를 유발합니다. 따라서 이 레이어를 사용하기 위해 저자들은 처음에 최종 훈련의 경우 꺼져있었던 인코더 레이어에서 batch normalization을 사용하여 훈련 시켰습니다. 저희는 이 방법을 사용하여 훈련하지 않았습니다.

결론

주제에 대한 self-supervised learning(자기지도 학습) 및 image inpainting에 대한 몇몇 새로운 접근법 등 몇 가지 추가 조언과 함께 마무리 하겠습니다.
image inpainting 모델의 매우 흥미로운 속성은 바로 이미지를 어느 정도 수준으로 이해할 수 있다는 것입니다. NLP에서의 경우와 매우 유사합니다. 여기서 저희는 임베딩을 사용하여 단어간 의미 관계를 이해하고, 이러한 임베딩을 통해 텍스트 분류와 같은 다운스트림 작업을 수행합니다.
여기서 전제는 이미지의 누락된 부분을 의미 및 시각적 어필로 채우기 시작하면, 이미지를 이해하기 시작한다는 것입니다. 이것은 명시적 레이블(explicit labels)이 없을 때, 입력 데이터에 있는 암시적 레이블(implicit labels)을 활용하는 self-supervised learning에 보다 더 가깝습니다.
이것은 우리가 NLP 작업에 임베딩을 사용하는 것처럼, 컴퓨터 비전 작업에서 image inpainting 모델에 대한 지식을 사용할 수 있다는 이유에서 특히 흥미롭습니다. 이에 대해 더 자세히 알고 싶으시다면 Jeremy Howard가 상세하게 서술한 이 기사를 읽어보실 것을 추천합니다.
지금까지 저희는 픽셀 단위 비교를 저희 손실 삼수로 사용했습니다. 이는 일반적으로 네트워크가 매우 엄격하고 그리 풍부하지 않은 특징 표현을 학습하도록 강요합니다. Charles 등의 학자들은 이 리포트에서 흥미롭지만 간단한 아이디어인 approximate exact matching(근사-정확 매칭)을 제시했습니다. 이 연구에 따르면, 이미지의 픽셀값을 작은 상수만큼 이동해도 이미지는 시각적으로 원본과 크게 다르지 않습니다. 따라서 그들은 이 아이디어를 구체화하기 위해 픽셀 단위 비교 손실(pixel-wise comparison loss)에 추가 항목을 추가했습니다.
저희 네트워크에 대한 또 다른 흥미로운 수정(tweak)사항은 이것이 이미지의 먼 공간 위치에서 관련 기능 패치(patches)에 대하여 관여할 수 있도록 하는 것입니다. 논문 Generative Image Inpainting with Contextual Attention에서 Jiahui 등의 학자들은 훈련 중에 네트워크가 이웃 이미지 특징을 참조(reference)로 명시적으로 사용할 수 있도록 하는 contextual attention의 개념을 도입했습니다.
이 기사를 끝까지 읽어주셔서 감사합니다. Image inpainting은 흥미로운 컴퓨터 비전 작업이며, 이 기사가 이 주제에 대한 괜찮은 소개가 되었기를 바랍니다. 이 기사에 대한 피드백이 있으시면 Twitter (AyushSayak)으로 언제든지 연락해주시면 감사하겠습니다 :)

Iterate on AI agents and models faster. Try Weights & Biases today.