ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从GAN到pix2pixHD:图像生成对抗网络原理与实战解析

从GAN到pix2pixHD:图像生成对抗网络原理与实战解析 1. 先把对抗生成这件事掰开揉碎标题里这四个名词一个比一个长但核心其实都是同一个底层思想让网络自己在“造假”和“打假”的对抗里把数据分布学出来。GAN那一篇2014年的论文刚出来的时候大家看它更像一个理论玩具——生成一堆模糊的卧室图片、手写数字效果远没有今天这么惊艳。但就是这套“生成器造假判别器打假”的对抗框架后来长出了pix2pix、CycleGAN、pix2pixHD这一整片森林。先不要急着记住那些复杂公式我先说一个特别接地气的类比。想象一个造假团伙和一个验钞专家。造假团伙生成器的任务是做出一张看起来以假乱真的钞票验钞专家判别器的任务是从一堆钱里把假币挑出来。一开始造假技术稀烂专家轻松看出破绽。但每隔一阵子造假团伙会根据“专家怎么识破”的反馈改良工艺专家也会根据新的假币升级鉴定手段。双方越斗越强最后造出来的钞票连专家都分不清。GAN的训练过程就是这套“军备竞赛”只不过这里的“钞票”是图像、音频、3D模型而专家反馈的是“这张图有多像真的”这个概率值。为什么要强调这层理解因为后面所有模型的改进本质上都是在回答一个问题怎样让这场对抗更快、更稳、更可控。pix2pix给生成器加了一张“设计图纸”CycleGAN给对抗训练装了一个“往返一致性”的保险杠pix2pixHD则是给生成器和判别器都换了更复杂的引擎。下面我按这个脉络一个一个拆。2. 原始GAN所有变化的根2.1 生成器和判别器的分工原始GAN由两个网络组成。生成器G的输入是服从某种简单分布的随机噪声z输出是一张图像G(z)目标是把随机噪声“雕刻”成一张看起来符合真实数据分布的图。判别器D的输入是一张图像输出是一个0到1之间的标量表示“这张图有多大概率是真实的”。训练时真实图像标为1生成图像标为0D要做的是尽量把两类分开而G要做的是尽量让D把生成图误判为真实图。从数学上看训练目标是一个极小极大博弈$$\min_G \max_D V(D, G) \mathbb{E}{x \sim p{data}(x)}[\log D(x)] \mathbb{E}_{z \sim p_z(z)}[\log(1 - D(G(z)))]$$这一堆符号读起来劝退但拆开看就三句话第一D拿到真实样本时要尽量输出1即log D(x)最大第二D拿到生成样本时要尽量输出0即log(1-D(G(z)))最大第三G则希望D在生成样本上输出接近1即这一项尽量小。实际实现里G的损失往往把最大化log D(G(z))转换为最小化-log D(G(z))梯度更稳。2.2 交替训练和Nash均衡训练时不能只更新一边。如果先只训练DD会强到把G的所有输出都批得一无是处G拿到的梯度会先变得极小后来变得不稳定反过来如果只训练GD会完全失效生成器失去指导信号产生一个什么都能骗过的低质量模型。实际做法是G和D交替更新每一轮先用当前G生成一批假图和真图一起训练D更新若干次再固定D只更新G让生成的图往“骗过D”的方向移动。两边循环往复。这里的终极状态叫Nash均衡即G无法再提升造假水平D也无法再提升鉴定水平。但在实际训练里几乎所有项目都到不了那个理想均衡能同时稳定训练、生成清晰图片就已经算是胜利。因此无论是WGAN、LSGAN还是BatchNorm、学习率衰减策略本质上都是在往“稳定逼近均衡”这个方向打补丁。2.3 模式坍塌和训练不稳定的根源GAN让人痛苦的几个问题模式坍塌、训练震荡、生成图像模糊。模式坍塌的表现是生成器学会了只生成一类能骗过D的图多样性彻底丧失。比如训练人脸数据集最后出来的全是同一个角度、同一种表情。根源在于D只能在整体分布层面给反馈G只要抓住其中少数几个“高频地区”就能获得高分奖励而没有动力去覆盖整个数据分布。训练震荡则要归因于双方都在一个非平稳环境里优化。D变强一点时G的梯度方向就变了G变强一点时D那侧的损失又变了。谁都没有一个固定的目标函数很像两个骑摩托车的人互相拉扯一不留神就双双摔倒。解决思路要么是给D加约束比如WGAN的Lipschitz限制、谱归一化要么是给G加多样的损失项要么是切换训练频率。理解了这些底层病根再看后面的pix2pix和CycleGAN就会明白它们每一处设计都不是灵机一动而是对症下药。3. 条件约束与pix2pix给生成器一张设计图纸3.1 从“随便画”到“照草图做”原始GAN生成图像是不可控的你只能输入随机噪声至于出的是猫还是狗、是白天还是黑夜完全交给运气。pix2pix引入了条件生成对抗网络cGAN的思路除了随机噪声生成器还接收一张输入图像作为“条件”。输入是一张语义分割图输出就是对应的真实街景输入是一张边缘草图输出就是上完色的完整图输入是一张灰度图输出就是彩色图。控制权从“随机”移交给了“输入图像”。pix2pix最早是Phillip Isola等人在CVPR 2017发表的论文标题很直白Image-to-Image Translation with Conditional Adversarial Networks。它解决的是成对图像转换问题训练数据里必须同时有输入图像x和对应的目标输出y。比如同一个场景一张是边缘图一张是真实照片。网络学到的是给定x之后y的条件分布而不是整个图像域的分布学习难度大大降低。3.2 生成器为什么用U-Net而不是普通编解码器pix2pix的生成器选择了U-Net架构。普通编解码器Encoder-Decoder将输入压缩成一个低维特征向量再从这个向量重建输出信息经过“瓶颈”时大量丢失。如果你做的是语义分割图到街景照片的转换原始输入里的边缘、轮廓、背景结构都是关键线索一旦被压缩就很难还原。U-Net的好处在于跳跃连接skip connection。它把编码器的第i层特征直接拼接到解码器的第i层特征上让浅层的结构信息绕过瓶颈一路传到底层输出。这有点像你把一张设计图纸复印了多份每道工序手里都拿着原图而不是只看一份被摘要过的说明。实测下来同样的训练轮数U-Net生成的边缘要锐利很多建筑轮廓不会糊成一团。3.3 PatchGAN判别器不看全图只看70×70的小块pix2pix里另一个关键设计是PatchGAN判别器。它不直接输出一个“全图真/假”的标量而是把输入图像切分成N×N个小块对每个小块独立判断真伪最后取所有块的平均作为判别结果。论文里常用的是70×70的PatchGAN即每个patch的感受野是70×70像素。为什么这么做如果只对整张图输出一个真/假概率判别器很容易被全局纹理和色调蒙骗对局部细节的监督力度不够。而PatchGAN强制模型关注局部结构让生成的图像在局部纹理上与真实图难以分辨。与此同时全图的语义结构则交给L1损失兜底两者分工明确。实际操作中patch大小是个功夫活patch太小生成图像整体结构容易失控patch太大计算量则成倍增加。70×70是论文在256×256输入下经过实验调出来的甜点值。3.4 目标函数GAN损失加L1损失的组合pix2pix的总损失是GAN损失和L1损失的加权和$$L L_{cGAN}(G, D) \lambda , L_{L1}(G)$$其中L1损失是生成图像和真实目标图像之间的平均绝对误差。为什么用L1而不用L2L2损失倾向于惩罚大误差容易让模型在“所有可能的合理输出”之间取平均生成结果灰蒙蒙的缺少锐利的细节。L1虽然也会让图像偏保守但模糊程度远低于L2再配合对抗损失补充高频细节效果要清晰得多。权重λ通常取100左右。不要小看这个数字它意味着对抗损失更像一个“细节顾问”而L1才是真正的“结构监工”。如果你把λ降到1生成的图像会细节狂野但整体跑偏如果把λ设成1000图像结构稳了但纹理、亮度、立体感又会回归平淡失去生成对抗网络的优势。3.5 典型应用与实操笔记pix2pix最常见的场景包括语义分割图转街景、边缘图转实物照片、灰度图上色、建筑草图转可视化效果图、卫星图转地图。它有一个硬性要求数据必须成对。这意味着采集成本很高。比如你想把白天的街景转成夜晚就得在同一机位、同一视角分别拍一张白天和一张夜晚的照片还要保证没有车辆、行人等动态干扰这对实际项目来说几乎是噩梦。也正因为成对数据太难凑才催生了后面CycleGAN的登场。实际训练过程中我有几个体会一是输入分辨率不要一上来就拉满先把256×256跑通再放大pix2pix在256×256下已经能出非常不错的效果二是训练过程中如果D的loss降到接近0说明D太强了最好的办法是把D的学习率调低而不是把G的学习率调高三是数据增强尽量少用裁剪随机裁剪容易破坏输入和输出之间的像素对应关系导致训练集内部不一致。4. 无配对也能学的CycleGAN循环一致的魔法4.1 成对数据太难凑那就不要了CycleGAN是Jun-Yan Zhu等人在ICCV 2017年提出的目标是在没有成对样本的情况下完成图像转换。比如你想把马变成斑马现实里几乎不可能拍到同一匹马站在同一位置、同一姿态下同时作为马和斑马的两张照片。但你可以轻易找一万张马的图片和一万张斑马的图片让模型自主学习两个域之间的映射。这个设定放宽了数据要求直接引爆了风格迁移类应用。CycleGAN不仅让“马变斑马”成为人尽皆知的现象级demo还被大量用在照片转油画、照片转素描、季节转换、物体变形等场景里。它和pix2pix最大的区别一句话就能概括pix2pix需要成对的“说明书”CycleGAN只需要两个装满不同风格图片的筐。4.2 双生成器加双判别器的完整结构CycleGAN的整体结构比pix2pix复杂了一倍。它有两个生成器G负责从域X映射到域YF负责从域Y映射回域X。还配了两个判别器DY负责判断G生成的Y域图像是否足够真实DX负责判断F生成的X域图像是否足够真实。如果只有这两个生成器和两个判别器网络很容易“作弊”G输出一张看起来像Y域的图就完事完全不保留X域输入的任何结构和内容信息。因为判别器只看单张图不关心它和输入图是什么关系。这就是所谓的数据分布配不上内容结构的问题。CycleGAN解决这个问题的思路非常优雅再加一组循环一致性损失cycle-consistency loss。4.3 循环一致性损失让图走一个往返循环一致性损失的思想是图片应该经得起“往返翻译”。你输入一张X域的图x先通过G得到Y域图G(x)再通过F把G(x)翻译回X域得到F(G(x))。理想情况下F(G(x))应该和原图x几乎一样即x经过两次翻译之后没有丢失关键信息。反之也一样y经过F再经过G之后应该回到y附近。对应的损失项写作$$L_{cyc}(G, F) \mathbb{E}{x \sim p{data}(x)}[|F(G(x)) - x|1] \mathbb{E}{y \sim p_{data}(y)}[|G(F(y)) - y|_1]$$这项损失直接约束了G和F互为逆映射。你可以把它理解成翻译软件的质量测试一句中文翻成英文再把英文翻回中文如果意思没有大改变就说明翻译能力靠谱。如果翻回来面目全非那中间一定出了问题。有了循环损失之后G不能随便乱变了。它必须把x变成Y域的图同时还要保证变完之后能变回来这逼迫它只改动风格层面的东西尽量保留几何结构、物体形状、位置关系。这正是CycleGAN在风格迁移任务上效果惊艳的根本原因。4.4 身份映射损失的锦上添花CycleGAN还有一个可选的身份映射损失identity loss。做法是把一张Y域的图直接喂给G要求输出仍然是这张Y域的图同样把X域的图喂给F要求输出不变。公式是$$L_{identity}(G, F) \mathbb{E}_{y}[|G(y) - y|1] \mathbb{E}{x}[|F(x) - x|_1]$$为什么要加这一项以照片转油画为例如果输入照片里本来就有油画风的内容G应该尽量保留而不要强行转换。身份损失能约束G“不要在本来就属于目标域风格的图像上画蛇添足”对色彩保持特别有效。我在实际训练里体会很直观不加identity loss时模型容易把整个画面色调强行调成桔黄色油画滤镜加上之后颜色会忠实许多尤其是白色和浅色区域不会莫名发黄。4.5 CycleGAN训练的坑与心得CycleGAN对超参更敏感这是我跑过的项目里体会最深的一件事。循环一致性的权重λ通常取10这是一个经过大量实验验证的经验值掉到1时图像内容约束变弱风格迁移会放飞自我升到100时风格变化又太保守常常只能看到颜色微调。学习率方面论文建议前100个epoch保持0.0002后100个epoch线性衰减到0。很多复现效果差的原因根本不是模型结构写错而是这个衰减策略没实现。另外要特别提醒CycleGAN生成器多是ResNet结构的9个残差块这让它天然擅长在256×256输入上工作。如果你直接上512×512显存占用会迅速爆炸普通消费级显卡根本扛不住。我的建议是先跑通256确认效果符合预期之后再用实例归一化、分块训练这类技巧一步步扩大分辨率不要一开始就高标准高难度。5. pix2pixHD把清晰度推向1080p的工程化教科书5.1 问题在哪高分辨率下生成网络直接失灵把pix2pix放大到高分辨率并不是“调大输入尺寸”这么简单。直接对输入输出分辨率做简单的上采样生成器的有效性会受到极大限制。具体来说随着分辨率升高生成器需要建模的像素数量呈平方级增长而U-Net在深层特征上的感受野并没有同步扩展就会出现结构错位。判别器的问题更严重在整图范围内判断真伪的PatchGAN虽然用平均patch计算但如果patch密度不够对高分辨率局部细节的监督效果会大幅下降。pix2pixHD的第一作者Ting-Chun Wang等人正是冲着解决这些问题去的。他们保留了pix2pix的基本框架——条件生成对抗网络但在生成器、判别器和损失函数三个方向分别做了重要改良。pix2pixHD最终能够在2048×1024甚至更大分辨率上生成高清晰度的语义分割转街景效果视觉质量在当时几乎是碾压级的。5.2 生成器升级Coarse-to-fine的Global Local结构pix2pixHD生成器采用coarse-to-fine由粗到细策略由两个子网络组成Global生成器和Local增强网络。Global生成器在低分辨率下生成图像的总体结构和大致内容一个U-Net或者ResNet结构Local增强网络则接收Global的输出在高分辨率局部区域上做细节修复。实际结构上这两个子网络并不是完全独立的。Local网络以Global输出的特征图和原始条件输入为输入通过残差连接把精细细节叠加到Global的粗糙输出上。这样设计的好处很明显大部分算力消耗在低分辨率的Global网络上高分辨率部分只负责局部细节总计算量远比全分辨率U-Net要低。训练时通常采用多阶段策略先单独训练Global网络再联合训练Local网络否则一开始两个子网络同时优化梯度交互会让训练崩得很快。5.3 多尺度判别器三个“鉴赏家”从不同距离审视pix2pixHD另一个核心创新是Multi-scale Discriminator。它用三个结构相同的判别器分别处理原始分辨率图像、1/2分辨率图像、1/4分辨率图像。这样一来最底层的判别器用较粗的尺度监督全局结构中间层判别细粒度特征最高分辨率判别器专注边缘纹理和细节。梯度回传时三个判别器的信号被加权求和共同指导生成器。在实际复现中不同尺度的判别器效果差异很大低分辨率判别器学得快但也更容易“带偏”生成器的整体色感高分辨率判别器负责的细节更难训练往往需要更多的训练步数才能稳定。因此训练时要留意三个判别器的loss分布如果某个尺度长期不收敛通常需要调低它的权重或者考虑换一个patch尺寸。5.4 损失函数Feature Matching Loss和感知对齐除了标准的GAN损失pix2pixHD还引入了feature matching loss。它不直接比较逐像素颜色而是拿判别器中间层提取的特征来做监督。具体做法是把真实图像和生成图像分别输入判别器取某些中间层的激活值计算它们的L1距离让生成图像在判别器内部的“感知特征”层面与真实图像对齐。这个损失的意义在于判别器内部的特征比像素级别的值更能描述图像的语义信息比如纹理风格、边缘密度、明暗分布。论文实验显示加了feature matching loss之后生成图像在高频细节如树叶、栅栏、建筑装饰上的丰富度肉眼可辨地提升训练也稳定得多。在很多开源实现里这项损失通常以multi-scale的方式同时作用于多个判别器进一步强化约束。5.5 实例边界信息的工程价值pix2pixHD论文里还有一个很容易被忽略的细节通过实例级别边界信息instance boundary map加持可以让生成结果在物体边缘处更加锐利。所谓实例边界是指语义分割图上不同物体实例之间的边界线比如两辆紧挨着的车、相邻的人行道和马路牙子。把这种边界信息作为额外的条件通道喂给生成器它会清楚地知道物体的轮廓约束而不是凭猜测去画边缘。在工程落地时是否使用实例边界对你的数据标注要求影响很大。只有语义分割标签是不够的还需要实例分割标签标注成本会成倍增加。我的建议是如果你的场景里物体密集、边缘交叠多比如街景、城市建筑群这一步值得投入如果场景相对简单、物体边界清晰比如单件产品图集可以不开这个选项效果差距不大。6. 实践中的常见问题与模型选型6.1 四类模型到底怎么选刚开始接触这四个模型的人最容易纠结“到底用哪个”。我的选型思路很简单先问数据再看任务。模型数据要求典型用途输出分辨率训练难度原始GAN无需配对完全无监督生成新图像、数据增广、风格探索通常64~128中等但容易训练不稳定pix2pix成对数据语义分割转图像、灰度上色、草图转照片256~512较低CycleGAN两个域的独立数据集风格迁移、季节变换、马变斑马256~512偏高pix2pixHD成对数据需要较大显存高分辨率图像生成、街景合成、虚拟场景构建2048分辨率甚至更高高如果数据集里有成对样本优先选pix2pix或pix2pixHD质量和训练稳定度都远胜CycleGAN。如果没有成对样本只能上CycleGAN。如果任务只是生成新的图像而不是做图像转换那原始GAN或其改进版本如StyleGAN系列才是更合适的方向。6.2 训练不稳定的排查清单我一直觉得跑GAN类模型最折磨人的不是代码跑不起来而是loss曲线看着一切正常生成图像却越来越糊。遇到这种情况按下面的顺序排查先看判别器loss。如果D的loss在0.0附近长时间横盘说明D已经碾压了G需要降低D的学习率或者把D改成小网络。反之如果D的loss一直在0.69附近纹丝不动说明D根本没有学到真伪差异这时候问题往往出在数据预处理或网络初始化上。再看学习率。GAN从高学习率启动几乎必定震荡0.0002是我觉得最稳妥的起步值。在训练后期让学习率线性衰减到0对稳定收敛帮助极大。检查BatchNorm。生成器用BN在处理不同批次统计量的时候容易引入伪影换用InstanceNorm在许多图像生成任务上效果更好。最后看损失项权重。比如CycleGAN里cycle loss的λ是10pix2pix里L1权重是100这些都是论文里精调过的甜点值。不要轻易改要改也要成倍地调。6.3 显存不够怎么办显存不够是绝大多数人在复现pix2pixHD时遇到的第一堵墙。我的经验是三个步骤依次尝试第一降低batch size到1配合梯度累积模拟更大的batch第二用混合精度训练在不损失太多精度的前提下省差不多一半显存第三输入分辨率从目标的一半开始训练等模型收敛后再微调到全分辨率。pix2pixHD的Global网络本身就是在低分辨率上工作的所以这个两阶段训练方案和它的设计初衷非常契合。不过要注意Local网络对精度的需求很高混合精度训练时如果发现生成图像出现彩虹状噪声多半是fp16的梯度溢出导致的给这两层保留fp32就好。6.4 数据预处理的一些经验图像生成类任务对数据质量的敏感度超出很多人预期。我踩过最大的坑是训练集里的图片尺寸不统一。pix2pix要求输入输出分辨率完全一致如果你拿来的图片有横有竖直接resize会让画面比例失调生成结果会出现诡异的拉伸形变。解决方法是先做中心裁剪把所有图片统一成正方形或同一个宽高比然后再resize到目标分辨率。另一个很容易犯的错是把数据增强里的水平翻转开得太猛。pix2pix里的input和target必须做完全相同的几何变换如果你对input做了翻转而target没跟着翻网络学到的是错位的映射关系训练loss会一直降不下去。CycleGAN虽然没有这种配对问题但两个域的数据增强策略最好保持一致否则模型会学到数据分布上的感观偏差而非真正的风格转换。7. 最后再分享一个实战小技巧这几个模型从论文到复现最让我觉得值得反复琢磨的还是“损失函数的配比”这一环。我最早跑pix2pix的时候按论文抄了L1权重100效果确实不错。后来换到另一个数据集上发现结构稳定但指纹细节全丢把L1权重降到30再把GAN损失权重提到1.5之后效果反而好了很多。这说明论文给的是起点不是终点真正的调参功夫是在“对抗损失管细节、重建损失管结构”这个张力之间找到平衡。还有一个小建议训练GAN时养成定时保存生成样本的习惯每1000步保存一组训练完把图片按时间顺序连成视频回放你能非常清晰地看到模型从模糊到清晰、从颜色漂移到稳定的完整过程。这个习惯帮我省了不知道多少debug时间比看loss曲线管用得多。
返回列表