「这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战」
使用BicyleGAN进行多样化图像转换
Pix2pix
和 CycleGAN
是非常的流行GAN,不仅在学术界有许多变体,同时也有许多基于此的应用。但梯度下降法是,它们都有一个缺点——图像的输出看起来几乎总是相同的。例如,如果我们要执行斑马到马的转换,被转换的同一马的照片将始终具有相同的外观和色调。这是由于GAN固有的特性,它学会过滤了噪声的随机性。为了进行多样化图像转换,本文详解了 BicycleGAN
如何解决此问题以生成更丰富的图像,并利用 Tensor梯度下降法flow2
实现了 BicycleGAN
。
BicyleGAN效果展示
使用 Bicyletensorflow安装GAN
可以将一张图工作流程组织片进行多样化的转换,产生不同的样式和色彩:
BicycleGAN架构
在开始实现 BicycleGAN
之前,首先简要介绍架构一下。第一次听到这个名字,你可能会认为 Bicycle工作流程怎么规范GAN
是 CycleGAN
的变体,但其实它与 C架构图ycleGAN
无关,反而它是对 pix2pix
的一种改进。
pix2p架构ix
是一对一映射,其中给定输入的输出始终相同。当试图将噪声添加到生成器输入时,网络会忽略噪工作流程模板声,并且在输出图像中并不会产生变化架构。因此,需要寻找一种方法,强制生成器不得忽略噪声,而是使用噪声来生成多样化的图像,即一对多映射。
下图是 BicycleGAN
相关的模型和配置。图(a)
是推理的配置工作流程图模板样式,图像A与噪声相结合以生成图像Bhat B,可以将此看作是架构是什么意思 cGAN
。在BicyleGAN中,形状为(256, 256, 3)架构图
的图像A是条件,而从潜在编码 zz 采样的噪声为大小为8的一维向量。图(b)
是 pix2pix + 噪声
的训练配置。而 图(工作流程组织c)
和 图(d)
的两个配置由 BicycleGAN
训练时使用:
简而言之,Bic架构工程师ycleGAN
可以找到潜在编码z与目标图像B之间的关系,因此生成器可以在给定不同的z时架构工程师学会生成不同的图像Bhat B。如上图所示,BicycleGAN 通过组合 cVAE-GAN
和 cLR-GAN
这两种模型来做到这一点。
cVAE-GA架构图模板N
VAE-GAN
的作者认为,L1L_1损失并不是衡量图像视觉质量的良好指标。例如,如果图像向右移动几个像素,则人眼看起来可能没有什么不同,但会导致较大的L1L_1损失。因此使用 GAN
的鉴别器来像素勇士大创造攻略学习目标函数,以判断伪造的图像是否真实,并使用 VAE
作工作流程为生成器,生成的图像更清晰。如果忽略上图(c)
中的图像 AA,那就是 VAE-GAN
,由于以 AA 为条件,其成为条件梯度散度旋度 cVAE-GAN
。训练步骤如下:
-
VAE
将真实图片 BB 编码为多元高斯分布的潜在编码,然后从它们中采样以创建噪声输入,梯度散度旋度此流程是标准的VAE工作流程; - 使用图像 AA 作为条件及从潜矢量 zz 采样的噪声用于生成伪图像Bh架构师工资at B.
训练中的数据流为 B−>z−>BB->z->hattensorflowgpu版本 B ( 图(c)
中的实线箭头),总的损失函数由三个损失组成:
- LGANVAEmathcal L工作流程怎么写范本_{GAN}^{VAE}:对抗损失
- L1VAEmathcal L_1^{VAE}:L1L_1重建损失
- L架构工程师KLmathcal L_{KL}:KLKL散度损失
cLR-GAN(Conditional Latent Regressor GAN)
在 cVAE-GAN
中,对真实图像B进行编码,以提供潜在矢量的真实样本并从中进行采样。但是, cLR-GAN
的处理方式有所不同,tensorflow和pytorch的区别其首先使用生成器从随梯度是什么意思机噪声中生成伪图像 Bhat B ,然后对伪图像 Bhat B 进行编码,最后计算其与输入随机噪声差异。
前向计算步骤如下:
- 首先,类似于
cGAN
,架构师工资随机产生一些噪声,然后串联图像A以生成伪图像 Bhat B。 - 之后,使用来自tensorflow是干什么的
VAE-GAN
的同一编码器工作流程图将伪图像 Bhat B 编码为潜矢量。 - 最后,从编码的潜矢量中采样 zhat z ,并用输入噪声 zz 计算损失。
数据流为 z−>B−>zz-> hat B -> hat z ( 图(d)
中的实线箭头),有两个损失:
- LGA架构图Nmathcal L_{GAN}:对抗损失
-
L1latentmathcal L_1^{latent}:噪声
N(z)
与潜在编码之间的 L1L_1 损失
通过像素生存者2组合这两个数据流,在输出和潜在空间之间得到了一个双映射循环。 BicycleGAN
中的 bi
来自双映射(双向单射),这是一个数学术语,简像素单来说其表示一对一映射,并且是可逆的。在这种情况下,BicycleGAN
将输出映射到潜在空间,并且类似地从潜在空间映射到输出。总损失如下:
在默认配置中,=像素地牢10 = 10、late梯度公式nt=0.5_{latent} = 0.5、latent=0.01_{latent工作流程怎么写} = 0.01。
Bicyc梯度leGAN实现
BicycleGAN
中有三种类型的网络——生成器,鉴别器和编码器。为 cVAE-GAN
和 cLR-GAN
使用单tensorflow安装教程独的鉴别器可以提高图像质量,因此我们将使用四个网络-生成器,编码架构图器和两个鉴别器。
在生成器中插入潜在编码
将潜在编码工作流插入到生成器中有两种方法,如下图所示:
- 与输tensorflow菜鸟教程入图像进行级联;
- 将其插入到生成器的下采样路径中的其他层中。
实验发现前者效果很好。
有多种方法可以将不同形状的输入和条梯度稀释件结合起来。 BicycleGAN
使用的方法是多次重复潜在编码然后与输入图像架构师和程序员的区别连接。
在 BicycleGAN
中,潜在编码长度为8,我们从噪声分布中提取了8工作流程模板个样本,每个TensorFlow样本重复HW次以形成形状为 (H, W, 8)
的张量。换句话说,在8个通道中,其 (工作流是什么意思H,W)
特征图都是相同的。以下代码显示了潜在编码的拼像素工厂接和连接tensorflow训练模型:
input_image = layers.Input(shape=image_shape, name='input_image')
input_z = layers.Input(shape=(self.z_dim,), name='z')
z = layers.Reshape((1,1, self.z_dim))(input_z)
z_tiles = tf.tile(z, [self.batch_size, self.input_shape[0], self.input_shape[1], self.z_dim])
x = layers.Concatenate()([input_image, z_tiles])
下一步是创建两个模型,即 cVAE-GAN
和 cLR-GAN
,以合并网络并创建前向信息流。
cVAE-GAN
下面创建 cVAE-GAN
模型的代码,前向计算的实现:
images_A_1 = layers.Input(shape=input_shape, name='ImageA_1')
images_B_1 = layers.Input(shape=input_shape, name='ImageB_1')
z_encode, self.mean_encode, self.logvar_encode = self.encoder(images_B_1)
fake_B_encode = self.generator([images_A_1, z_encode])
encode_fake = self.discriminator_1(fake_B_encode)
encode_real = self.discriminator_1(images_B_1)
kl_loss = - 0.5 * tf.reduce_sum(1 + self.logvar_encode - tf.square(self.mean_encode) - tf.exp(self.logvar_encode))
self.cvae_gan = Model(inputs=[images_A_1, images_B_1], outputs=[encode_real, encode_fake, fake_B_encode, kl_loss])
我们在模型中使用了 Ktensorflowgpu版本LK工作流程怎么规范L 散度损失。由于可以直接根据均值和对数方差来计算 kl架构是什么意思_loss
,而无需在训练步骤中传入外部标像素画签,因此更加简单有效。
cLR-GAN
下工作流引擎面是 cLR-GAN
的实现,前向计算的实现:
images_A_2 = layers.Input(shape=input_shape, name='ImageA_2')
images_B_2 = layers.Input(shape=input_shape, name='ImageB_2')
z_random = layers.Input(shape=(self.z_dim,), name='z')
fake_B_random = self.generator([images_A_2, z_random])
_, mean_random, _ = self.encoder(fake_B_random)
random_fake = self.discriminator_2(fake_B_random)
random_real = self.discriminator_2(images_B_2)
self.clr_gan = Model(inputs=[images_A_2, images_B_2, z_random],
outputs=[random_real, random_fake, mean_random])
现在,我们现在已经定义了模型,下一步是实现训练步骤。
训练步骤
两种模型一起进行训练,但是具有不同的图像对。因此,在每个训练步骤中,我们两次获取数据,每个模型一次,这是通过创建数据管道来完成的,该数据管道将调用两次以加载数据:
images_A_1, images_B_1 = next(data_generator)
images_A_2, images_B_2 = next(data_generator)
self.train_step(images_A_1, images_B_1, images_A_2, images_B_2)
我们可以使用两种不同的方法来执行训练。一梯度下降法种是使用优化器和损失函数定义和编像素射击破解版译Keras模型,然后调用 train_on_batch()
来执行训练步骤,这种方法在定义明确的模型上效果很好。此外,我们也可以使用 tf.GradientTape
来更好地控制梯度更新。BicycleGAN
有两个模型,它们共享一个生成器和一个编码器,但像素射击是我们需要使用损失函数的不同组合来更新它们的参数,这使 train_on_batch
方法在不修改原始设置的情况下不可行。因此,我们使用 tf.GradientTape
将这两个模型的生成器和鉴别器组合为一个训练步骤,如下所示:
- 第一步是执行前tensorflow2.0教程向传递并收集两个模型的输出:
def train_step(self, images_A_1, images_B_1, images_A_2, images_B_2):
z = tf.random.normal((self.batch_size, self.z_dim))
real_labels = tf.ones((self.batch_size, self.patch_size, self.patch_size, 1))
fake_labels = tf.zeros((self.batch_size, self.patch_size, self.patch_size, 1))
with tf.GradientTape() as tape_e, tf.GradientTape() as tape_g, tf.GradientTape() as tape_d1, tf.GradientTape() as tape_d2:
encode_real, encode_fake, fake_B_encode, kl_loss = self.cvae_gan([images_A_1, images_B_1])
random_real, random_fake, mean_random = self.clr_gan([images_A_2, images_B_2, z])
- 接下来,我们通过反向梯度传播更新鉴别器:
# discriminator loss
self.d1_loss = self.mse(real_labels, encode_real) + self.mse(fake_labels, encode_fake)
gradients_d1 = tape_d1.gradient(self.d1_loss, self.discriminator_1.trainable_variables)
self.optimizer_d1.apply_gradients(zip(gradients_d1, self.discriminator_1.trainable_variables))
self.d2_loss = self.mse(real_labels, random_real) + self.mse(fake_labels, random_fake)
gradients_d2 = tape_d2.gradient(self.d2_loss,self.discriminator_2.trainable_variables)
self.optimizer_d2.apply_gradients(zip(gradients_d2, self.discriminator_2.trainable_variables))
- 然后,我们根据模型的输出计算损失。与
CycleGAN
相架构师似,BicycleGAN
也使用LSGAN
损失函数,即均方误差:
self.LAMBDA_IMAGE = 10
self.LAMBDA_LATENT = 0.5
self.LAMBDA_KL = 0.01
# Generator and Encoder loss
self.gan_1_loss = self.mse(real_labels, encode_fake)
self.gan_2_loss = self.mse(real_labels, random_fake)
self.image_loss = self.LAMBDA_IMAGE * self.mae(images_B_1, fake_B_encode)
self.kl_loss = self.LAMBDA_KL * kl_loss
self.latent_loss = self.LAMBDA_LATENT * self.mae(z, mean_random)
- 最后,还有生成器和编码器权重的更新。 L1L_1潜在编码损失仅用于更新生成器,而不用于更新工作流程模板编码器。由于针对损失同时优化将导致它们隐藏与潜在梯度散度旋度编码有关的信息,而不学习潜在编码中有意义架构师和程序员的区别的模式。因此,需要为生成器和编码梯度是什么意思器分别计算损失,并相应地更新权重:
encoder_loss = self.gan_1_loss + self.gan_2_loss + self.image_loss + self.kl_loss
generator_loss = encoder_loss + self.latent_loss
gradients_generator = tape_g.gradient(generator_loss, self.generator.trainable_variables)
self.optimizer_generator.apply_gradients(zip(gradients_generator, self.generator.trainable_variables))
gradients_encoder = tape_e.gradient(encoder_loss, self.encoder.trainable_variables)
self.optimizer_encoder.apply_gradients(zip(gradients_encoder, self.encoder.trainable_variables))
训练结果及分析
训练BicycleGAN,可以选择两个数据集架构设计-建筑结构草图或鞋子的边线草图。鞋子数据集的图像更简单,因此更易于训练,因此以此训练为例。以下图像是 BicycleGAN
训练结果的展示示例。第梯度一张图片是线稿,第二个图片是线稿对应的真实图像,右边的四个图片是生成的:
可以看到,由同一线稿生成的不同图片间的差异主要是颜色。它们都几乎完美地捕捉了鞋子的结构,但就细节捕捉而言,效工作流程图果并不十分理想,可以通过增加训练与超参数调整来获取更加优异的模型性能。