一代宗师__循环一致性生成对抗网络(CycleGAN)(八)

本文深入解析CycleGAN模型,一种能够将某一类图片转换成另一类图片的生成对抗网络。不同于传统GAN,CycleGAN采用双向生成机制,即使在无配对数据的情况下也能训练。文章详细介绍了其原理、结构及损失函数,并通过实例展示了CycleGAN与pix2pix模型的对比,突出了CycleGAN在图像转换任务上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介
CycleGAN是在2017年发表的一篇文章《Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks》,同一时期还有两篇非常类似的DualGAN和DiscoGAN,简单来说,它们的功能就是:自动将某一类图片转换成另外一类图片。传统的GAN是单向生成,而CycleGAN是互相生成,网络是个环形,所以命名为Cycle。并且CycleGAN一个非常实用的地方就是输入的两张图片可以是任意的两张图片,也就是unpaired。
在这里插入图片描述
原论文地址:https://arxiv.org/pdf/1703.10593.pdf

一、CycleGAN原理:
单向GAN详解:
CycleGAN本质上是两个镜像对称的GAN,构成了一个环形网络。其实只要理解了一半的单向GAN就等于理解了整个CycleGAN。
在这里插入图片描述
上图是一个单向GAN的示意图。我们希望能够把domain A的图片(命名为a)转化为domain B的图片(命名为图片b)。为了实现这个过程,我们需要两个生成器GAB和GBA,分别把domain A和domain B的图片进行互相转换。图片A经过生成器GAB表示为Fake Image in domain B,用GAB(a)表示。而GAB(a)经过生辰器GBA表示为图片A的重建图片,用GBA(GAB(a))表示。最后为了训练这个单向GAN需要两个loss,分别是生成器的重建loss和判别器的判别loss。
1.判别器loss:
判别器DB是用来判断输入的图片是否是真实的domain B图片,于是生成的假图片GAB(A)和原始的真图片B都会输入到判别器里面,公示挺好理解的,就是一个0,1二分类的损失。最后的loss表示为:
在这里插入图片描述
2.生成器loss:
生成器用来重建图片a,目的是希望生成的图片GBA(GAB(a))和原图a尽可能的相似,那么可以很简单的采取L1 loss或者L2 loss。最后生成loss就表示为:
在这里插入图片描述
以上就是A→B单向GAN的原理。

CycleGAN详解:
CycleGAN其实就是一个A→B单向GAN加上一个B→A单向GAN。两个GAN共享两个生成器,然后各自带一个判别器,所以加起来总共有两个判别器和两个生成器。一个单向GAN有两个loss,而CycleGAN加起来总共有四个loss。CycleGAN论文的原版原理图和公式如下:
在这里插入图片描述
我们之前已经说过,CycleGAN的原理可以概述为:将一类图片转换成另一类图片。也就是说,现在有两个样本空间,X和Y,我们希望把X空间中的样本转换成Y空间中的样本。
因此,实际的目标就是学习从X到Y的映射。我们设这个映射为G。它就对应着GAN中的生成器,G可以将X中的图片X转换为Y中的图片G(x)。对于生成的图片,我们还需要GAN中的判别器来判别它是否为真实图片,由此构成对抗生成网络。设这个判别器为 D{Y} 。这样的话,根据这里的生成器和判别器,我们就可以构造一个GAN损失,表达式为:
在这里插入图片描述
这个损失实际上和原始的GAN损失是一模一样的,但单纯的使用这一个损失是无法进行训练的。原因在于,映射G完全可以将所有x都映射为Y空间中的同一张图片,使损失无效化。我们再假设一个映射F,它可以将Y空间中的图片y转换为X中的图片F(y)。同样的我们为F也引入一个判别器 D{X} ,由此可以同样定义一个GAN的损失:
在这里插入图片描述
CycleGAN同时学习G和F两个映射,并要求将X的图片转换到Y空间后,应该还可以转换回来。这样就杜绝模型把所有X的图片都转换为Y空间中的同一张图片了。对此,作者又提出了所谓的“循环一致性损失”(cycle consistency loss)。
而循环一致性损失(两个生成器的loss加起来)就定义为:
在这里插入图片描述
最终网络的所有损失加起来为:
在这里插入图片描述

