Image-to-Image Translation with Conditional Adversarial Networks笔记

论文的链接:https://arxiv.org/pdf/1611.07004.pdf

代码链接:https://github.com/phillipi/pix2pix

本文是UC Berkeley AI研究院关于图像风格转化的文章,该文章首先指出gan可以自动地学习目标函数,从而对于一些难以确定目标函数的问题,gan可以取得更好的效果。同时采用U-网络代替原始的auto-encoder,实验表明u网络可以取得更好的效果。最后,作者比较了gan,cgan,gan+L1,cgan+L1等目标函数。

一、为什么用GAN

虽然神经网络可以自己学习参数来拟合数据,但是其仍然需要我们认为设置一个目标函数从而让神经网络根据该目标函数去优化模型的参数。对于一些简单的问题,目标函数可以根据经验轻松地得到。但是对于一些比较抽象的问题,比如图像的风格转化,如果我们简答的将模型转化后的图像和目标图像的每个像素点距离的平方和来作为目标函数进行优化,会使得产生的图片是模糊不清的。这是因为欧式距离会采信多个貌似合理的转化图片,然后对其进行平均。因而,如何设置一个合适的目标函数对于抽象的问题显得尤为重要。gan的提出正好解决这一问题,gan在训练中,判别器不断地更新,通过将判别结果作为生成器的优化目标去指引生成器如何优化,从而起到了生成器目标函数的作用。如果对于模糊不清的转化结果,判别器就可以轻易将其与真正的图片区别开来,同时又指导生成器去生成更加清晰可靠的图片。因而,gan一方面学习产生目标函数,另一方面又根据学习到的目标函数去对模型进行优化。

二、方法介绍

本文主要采用了gan和cgan两种模型。

2.1目标函数

对于cgan,其目标函数为:


对于gan,其目标函数为:


这里的区别在于,对于gan,判别器的输入只有模型转化后的图片G(x,z)和真实转化的图片y;而对于cgan,判别器的输入不仅有模型转化后的图片G(x,z)和真实转化的图片y,还有模型转化前的图片x。这样判别器在进行判别时,不仅仅会考虑转化后图片是否符合指定的风格,而且会考虑转化后图片的内容与原始的图片是否对应。

同时,我们要求生成器生成的图片不仅仅需要可以骗过判别器,而且需要其与真正转化后的图片在像素点上的距离尽可能的接近。由于使用L1可以比L2产生更加清晰的图片,故目标函数转化为:


2.2网络结构

2.2.1U型网络作为gennerator

传统上,我们使用auto-encoder作为网络结构,其在编码的时候通过降维的方法编码数据,然后让压缩后的数据重新解码成真实的图片,在这个过程中顺便实现了风格转化。该模型架构存在一个问题就是要求在数据编码时不损失重要的信息,否则无法解码得到想要的结果。而本文采用一种更为有效的U型网络,通过跳跃连接可以有效地避免模型压缩造成的信息损失。即在decoder的层叠加上encoder对应的层,如果遇到shape不一致时候,即裁剪用于叠加的encoder左边和右边使得其与decoder的shape保持一致,其思想跟deep residual network有点类似,区别在于U-net是将特征叠加起来,而deep residual network是将对应元素直接相加。


2.2.2PatchGAN

对于生成器的目标函数,前面提到是尽可能让转化的图片骗过判别器,同时在与目标的图片的距离(MAE/MSE)尽可能接近。可以骗过判别器要求生成的图片在抽象特征上与转化的图片接近(不会把马转化成羊),而与目标图片的距离尽可能地接近则要求其在细节上与转化的图片尽可能接近,这两方面保证了转化后图片的效果。

但是仅仅使用L1 loss去优化局部特征是不够的,L1每次只看到一个像素点,而无法考虑像素之间的联系,因而作者提出了PathcGAN来解决这一问题。PathcGAN是GAN的一个变种,只是对于判别器,其每次只输入N*N个像素点,然后让判别器对这N*N个像素点判断其是否为真,采用类似CNN滑窗的方法得到每个N*N框的判别器输出值,将这些输出值进行平均得到最后判别器的输出结果。

这种方法有两大优点,第一是由于网络参数数量的减少,提高了模型训练速度。第二是该模型可以同时训练不同规格的图片。作者尝试了不同patch的大小,实验证明了70*70的patch具有最好的效果,而且可以将256*256规格训练的模型用于512*512的图片中。

2.3优化方法

在优化上,本文采用mini-batch的SGD去配合Adam,同时对每一层采用BN(batch normalization),但这里作者采用的是测试集batch的统计量而不是训练集batch的统计量。

3 目标函数

作者比较了在目标函数中L1,gan,cgan等的作用。

