Image to Image Translation (pix2pix, CycleGAN)

생성모델쟁이·2020년 11월 4일
17

GAN

목록 보기
4/9
post-thumbnail

작성자 : 건국대학교 응용통계학과 정재윤

Image to Image Translation

image to image translation이란 이미지 데이터셋을 사용하여 input 이미지와 output 이미지를 mapping하는 것을 목표로 하는 생성모델의 한 분야입니다. 흑백 이미지에 컬러를 입힌다든지, 낮 사진을 밤 사진으로 만든다든지, 테두리만 주어진 사진을 실제 물건같이 만드는 것이 가능하죠.


이런 image to image translation은 크게 paired한 데이터셋을 사용하는 분야와 unpaired한 데이터셋을 사용하는 분야로 구분할 수 있습니다. 그리고 이 분야들을 대표하는 모델들이 오늘 볼 pix2pix과 cyclegan입니다.

Pix2Pix

그 당시 이미지 처리 문제의 대부분은 CNN을 사용해서 해결했습니다. 하지만 그 당시 CNN에는 큰 결점이 하나 있습니다. 특정 과업을 수행하기 위해서는 매번 특정 loss를 설계해야하기 때문에 포괄적인 작업을 할 수 없다는 것입니다. 실제 pix2pix에서 진행하는 실험들을 CNN으로 시도한 적 있으나 대부분의 결과는 blurry했습니다. 그래서 논문의 저자들은 CGAN이라는 조건부 생성모델을 바탕으로 포괄적인 작업을 수행할 수 있는 pix2pix을 만들었습니다.
CGAN은 지난 번 민정님께서 잘 설명해주셨으니 넘어갈게요 :)

기본적으로 pix2pix은 생성모델이기 때문에 generator, discriminator가 필요합니다.

generator의 경우, CGAN과 굉장히 유사하게 작동합니다. 하지만 input으로 Noise vector와 class vector를 받는 CGAN과는 다르게 더 이상 Noise vector를 필요로 하지 않습니다. 오로지 이미지만을 input으로 받아 output을 생성하는 것입니다.

discriminator의 경우, 2가지를 input으로 받습니다. 기본적으로 generator에 넣었던 input 이미지, 이와 하나의 pair가 될 진짜 이미지나 생성된 이미지를 input으로 받습니다. 이 2가지를 동시에 discriminator에 넣었을 때, discriminator는 pair를 비교하여 생성된 이미지인지 진짜 이미지인지를 구분하는 것입니다. 이 일련의 과정으로 학습을 마치게 됩니다.

여기서 알아두셔야 할 점은 기존의 discriminator와 generator를 한 단계 발전시켰다는 점입니다. generator는 U-net구조와 skip connection을 사용했고, discriminator는 patchgan을 사용했다는 점입니다.

U - net