下面放一张网友们自制的CycleGAN示意图,比论文原版的更加直观,出处见水印。
在这里插入图片描述
在这里插入图片描述
CycleGAN结果展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
CycleGAN与pix2pix模型的对比
pix2pix也可以做图像变换,它和CycleGAN的区别在于,pix2pix模型必须要求成对数据(paired data),而CycleGAN利用非成对数据也能进行训练(unpaired data)。
比如,我们希望训练一个将白天的照片转换为夜晚的模型。如果使用pix2pix模型,那么我们必须在搜集大量地点在白天和夜晚的两张对应图片,而使用CycleGAN只需同时搜集白天的图片和夜晚的图片,不必满足对应关系。因此CycleGAN的用途要比pix2pix更广泛,利用CycleGAN就可以做出更多有趣的应用。

系列传送门:
初窥门径__生成对抗网络(GAN)(一)
小试牛刀__GAN实战项目之mnist数据集(二)
融会贯通__条件生成对抗网络(cGAN)(三)
炉火纯青__深度卷积生成对抗网络(DCGAN)(四)
登堂入室__生成对抗网络的信息论扩展(infoGAN)(五)
渐入佳境__距离生成对抗网络(WGAN)(六)
登峰造极__边界均衡生成对抗网络(BEGAN)(七)

### CycleGAN 网络架构解析 #### 生成器架构 CycleGAN 的生成器采用了一种称为残差块(Residual Block)的设计来保持输入图像的结构信息[^1]。具体来说,生成器由以下几个部分组成: - **编码器**:负责提取输入图像中的特征表示。通常通过一系列下采样操作实现,这些操作可以是卷积层加上步幅或最大池化层。 - **变换模块**:此阶段利用多个残差块处理来自编码器的信息,在不改变空间维度的情况下修改特征向量的内容属性。残差连接有助于缓解梯度消失问题并促进更深层次模型的学习能力。 - **解码器**:将中间表征重建为目标域内的输出图片形式。它执行的是上采样的过程,逐步恢复原始分辨率的同时引入自适应实例归一化 (AdaIN)[^3] 来调整风格特性。 ```python import torch.nn as nn class ResnetBlock(nn.Module): def __init__(self, dim, padding_type='reflect', norm_layer=nn.BatchNorm2d, use_dropout=False, use_bias=False): super(ResnetBlock, self).__init__() conv_block = [] p = 0 if padding_type == 'reflect': conv_block += [nn.ReflectionPad2d(1)] elif padding_type == 'replicate': conv_block += [nn.ReplicationPad2d(1)] elif padding_type == 'zero': p = 1 conv_block += [ nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias), norm_layer(dim), nn.ReLU(True)] if use_dropout: conv_block += [nn.Dropout(0.5)] p = 0 if padding_type != 'zero': conv_block += [nn.ReflectionPad2d(1)] conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias), norm_layer(dim)] self.conv_block = nn.Sequential(*conv_block) def forward(self, x): out = x + self.conv_block(x) return out ``` #### 判别器架构 判别器遵循 PatchGAN 设计理念,旨在判断局部区域而非整个图像的真实性。其核心在于多尺度感知机制,即能够捕捉不同大小的感受野上的模式差异,从而提高伪造样本检测精度。 #### 损失函数构成 除了传统的 GAN 对抗损失外,CycleGAN 还加入了循环一致性的约束条件以确保跨领域映射的一致性和稳定性。这意味着当数据点经两次连续转换后应回到初始状态附近,以此强化双向翻译的质量控制[^2]。 ```python criterionGAN = torch.nn.MSELoss() lambda_A = lambda_B = 10.0 def compute_loss(real_A, fake_B, rec_A, real_B, fake_A, rec_B): loss_G_A = criterionGAN(netD_A(fake_B).detach(), target_real) * lambda_A loss_D_A = (criterionGAN(netD_A(real_B), target_real) + criterionGAN(netD_A(fake_B.detach()), target_fake)) / 2 loss_G_B = criterionGAN(netD_B(fake_A).detach(), target_real) * lambda_B loss_D_B = (criterionGAN(netD_B(real_A), target_real) + criterionGAN(netD_B(fake_A.detach()), target_fake)) / 2 loss_cycle_A = criterionCycle(rec_A, real_A) * lambda_A loss_cycle_B = criterionCycle(rec_B, real_B) * lambda_B total_loss = (loss_G_A + loss_G_B + loss_cycle_A + loss_cycle_B) return { "total": total_loss, "gan_a": loss_G_A.item(), "gan_b": loss_G_B.item(), "cycle_a": loss_cycle_A.item(), "cycle_b": loss_cycle_B.item(), "discriminator_a": loss_D_A.item(), "discriminator_b": loss_D_B.item() } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值