如果单单是使用L1,会得到模糊但是合理的图片,使用GAN可以使图片变得清晰,但是会加入一些新的东西(真正转化出来的图片没有的),而L1配合GAN则可以减少这些不合理的东西并保证清晰度。如果不加入L1,那么cgan效果会好过gan,但是如果加上了L1,这种差别将会大大减少,因为L1会度量模型转化的图片和真正转化图片的距离,从而要求模型转化的图片的内容尊重原始图片的内容,而这一点正是cgan比gan好的地方。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
image-to-Image Translation with Conditional Adversarial Networks(条件对抗网络的图像到图像转换)是一种用于图像转换的深度学习方法。它通过训练一个生成器网络和一个判别器网络来实现图像的转换。生成器网络将输入图像转换为目标图像,而判别器网络则试图区分生成的图像和真实的目标图像。 这种方法的关键是使用对抗性训练。生成器网络和判别器网络相互竞争,以提高生成器网络生成逼真图像的能力。生成器网络通过最小化判别器网络对生成的图像的判别误差来学习生成逼真的图像。判别器网络则通过最大化对生成的图像和真实图像的判别能力来学习区分真实图像和生成图像。 在条件对抗网络中,生成器网络和判别器网络都接收额外的条件输入,以指导图像转换的过程。这个条件输入可以是任何与图像转换任务相关的信息,例如标签、语义分割图或其他图像。 通过训练生成器网络和判别器网络,条件对抗网络可以实现各种图像转换任务,例如将黑白图像转换为彩色图像、将马的图像转换为斑马的图像等。 这是一个使用条件对抗网络进行图像到图像转换的示例代码: ```python import tensorflow as tf from tensorflow.keras import layers # 定义生成器网络 def build_generator(): # 定义生成器网络结构 generator = tf.keras.Sequential() generator.add(layers.Conv2DTranspose(64, (4, 4), strides=(2, 2), padding='same', input_shape=(256, 256, 3))) generator.add(layers.BatchNormalization()) generator.add(layers.ReLU()) generator.add(layers.Conv2DTranspose(32, (4, 4), strides=(2, 2), padding='same')) generator.add(layers.BatchNormalization()) generator.add(layers.ReLU()) generator.add(layers.Conv2DTranspose(3, (4, 4), strides=(2, 2), padding='same', activation='tanh')) return generator # 定义判别器网络 def build_discriminator(): # 定义判别器网络结构 discriminator = tf.keras.Sequential() discriminator.add(layers.Conv2D(64, (4, 4), strides=(2, 2), padding='same', input_shape=(256, 256, 3))) discriminator.add(layers.LeakyReLU()) discriminator.add(layers.Conv2D(128, (4, 4), strides=(2, 2), padding='same')) discriminator.add(layers.BatchNormalization()) discriminator.add(layers.LeakyReLU()) discriminator.add(layers.Conv2D(256, (4, 4), strides=(2, 2), padding='same')) discriminator.add(layers.BatchNormalization()) discriminator.add(layers.LeakyReLU()) discriminator.add(layers.Conv2D(1, (4, 4), strides=(1, 1), padding='same')) return discriminator # 定义条件对抗网络 class cGAN(tf.keras.Model): def __init__(self, generator, discriminator): super(cGAN, self).__init__() self.generator = generator self.discriminator = discriminator def compile(self, g_optimizer, d_optimizer, loss_fn): super(cGAN, self).compile() self.g_optimizer = g_optimizer self.d_optimizer = d_optimizer self.loss_fn = loss_fn def train_step(self, real_images, labels): # 生成器网络生成假图像 with tf.GradientTape() as tape: fake_images = self.generator([real_images, labels], training=True) # 判别器网络判别真实图像和假图像 real_output = self.discriminator([real_images, labels], training=True) fake_output = self.discriminator([fake_images, labels], training=True) # 计算生成器和判别器的损失 g_loss = self.loss_fn(fake_output, tf.ones_like(fake_output)) d_loss_real = self.loss_fn(real_output, tf.ones_like(real_output)) d_loss_fake = self.loss_fn(fake_output, tf.zeros_like(fake_output)) d_loss = d_loss_real + d_loss_fake # 更新生成器和判别器的参数 g_gradients = tape.gradient(g_loss, self.generator.trainable_variables) d_gradients = tape.gradient(d_loss, self.discriminator.trainable_variables) self.g_optimizer.apply_gradients(zip(g_gradients, self.generator.trainable_variables)) self.d_optimizer.apply_gradients(zip(d_gradients, self.discriminator.trainable_variables)) return {"g_loss": g_loss, "d_loss": d_loss} # 创建生成器和判别器 generator = build_generator() discriminator = build_discriminator() # 创建条件对抗网络 cgan = cGAN(generator, discriminator) # 编译条件对抗网络 cgan.compile( g_optimizer=tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5), d_optimizer=tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5), loss_fn=tf.keras.losses.BinaryCrossentropy(from_logits=True) ) # 训练条件对抗网络 cgan.fit(dataset, epochs=100) # 使用生成器网络进行图像转换 input_image = ... label = ... output_image = generator([input_image, label]) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值