[출처 : https://taeoh-kim.github.io/blog/image2image/]

기본적으로 U-net은 encoder-decoder 구조를 skip-connection으로 발전시킨 구조입니다. 데이터가 인코더를 통하면 이미지의 feature들을 잘 추출해낼 수 있겠죠? 그리고 다시 디코더를 통하면 원하는 이미지를 만들 수 있을 것입니다. 그러나 이 과정에서 이미지의 형태나 해상도 등 정보의 손실은 어쩔 수 없이 발생하게 됩니다. 이러한 정보의 손실을 막기 위해서 skip - connection을 사용합니다. 이 뿐만 아니라 skip-connection을 사용하면 역전파 과정에서 vanishing gradient 문제도 해결할 수 있다는 장점이 있습니다.


[출처 : https://taeoh-kim.github.io/blog/image2image/]

모델의 구조는 위와 같습니다. 각각 8개의 block으로 구성되어 있으며, 유의하셔야 점은 decoder의 처음 3개의 block에서 Batch Normalizaion과 Dropout이 같이 진행되는 것입니다.

    def __init__(self, image_channels=3, inner_channels=64, n_layers=8, dropout=0.5, norm_layer=nn.InstanceNorm2d):
        super().__init__()
        assert n_layers >= 5

        block = UNetSkipConnectionBlock(inner_channels*8, inner_channels*8, 'innermost', norm_layer=norm_layer)
        for _ in range(n_layers-5):
            block = UNetSkipConnectionBlock(inner_channels*8, inner_channels*8, 'middle', block, dropout, norm_layer=norm_layer)
        block = UNetSkipConnectionBlock(inner_channels*4, inner_channels*8, 'middle', block, dropout, norm_layer=norm_layer)
        block = UNetSkipConnectionBlock(inner_channels*2, inner_channels*4, 'middle', block, dropout, norm_layer=norm_layer)
        block = UNetSkipConnectionBlock(inner_channels, inner_channels*2, 'middle', block, dropout, norm_layer=norm_layer)
        self.model = UNetSkipConnectionBlock(image_channels, inner_channels, 'outermost', block)

    def forward(self, x):
        return self.model(x)

generator 구조 코드 [출처 : https://www.secmem.org/blog/2020/07/19/pix2pix/]

    def __init__(self,
                 outer_channels,
                 inner_channels,
                 module_type,
                 submodule=None,
                 dropout=0.5,
                 norm_layer=nn.InstanceNorm2d
                 ):
        super().__init__()
        
        if module_type not in ['innermost', 'outermost', 'middle']:
            raise Exception('no such module type')

        if type(norm_layer) == functools.partial:
            use_bias = norm_layer.func == nn.InstanceNorm2d
        else:
            use_bias = norm_layer == nn.InstanceNorm2d
        
        down_conv = nn.Conv2d(outer_channels, inner_channels, kernel_size=4, stride=2, padding=1, bias=use_bias)
        down_relu = nn.LeakyReLU(0.2, True)
        down_norm = norm_layer(inner_channels)

        up_relu = nn.ReLU(True)
        up_norm = norm_layer(outer_channels)

        self.outermost = module_type == 'outermost'
        if module_type == 'innermost':
            up_conv = nn.ConvTranspose2d(inner_channels, outer_channels, kernel_size=4, stride=2, padding=1, bias=use_bias)
            modules = [down_relu, down_conv, up_relu, up_conv, up_norm]
        elif module_type == 'outermost':
            up_conv = nn.ConvTranspose2d(inner_channels*2, outer_channels, kernel_size=4, stride=2, padding=1)
            modules = [down_conv, submodule, up_relu, up_conv, nn.Tanh()]
        else:
            up_conv = nn.ConvTranspose2d(inner_channels*2, outer_channels, kernel_size=4, stride=2, padding=1, bias=use_bias)
            modules = [down_relu, down_conv, down_norm, submodule, up_relu, up_conv, up_norm, nn.Dropout(dropout)]

        self. model = nn.Sequential(*modules)

    def forward(self, x):
        if self.outermost:
            return self.model(x)
        return torch.cat([x, self.model(x)], 1)

skip-connection 구조 코드 [출처 : https://www.secmem.org/blog/2020/07/19/pix2pix/]

PatchGAN

pix2pix의 discriminator는 PatchGAN입니다. PatchGan이라고 대단한 구조는 아닙니다. 기존의 GAN의 discriminator는 Image 전체를 보고 진짜인지 아닌지를 판별한다면, PatchGAN은 이미지를 조각내서 부분부분을 보고 진짜인지 아닌지를 판별합니다. 아래와 같은 그림처럼 말이죠. 그러면 Patch 단위로 loss의 역전파가 진행되기 때문에 좀 더 detail한 image를 만들 수 있게 되는 것이죠.

이 때 대체로 patch의 크기는 70 x 70 사이즈를 사용합니다. 그 이유는 이미지의 크기와 동일한 286 x 286 사이즈의 patch를 사용해도 70 x 70 사이즈의 결과물과 다를 바가 없고, 오히려 parameter만 증가해 학습시간에 악영향을 미치기 때문이라고 합니다. 모델의 구조는 아래와 같습니다.


[출처 : https://taeoh-kim.github.io/blog/image2image/]

    def __init__(self,
                 input_channels=6,
                 inner_channels=64,
                 n_layers=3,
                 norm_layer=nn.InstanceNorm2d
                 ):
        super().__init__()

        if type(norm_layer) == functools.partial:
            use_bias = norm_layer.func == nn.InstanceNorm2d
        else:
            use_bias = norm_layer == nn.InstanceNorm2d

        modules = [nn.Conv2d(input_channels, inner_channels, kernel_size=4, stride=2, padding=1), nn.LeakyReLU(0.2, True)]
        for i in range(n_layers-1):
            modules += [
                nn.Conv2d(inner_channels*min(2**i, 8), inner_channels*min(2**(i+1), 8), kernel_size=4, stride=2, padding=1, bias=use_bias),
                norm_layer(inner_channels*min(2**(i+1), 8)),
                nn.LeakyReLU(0.2, True)
            ]
        modules += [
            nn.Conv2d(inner_channels * min(2 ** (n_layers-1), 8), inner_channels * min(2 ** n_layers, 8), kernel_size=4, stride=1,
                      padding=1, bias=use_bias),
            norm_layer(inner_channels * min(2 ** n_layers, 8)),
            nn.LeakyReLU(0.2, True),
            nn.Conv2d(inner_channels * min(2 ** n_layers, 8), 1, kernel_size=4, stride=1, padding=1)
        ]
        self.model = nn.Sequential(*modules)

    def forward(self, x):
        return self.model(x)

discriminator 구조 코드 [출처 : https://www.secmem.org/blog/2020/07/19/pix2pix/]

Loss

pix2pix의 기본적인 loss는 위와 같은 형식입니다. 굉장히 익숙한 앞부분과 생소한 뒷부분으로 구성되어 있죠.


pix2pix은 생성모델이므로 adversarial loss를 사용합니다. 이 때, loss는 주로 BCE loss를 사용한다고 합니다.


위의 adversarial loss만을 사용하면 생성된 이미지가 약간 흐리게 나온다고 합니다. 그래서 논문의 저자들은 조금이라도 개선된 이미지를 만들기 위해 L1 distance (Manhattan distance)를 사용합니다. 즉, 만들어진 이미지와 실제 이미지 사이의 픽셀간의 거리를 구해 이를 최소화하여 최대한 원래 이미지처럼 만들 수 있게 하는 것입니다.

그래서 최종적으로 제일 위의 loss function을 만들고, 람다라는 hyper parameter를 조절하여 최적의 loss function을 찾아갑니다.

CycleGAN

위에서 설명한 pix2pix 모델은 paired한 이미지 데이터셋을 가지고 학습을 진행했습니다. 하지만 paired 데이터셋은 실제로 구하기 굉장히 어렵고, 구한다고 하더라도 데이터셋에 들어가는 비용이 만만치 않습니다. 뿐만 아니라 아예 못구하는 데이터들도 수두룩합니다. 그래서 논문의 저자들은 짝지어진 예시 없이 X라는 도메인으로부터 얻은 이미지를 타겟 도메인 Y로 바꾸는 방법인 CycleGAN을 제시합니다.

paired dataset의 경우, X 이미지의 좌표값과 Y 이미지의 좌표값이 어떻게 대응되는지에 대한 정보들이 담겨있습니다. 그러나 unpaired dataset은 일대일로 매칭된 것이 아니기 때문에 이에 대한 정보가 존재하지 않습니다. 이를 개선하고자 저자들은 cycle consistency loss function을 사용한 것입니다.

구조

기본적으로 CycleGAN은 2개의 GAN을 필요로 합니다. X에서 Y의 이미지를 만들어주는 generator와 이 이미지가 진짜인지 판단하는 discriminator, 그리고 반대의 경우까지 고려한 것이죠.

기본적으로 discriminator는 pix2pix과 마찬가지로 patchGAN을 사용합니다. generator의 경우, pix2pix과 같은 U - net을 기반으로 발전시켰다. 아래와 같이 U-net에 DCGAN과 residaul connection을 추가한 방식을 사용했습니다. 이렇게 만들면서 확실히 정보의 손실량이 줄어, 고해상도 처리를 더 수월하게 만들었습니다.

    if netG == 'resnet_9blocks':
        net = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=9)
    elif netG == 'resnet_6blocks':
                net = ResnetGenerator(input_nc, output_nc, ngf, norm_layer=norm_layer, use_dropout=use_dropout, n_blocks=6)
    elif netG == 'unet_128':
        net = UnetGenerator(input_nc, output_nc, 7, ngf, norm_layer=norm_layer, use_dropout=use_dropout)
    elif netG == 'unet_256':
        net = UnetGenerator(input_nc, output_nc, 8, ngf, norm_layer=norm_layer, use_dropout=use_dropout)
    else:
        raise NotImplementedError('Generator model name [%s] is not recognized' % netG)
    return init_net(net, init_type, init_gain, gpu_ids)

일반적으로 작동원리는 아래의 그림과 같습니다. 실제 이미지가 generator를 통하면 가짜 이미지를 생성합니다. 이 때, discriminator는 이 이미지가 진짜인지 가짜인지를 자신이 학습한 데이터를 토대로 판별하게 됩니다. output은 patchGAN을 사용했기 때문에 그림과 같이 각 부분마다 진짜인지 아닌지를 판별해서 구해집니다.

    # define networks (both Generators and discriminators)
    # The naming is different from those used in the paper.
    # Code (vs. paper): G_A (G), G_B (F), D_A (D_Y), D_B (D_X)
    self.netG_A = networks.define_G(opt.input_nc, opt.output_nc, opt.ngf, opt.netG, opt.norm,
                                    not opt.no_dropout, opt.init_type, opt.init_gain, self.gpu_ids)
    self.netG_B = networks.define_G(opt.output_nc, opt.input_nc, opt.ngf, opt.netG, opt.norm,
                                    not opt.no_dropout, opt.init_type, opt.init_gain, self.gpu_ids)

    if self.isTrain:  # define discriminators
        self.netD_A = networks.define_D(opt.output_nc, opt.ndf, opt.netD,
                                        opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.gpu_ids)
        self.netD_B = networks.define_D(opt.input_nc, opt.ndf, opt.netD,
                                        opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.gpu_ids)

def forward(self):
    """Run forward pass; called by both functions <optimize_parameters> and <test>."""
    self.fake_B = self.netG_A(self.real_A)  # G_A(A)
    self.rec_A = self.netG_B(self.fake_B)   # G_B(G_A(A))
    self.fake_A = self.netG_B(self.real_B)  # G_B(B)
    self.rec_B = self.netG_A(self.fake_A)   # G_A(G_B(B))

Loss



기본적으로 논문에서 제시한 loss function은 처음 이미지와 같습니다. GAN이 2개이기 때문에 각각의 adversarial loss와 cycle consistency loss를 고려한 것이죠. 이 후 이 function을 논문에서 차차 발전시켜서 두 번째 이미지와 같은 loss function을 만들게 됩니다. 이를 하나하나 살펴보겠습니다.

Cycle Consistency loss

Cycle Consistency를 사용하는 이유는 저희가 unpaired dataset을 사용하기 때문입니다. 위에서 언급했듯이 paired dataset의 경우, X와 Y의 이미지의 좌표값이 있어서 이 관계에 대한 정보가 있습니다. 반면 unpaired dataset은 이 정보가 없으며, 각 이미지간의 대응관계 너무 많기 때문에 사실상 만들어진 이미지가 실제와 pair라고 확정지을 수 없습니다. 즉, mapping의 제약이 적다는 의미이며 이는 결국 mode collapse를 야기할 수 있습니다. 이를 방지하기위해 Cycle consistency를 사용하는 것입니다.

단순 mapping이 아닌 돌아오는 mapping까지 고려하여, 최대한 mapping의 가능성을 줄여주는 것이죠. 그래서 아래의 loss function이 나오게 된 것입니다.

Adversarial Loss

CycleGAN 역시 생성모델이기에 adversarial loss를 사용합니다. 하지만 여기서 알아둬야할 점은 일반적인 GAN처럼 BCE loss를 사용하지 않고 Least Square loss를 사용한다는 점입니다.

논문에서는 이렇게 Least Sqaure loss를 사용했을 때, 좀 더 안정적으로 학습이 가능했고, 높은 퀄리티의 이미지를 생성했다고 합니다. 그리고 이 loss를 사용하면 BCE loss를 사용했을 때 나타나는 mode collapse나 vanishing gradient의 가능성을 줄여준다고 합니다.

Identity Loss

마지막으로 Identity Loss입니다. 논문의 저자들은 일부 작업에 이 loss를 적용했습니다. 일반적으로 모델은 X에서 Y로 가는 mapping을 학습합니다. 아래의 이미지가 대표적인 결과물입니다.

input은 모네의 그림인데요. 그림이 들어오면 마치 사진처럼 굉장히 잘 바꾼다는 것은 확실합니다. 하지만 색상이나 분위기를 완전히 바뀌었습니다. 이처럼 분위기나 색상을 유지하기 위해 Identity loss를 사용한 것입니다.

즉, Identity loss를 사용하는 이유는 Y에서 Y로 가는 mapping에 대한 제약을 걸어주는 것입니다. Y domain의 image가 input으로 들어왔을 때 그 특징을 유지하려면, 모델은 단순히 X를 Y로 만드는 단순 작업(?)을 하는 것이 아니라 들어온 input 이미지를 한 번 더 들여다 봐야한다는 것이죠.

그래서 위와 같은 identity loss를 만들어주는 것입니다.

    if gan_mode == 'lsgan':
        self.loss = nn.MSELoss()
    elif gan_mode == 'vanilla':
        self.loss = nn.BCEWithLogitsLoss()
    elif gan_mode in ['wgangp']:
        self.loss = None
    else:
        raise NotImplementedError('gan mode %s not implemented' % gan_mode)

        self.criterionGAN = networks.GANLoss(opt.gan_mode).to(self.device)  # define GAN loss.
        self.criterionCycle = torch.nn.L1Loss()
        self.criterionIdt = torch.nn.L1Loss()

한계

지금까지 본 CycleGAN은 굉장히 좋은 성능을 보여줬습니다. 하지만 이 모델 역시 한계는 존재했습니다. 우선 이미지의 모양을 바꾸진 못한다는 점입니다. CycleGAN은 주로 분위기나 색상을 바꾸는 것으로 스타일을 학습하여 다른 이미지를 생성합니다. 그러다보니 피사체의 모양 자체는 바꿀 수가 없었습니다. 그리고 데이터셋의 분포가 불안정하면 이미지를 제대로 생성할 수 없게 됩니다.

위의 예시처럼 사과를 오렌지로 바꾸는 작업은 모양을 바꾸지 못하는 오류입니다. 그리고 사람을 태운 말을 얼룩말로 바꿀 때, 사람까지 얼룩말이 되는 것은 데이터셋에 사람이 말을 탄 데이터가 없기 때문에 나타난 결과입니다.

Reference

CycleGAN, pix2pix 논문 :
https://arxiv.org/abs/1611.07004
https://arxiv.org/abs/1703.10593
coursera 강의 : Apply Generative Adversarial Networks (GANs)
pix2pix 관련 :
https://taeoh-kim.github.io/blog/image2image/
https://greeksharifa.github.io/generative%20model/2019/04/07/Pix2Pix/
https://www.secmem.org/blog/2020/07/19/pix2pix/
CycleGAN 관련 :
https://taeoh-kim.github.io/blog/image2image/
https://comlini8-8.tistory.com/9
https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix
https://medium.com/curg/cyclegan-unpaired-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-%ED%95%99%EC%8A%B5%ED%95%98%EA%B3%A0-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B3%80%ED%99%98%ED%95%98%EA%B8%B0-6fca2f2cddd5

profile
투빅스 생성모델 세미나입니다.

9개의 댓글

comment-user-thumbnail
2020년 11월 7일

투빅스 14기 한유진

  • input 이미지와 ouput 이미지를 mpping하는 것을 목표로 하는 Image to Image Translation중 Pix2Pix와 CycleGAN에 대해서 배웠습니다.
  • paired한 dataset을 사용하는 분야인 Pix2Pix는 CGAN을 바탕으로 포괄적인 수행을 할 수 있는 모델입니다. G는 noise vector없이 오직 image만을 입력으로 받아서 생성합니다. D는 (input image, real ouput) 또는 (input image, generated ouput)을 입력으로 받아서 real/fake를 구분합니다. Pix2Pix의 큰특징은 G에 U-net구조와 정보의 손실을 막기 위해 skip connection을 사용했고, D는 PatchGAN을 사용했다고 합니다.
  • paired한 dataset없이 X라는 도메인으로부터 얻은 이미지를 타켓도메인 Y로 바꾸는 방법인 CycleGAN에서 특징은 cycle consistency loss입니다. D는 adverserial loss만 있으면 되지만 G는 input image를 G에 넣었을 때 생성된 image를 다시 F에 넣었을 때 나온 이미지와 서로 비슷하게 만들어지면 mode collapse문제를 해결할 수 있기 때문에 도입된 loss입니다. 또한 identity loss는 일부 작업에만 사용된 loss로 분위기나 색상을 유지시키기 위해 도입된 loss입니다. CycleGAN의 한계는 이미지의 모양을 바꾸진 못한다는 점입니다. 그렇기 때문에 주로 분위기나 색상을 바꾸는 것으로 스타일을 학습하여 다른 이미지를 생성한다고 합니다.

Pix2Pix와 CycleGAN 관련 그림들과 코드를 활용하여 설명해주셔서 각 모델들의 동작과정을 세세하게 배울 수 있었던 좋은 수업이었습니다. 좋은강의 감사합니다!

답글 달기
comment-user-thumbnail
2020년 11월 9일

투빅스 14기 김상현
pix2pix와 cycleGAN에 관한 강의로 14기 정재윤님이 진행해주셨습니다.

Pix2Pix: CNN으로 시도한 이미지 처리 문제는 blurry한 결과를 생성했다. 이러한 문제를 개선하기 위해 CGAN이라는 조건부 생성모델을 바탕으로 포괄적인 작업을 수행할 수 있는 pix2pix 모델을 만들었다.

  • Generator의 경우 segmentation인 real input을 이용해서 realistic한 이미지를 생성한다. CGAN에서는 noise vector와 class vector를 받는 것과 차이가 있다. 또한 U-net 구조를 이용해 이미지를 생성한다.
  • Discriminator의 경우 generator의 input과 이와 쌍을 이루는 real/generated 이미지를 입력으로 받고 생성된 이미지인지 진짜 이미지인지를 판별한다. 또한 patchGAN 구조로 이미지를 조각내서 부분별로 진짜인지 아닌지를 판별하여 좀 더 detail 한 image를 만들 수 있다.
  • Loss function은 adversarial loss만을 사용한 이미지의 경우 흐릿한 이미지를 생성할 수 있어 L1 distance를 추가한 loss를 사용한다. 즉 L1 loss를 이용해 만들어진 이미지와 실제 이미지의 픽셀간 거리를 최소화하는 loss이다.

CycleGAN: 실제로 paired dataset을 구하기 어렵다. 따라서 짝지어진 예시 없이 x라는 도메인으로부터 얻은 이미지를 타겟 도메인 y로 바꾸는 방법인 cycleGAN을 만들었다.

  • x -> y를 생성하는 G1, y -> x를 생성하는 G2로 두 개의 생성자와 이 둘을 판별한 두 개의 판별자가 필요하다.
  • 생성자와 판별자의 기본적인 구조는 pix2pix와 마찬가지로 U-net과 patchGAN을 이용했다.
  • Loss function은 기존의 adversarial loss와 함께 추가로 cycle consistency loss, identity loss가 합쳐져 있다. cycle consistency loss는 unpair한 데이터의 mode collapse를 막기 위해 존재하며 G1으로 생성된 이미지를 입력으로 사용하여 G2로 생성된 이미지와 원래의 이미지의 차이의 loss이며, 여기서 차이는 L1 distance를 이용한다. 또한 identity loss는 기존의 분위기와 색상을 유지하기 위해 존재하며 해당 이미지를 해당 이미지를 생성하는 생성자를 이용해 생성된 이미지와 차이를 loss이며, 여기서 차이는 위와 마찬가지로 L1 distance를 이용한다.

pix2pix와 cycleGAN의 전체적인 구조 및 손실함수가 어떻게 정의되는지 이해할 수 있었습니다.
유익한 강의 감사합니다!

답글 달기
comment-user-thumbnail
2020년 11월 10일

투빅스 11기 이도연
이번 강의는 Image to Image Translation 강의로 Pix2Pix와 CycleGAN에 대해 배웠습니다. 좋은 강의 감사합니다!

  • Image to Image Translation이란 이미지 데이터를 이용해 input 이미지와 output 이미지를 mapping하는 것을 목표로 하는 생성모델의 한 분야다. 여기에는 대표적으로 paired한 데이터셋을 사용하는 Pix2Pix와 unpaired한 데이터셋을 사용하는 CycleGAN이 있다.
  • Pix2Pix는 라벨을 실제 이미지로 바꾼다던지, 낮을 밤으로 바꾸고, 위성 지도를 그래픽 지도로 바꾸는 등 여러 Process가 가능하다.
  • 단순히 CNN으로 이 문제를 풀려고 한다면 모든 Pixel의 error를 loss로 사용해 각 픽셀별로 완벽한 답을 찾기 보다는 전체적인 loss를 줄이려고 하기 때문에 blurry한 이미지를 생성하게 된다. 여기서는 input image라는 조건을 주고 그에 맞는 output image를 생성하기 위해 CGAN을 바탕으로 Pix2Pix를 만들었다.
  • Pix2Pix의 Generator에서는 U-Net을 사용했다. input을 output에 mapping 할 때 해상도가 동일하고, 어느정도 detail과 shape을 유지하려는 성질을 가지기 때문에 Encoder-Decoder 구조를 사용하는데, bottleneck 레이어를 통과하기 때문에 정보의 손실이 필연적이다. 이를 해결하기 위해 skip-connection을 추가한 U-Net 구조를 사용한다.
  • Discriminator는 PatchGAN을 사용했다. Patch 단위로 이미지를 보고 각 Patch 별로 이 부분이 진짜인지 가짜인지 판별한다. 더 적은 parameter를 가지고 학습하고 더 빠르며 Patch 단위로 역전파가 진행되기 때문에 좀 더 detail한 부분에서 feedback을 할 수 있다.
  • CycleGAN은 Pix2Pix를 발표한 연구실에서 이어 나온 논문인데, cycle consistency로 unpaired한 데이터셋의 문제를 해결한다.
  • X->Y, Y->X로 2개의 Generator와 2개의 Discriminator가 학습을 진행한다.
  • CycleGAN의 Generator는 U-Net구조에 DCGAN과 residual connection을 추가한 방식을 사용하고, Discriminator는 PatchGAN을 사용했다.
  • loss는 기본적인 GAN의 loss인 adversarial loss와 여기서 중요한 부분인 cycle-consistency loss, 마지막으로 identity-mapping loss를 사용한다.
  • cycle-consistency loss는 원본으로 복구 가능한 정도만 바꾸자, identity-mapping loss는 input에 대해 더 잘 보존해보자라고 쉽게 생각해 볼 수 있다.
  • CycleGAN은 주로 분위기나 색상, 질감에 대해서는 잘 적용하지만 객체의 모양 자체를 바꿀 수는 없다는 등의 한계가 있다.
답글 달기
comment-user-thumbnail
2020년 11월 10일

투빅스 14기 박준영

이번강의는 Image to Image Translation의 강의로 pix2pix, cyclegan에 대해
투빅스 14기 정재윤님께서 강의해주셨습니다.

  • Image to Image translation이란 이미지 데이터셋을 사용하여 input, output을 매핑하는 것을 목표로 합니다.
    이미지에 컬러를 입힌다거나 테두리를 실제처럼 만드는 것에 활용할 수 있다.

  • paired한 데이터셋을 사용하는 분야는 pix2pix가 있다. pix2pix의 Generator는 Noise vector없이
    이미지를 input으로 받아 output이미지를 생성한다. pix2pix의 discriminator의 경우 generator의 input
    이미지와 pair가 될 진짜 이미지나 생성된 이미지를 input으로 받아 생성된 이미지를 구별해낸다.

  • 이때 pix2pix의 generator는 U-net, skip connection을 사용하여 이미지의 형태나 해상도 손실 문제를 해결했고 vanishing gradient문제를 해결했다.
    pix2pix의 discriminator은 patchgan을 사용했다. patch gan을 사용함으로써 이미지를 조각 내어 진짜 가짜를 판별한다. patch Gan을
    사용함으로써 파라미터의 연산도 줄이고 이미지의 정보 손실을 줄이면서 이미지를 구별해낸다.

  • pix2pix는 adversarial loss의 이미지 blur문제를 해결하기 위해 manhattan distance를 사용하여 거리를 최소화 시켜 이미지를 비슷하게 만듦

  • paired한 데이터 셋을 구하기 어렵기 때문에 unpaired한 데이터셋을 사용하는 cyclegan을 제시했다.

  • unpaired한 데이터로 gan과 discriminator 각각 2개 만들어 pix2pix와 비슷한 효과를 얻을 수 있다.
    마치 X의 데이터를 gan 하나에 통과해서 생성된 X 이미지를 만들고 Y데이터를 다른 gan에 통과시켜 생성된 y이미지를 만든다.
    그리고 생성된X, Y와 실제 X,Y 이미지를 2개의 discriminator에 통과시켜 이미지를 구별한다.

  • cyclegan도 pix2pix와 비슷하게 discriminator에 patchGan을 사용하고 generator의 경우 U-net을 사용했다.
    cyclegan 역시 pix2pix와 비슷한 방법으로 사용하여 정보의 손실량을 줄이고 고해상도 처리를 수월하게 만들었다.

  • unpaired 데이터셋을 사용하는 cyclegan paired하다고 단정지을 수 없기 때문에 Cycle consistency를 사용하여 mode collapse를 방지한다.

  • 하지만 CycleGAN은 피사체의 모양과 데이터셋의 분포가 불안정하면 이미지를 제대로 생성할 수 없다.

이번 강의로 pix2pix와 cycleGAN의 구조와 코드를 활용해서 각 모델의 구조와 구현하는 법을 알게된 수업이었습니다. 강의 감사합니다.

답글 달기
comment-user-thumbnail
2020년 11월 10일

투빅스 13기 신민정
이번 image translation강의는 정재윤님이 진행해주셨습니다.
대표적인 image-to-image transaltion기법인 pix2pix과 CycleGAN에 대해 배워보았습니다.

pix2pix

pix2pix은 paired한 데이터로 학습이 진행됩니다. 주로 한종류의 이미지 데이터에 컴퓨터비전으로 전처리하여 쌍을 만들게됩니다. pix2pix에서는 noize vector z가 아닌 실제 이미지를 입력으로 받게 됩니다.
Discriminator

  • PatchGAN구조 : 이미지를 조각내서 부분부분을 real or fake 판단합니다. 맨 마지막 레이어에 sigmoid를 사용합니다. 대부분 70x70 patch사용합니다.

Generator

  • U-net 구조와 skip-connection사용
    -U-net : encode&decoder구조에 skip connection을 추가하여 정보 손실을 방지하고 vanishing gradient문제 해결합니다.

Loss
adversarial loss + lamda*L1 distance
바닐라GAN에서 사용한 adversarial loss를 사용하고 블러리한 이미지가 나오는 것을 방지하기 위하여 L1항(||y-G(x,z)||)을 추가합니다. 하이퍼파라미터 람다를 조절하여 최적화를 진행합니다.

CycleGAN

unpaired한 이미지 데이터셋으로 학습을 진행합니다. X-domain의 데이터에 Y-domain의 스타일을 입히는 모델입니다. 두개의 GAN 네트워크가 학습되고, 각각 X->Y, Y->X의 방향으로 학습됩니다.
Discriminator

  • pix2pix과 동일하게 PatchGAN구조

Generator

  • U-net구조에 skip-connection(pix2pix과 동일한 기능)과 residual connection을 추가하여 정보의 손실량을 줄이고 고해상도 이미지 처리를 하였다.

Loss

  • Cycle Consistency Loss : X->Y->X 고려. mode collapse 방지
  • Adversarial Loss
  • Identity Loss : 분위기나 색생을 유지해 주는 기능

이미지에 스타일을 입히는 작업은 잘하나, 이미지의 모양을 바꾸지는 못하는 한계가 있습니다.

pix2pix과 CycleGAN의 차이와 PatchGAN,U-Net 구조의 장단점을 배울 수 있는 의미있는 시간이었습니다. 또한 Cycle Loss에 대해 자세히 설명해주셔서 좋았습니다. 알찬 강의 감사드립니다.

답글 달기
comment-user-thumbnail
2020년 11월 10일

투빅스 14기 박지은

  • pix2pix는 조건부 생성모델인 CGAN을 이용하여 CNN보다 더 포괄적 작업을 수행할 수 있게 합니다. 이 때, 생성자는 CGAN과 유사하지만 noise vector는 필요없고 이미지만 input으로 받습니다. 판별자는 생성자에 넣었던 input 이미지와 이와 쌍이 될 실제 이미지나 생성된 이미지를 input으로 받습니다.
  • pix2pix의 생성자는 U-net 구조를 가지고, skip connection을 사용합니다. 이는 정보의 손실과 vanishing gradient 문제를 막습니다. 판별자에서 쓰이는 patchGAN은 이미지를 patch 단위로 진위 여부를 판별하여 더 자세한 이미지를 생성할 수 있습니다. loss는 adversarial loss와 L1 distance를 사용해 생성된 이미지와 실제 이미지 간의 픽셀 거리를 최소화합니다.
  • cycleGAN은 pix2pix와 달리 pair가 없는 데이터셋의 경우, X 도메인으로부터 얻은 이미지를 Y로 바꾸는 방법입니다.
  • 판별자는 patchGAN을 사용합니다. 생성자는 U-net에 DCGAN과 residual connection을 추가합니다. GAN을 각각 2개씩 사용하는데, 이는 최대한 mapping의 가능성을 줄이기 위하여 단순 mapping 뿐만이 아니라 돌아오는 mapping까지 고려하기 위함입니다. 그래서 loss도 adversarial loss와 consistency loss를 고려했습니다. 또한 identity loss를 고려하여 Y에서 Y로 가는 mapping에 대한 제약을 통해 input 이미지의 분위기와 색상을 유지합니다. 그러나 모양 자체는 바꿀 수 없고 데이터셋의 분포가 불안정하면 이미지를 제대로 생성하기 어렵습니다.
    pix2pix와 cycleGAN에 대한 비교와 개념 정리를 친절하게 해주셔서 차이점을 이해하는 데에 더 도움이 되었습니다. 좋은 강의 감사드립니다.
답글 달기
comment-user-thumbnail
2020년 11월 10일

투빅스 14기 김민경

  • pix2pix는 image-to-image translation 중에서도 paired한 데이터셋을 사용하는 분야의 대표적인 모델이며 CGAN을 base로 한 모델이다.
  • pix2pix의 generator는 U-Net 구조를 가지기 때문에 encoder 부분을 decoder 부분과 skip-connection을 통해 연결하여 정보 손실을 막는다. 또한, 오로지 이미지만을 input으로 받아 output을 생성한다.
  • discriminator는 patchGAN 구조를 사용했기 때문에 전체 영역이 아니라, 특정 크기의 patch 단위로 진짜/가짜 이미지를 discriminate하기 때 detail한 부분의 특징을 추출할 수 있다.
  • pix2pix의 loss는 주로 BCE loss를 사용한다.
  • CycleGAN은 image-to-image translation 중에서도 unpaired한 데이터셋을 사용하는 분야의 대표적인 모델이다. 즉, pair한 이미지가 없어도 X라는 도메인으로부터 얻은 이미지를 타겟 도메인 Y로 전환할 수 있다.
  • CycleGAN은 2개의 GAN을 필요로 하기 때문에 2개의 generator와 2개의 discriminator를 훈련한다.
  • generator 중 하나는 G: X->Y로 학습하며 G(X)가 Y와 동등한지를 학습한다. 또 다른 하나는 F: Y->X를 학습한 다음에 Y에서 이미지를 가져와서 X에 있는 원본 이미지와 비슷한 이미지로 변환한다.
  • generator는 U-Net 구조를 base로 하면서 DCGAN과 residual connection을 추가한 구조를 사용했다. 이로 인해 정보의 손실을 크게 감소시켜서 고해상도 이미지 처리를 더욱 수월하게 했다.
  • discriminator 중 하나는 generator G로 생성된 이미지와 X에 있는 원본 이미지를 discriminate하고, 또 다른 하나는 generator F가 생성한 이미지와 Y에 있는 실제 이미지를 discriminate한다.
  • discriminator는 pix2pix와 마찬가지로 patchGAN 구조를 사용한다.
  • CycleGAN의 loss는 adversarial loss, cycle consistency loss, identity loss로 구성된다. adversarial loss는 실제 분포 X 또는 Y의 이미지와 생성된 이미지 간의 손실을 나타낸다. cycle consistency loss는 단순 mapping이 아닌 돌아오는 mapping까지 고려하여 있을 법한 mapping을 줄여주는 것이다. identity loss는 X->Y mapping을 할 때 Y->Y mapping에 대한 제약을 걸어줌으로써 자기 자신을 output으로 내놓도록 해서 이미지의 색감 등의 전반적인 분위기를 유지한다.
  • CycleGAN은 주로 분위기나 색상을 바꾸는 등의 style을 학습해서 다른 이미지를 생성하지만 이미지의 모양은 바꾸지 못한다는 한계가 있다. 또한, 데이터셋의 분포가 불안정하면 성능이 좋지 않다는 한계가 있다.
  • image-to-image translation의 대표 모델을 자세하게 설명해주셔서 정말 도움이 많이 되는 강의였습니다. 감사합니다:)
답글 달기
comment-user-thumbnail
2020년 11월 12일

투빅스 12기 김태한

  • 이번 강의 내용은 Image to Image Translation을 주제로하여 pix2pix, cyclegan에 대해 이루어졌습니다.

  • Image to Image Translation은 이미지 데이터셋을 통해서 input과 output을 mapping하도록 학습이 진행됩니다.

-이때 기존의 pix2pix의 경우는 pair된 이미지들을 통해 학습하여 mapping이 되도록합니다.

  • 기존의 나와있던 방법들은 skip connection을 응용한 U-net과 patchgan이 적용되어 있는 것이 특징입니다.

  • 그러나 이러한 pix2pix 모델은 pair한 이미지 데이터셋을 모으는데 어려움이 있어 unpair한 데이터 셋을 가지고도 학습이 될 수 있는 cyclegan이 나오게됩니다.

  • cyclegan의 경우 gan과 discriminator를 각각 2개씩 만들어 각 특징이 서로 mapping되도록 학습이 됩니다.

  • 이때 unpaired한 데이터로 인한 학습으로 인하여 발생할 수 있는 문제들을 cycle consistency loss를 이용하여 방지하여 줍니다.

좋은 강의 감사합니다 :)

답글 달기
comment-user-thumbnail
2020년 12월 20일

투빅스 13기 이예지:
이번 강의는 ‘Image to Image Translation’으로, 정재윤님이 진행하였습니다.

Image to Image Translation

  • Input 이미지와 output 이미지를 mapping하는 것
  • 대표적으로 pix2pix과 cycleGAN이 있음

Pix2Pix

  • CGAN(조건부 생성모델)을 바탕으로 포괄적인 작업을 수행하기 위함
  • 기존 GAN과는 다르게 noise vector를 필요로 하지 않음
  • Paired dataset을 사용함
  • generator는 U-net구조와 skip connection을 사용함
  • discriminator는 patchGAN을 사용함

CycleGAN

  • Unpaired dataset으로 학습하는 방식으로, 이를 위해 cycle consistency loss를 사용함
  • 두 개의 GAN을 사용하였으며, discriminator는 U-net 기반으로 발전시켰음

좋은 강의 감사합니다 :)

답글 달기