首页 / 资讯中心 / 文章详情

深度学习图像修复实战:基于DCGAN的毕设实现与踩坑全记录

深度学习图像修复实战:基于DCGAN的毕设实现与踩坑全记录 ★ FEATURED ARTICLE
大三下学期定毕设题目那会儿我在教研室坐了一下午把“图像修复”四个字翻来覆去地看。传统方法从扩散插值到纹理合成论文看了一堆实验也跑了不少总觉得差点意思——要么只能用在小块划痕上要么修复完边缘糊成一片。后来看到DCGAN在无监督特征学习上的那篇经典工作脑子里蹦出来一个想法既然生成器能学到图像的分布那把它挖掉一块再让生成器填回去是不是就是图像修复就这样我把毕设题目定成了“基于深度学习的图像修复算法研究——DCGAN方向”。这篇博文就把整个从选题到答辩的过程写出来。我不会只贴代码会把为什么选这个方案、每一步怎么设计、训练中踩过哪些坑、最后怎么跟导师解释实验结果全部摊开讲。适合正在做类似毕设、或者想入门GAN做图像生成/修复方向的同学参考。你不需要把DCGAN当作一个“过时模型”来看它的结构简单、原理直观、可视化效果好恰恰是做毕设最稳的切入点——比一上来就跑SOTA模型靠谱得多。1. 选题复盘为什么一个本科生敢用DCGAN做图像修复1.1 图像修复问题到底在解决什么图像修复Image Inpainting的核心任务描述起来很朴素给定一张图图上有一块区域缺失或不完整把缺失部分补上让人看不出修补痕迹。听起来像Photoshop里的“内容识别填充”但本科毕设要做的远比这个具体——你要定义清楚“缺失”是什么形式、用什么算法生成补全内容、怎么量化补得好不好。早期方法主要分两类。一类是偏微分方程扩散的方法代表性的是Telea的快速行进法FMM它从已知像素边界向内扩散颜色信息适合小面积划痕一旦挖掉区域超过一定尺寸就会因为缺少高层语义信息而只剩模糊的一团。另一类是纹理合成方法从周围区域找相似纹理块拼进去对小纹理区域尚可碰到复杂的图像结构就崩了。传统方法的核心局限在于它们只利用局部像素关系不理解“这里应该是一扇门”“那里应该是一只眼睛”这种全局语义。深度学习方法的思路完全不同。它不再手工设计扩散规则而是让网络从大量数据中直接学习图像的内在分布。到毕设这个层面你真正需要的不是从零发明一个新架构而是把已有框架吃透跑通并给出合理的分析和对比。这也是我最终选择GAN路线而不是纯CNN回归路线的原因——修复任务和生成任务天然契合GAN的训练过程本身也是毕设中期展示的好素材。1.2 从传统方法到生成式方法的演化逻辑想理解DCGAN为什么能用来修复得先理解GAN在学什么。生成对抗网络的核心思想是训练两个网络互相博弈生成器负责把随机噪声变成“看起来像真实图像”的输出判别器负责区分输入是真实样本还是生成样本。两者对抗到最后生成器学会的其实不是背诵训练集而是学到了训练数据的概率分布。那这和图像修复有什么关系关系大了。你想如果生成器真的学到了“猫的照片长什么样”这个分布那给它输入一只缺了耳朵的猫它理论上知道耳朵区域应该生成什么样的毛发纹理因为它见过大量“完整的猫”。DCGAN的价值在于它用卷积操作替换了原始GAN中的全连接结构让生成器能够更好地建模图像的空间结构信息稳定性也比最早的全连接GAN好了一大截。放到毕设的时间尺度上看DCGAN还有一个难以拒绝的优势它足够简单。整个生成器不过五六层反卷积判别器对应五六层卷积在单卡上训练几小时就能出效果。你完全可以在中期检查时给导师展示训练过程的生成效果对比这在传统方法里是不可能的。说白了这是一个“性价比极高”的毕设选题——理论深度够讲实验周期可控可视化和可解释性都强。2. DCGAN图像修复的完整原理拆解2.1 生成器与判别器的攻防结构先明确一下DCGAN的总体架构这部分在论文里写得比较清楚但还是值得用自己的话盘一遍。生成器输入一个100维的随机噪声向量通过一系列转置卷积逐步上采样最终输出64x64x3的图像。判别器则是标准CNN结构输入图像输出一个0到1之间的标量表示输入图像“有多真”。关键设计点有三个每一个都有明确设计意图。第一全卷积化。生成器和判别器里全部使用卷积层和转置卷积层不引入全连接层。这么做的原因很实际全连接层的参数太多容易过拟合而且会丢失图像的空间位置信息。第二批归一化Batch Normalization加在除生成器输出层和判别器输入层之外的所有层上。批归一化能把各层输出拉回均值为0、方差为1的分布附近明显缓解深层网络梯度消失的问题——在GAN这种训练极不稳定的场景下这一招几乎是必需品。第三激活函数的选用。生成器隐藏层用ReLU输出层用Tanh判别器隐藏层用LeakyReLU负斜率0.2输出层用Sigmoid。这里有个容易被忽略的细节输出层用Tanh意味着你要把训练图像像素值归一化到-1到1之间而不是常见的0到1。我一开始没注意直接拿0到1的图像去训练生成结果一直偏暗后来检查代码才发现的。这类细小但是致命的预设条件论文里一句话带过实操中却要踩一次坑才记得住。2.2 上下文损失与感知损失的组合逻辑有了生成器和判别器怎么把它们组合成修复模型这是整个毕设最核心的设计决策。最直接的思路是把缺失区域的图像直接送入生成器让它输出完整图像。但这里有个问题——标准DCGAN生成器只接受随机噪声你得先确定“哪一维噪声对应哪张图像”这个约束本身就不成立。所以更可行的做法是“Encoder-Decoder”思路的变体让生成器的输入不再是纯噪声而是带缺失区域的图像。不过这已经偏离DCGAN的纯形式了。另一个更经典的切入方式参考了Context Encoder的思路不改变DCGAN生成器的输入输出结构而是直接在损失函数上做文章。把完整图像经过掩码操作得到带孔图像再通过某种方式与生成结果叠加然后设计一个联合损失L λ_context * L_context λ_perc * L_perc其中L_context通常是L1或L2损失计算生成结果和真实图像在缺失区域的逐像素误差L_perc是感知损失即把生成图像和真实图像分别送入判别器或预训练分类网络取某一层特征做L2距离。逐像素损失保证填充区域和真实内容的像素值接近感知损失保证填充区域的“风格”和语义与整体图像协调。如果只用逐像素损失生成结果往往是模糊的色块平均——因为L1/L2损失天然倾向于在多个可能正确的颜色之间取平均产生平滑但不真实的纹理。加入感知损失之后网络被要求“骗过判别器”输出就必须具备更真实的统计特性比如边缘锐利、纹理连续。2.3 掩码策略修复任务的关键变量所谓掩码Mask就是标记图像中哪些区域需要修复的二值模板。掩码的设计直接决定了任务难度。毕设阶段我采用了三种掩码策略正好构成一组对比实验。第一种是中心方形掩码——把图像正中央的一块正方形区域整块挖空最简单也最常用方便和论文中已有结果对比。第二种是随机位置掩码——在图像任意位置放置一个固定大小的方形空洞难度略高因为模型不能依赖“空洞一定在中心”的先验信息。第三种是随机不规则掩码——用随机曲线生成不规则的孔洞更接近真实场景中物体被遮挡或照片被划伤的情形。掩码的尺寸也需要考虑。固定成整张图的1/4到1/3比较合适。太小了没有修复意义传统方法也能做太大了生成器输入信息严重不足DCGAN这种浅层生成器扛不住。我实测下来64x64的图像上挖一个32x32左右的中心孔正好在“有点挑战但能学会”的区间。这个区间也方便拿DCGAN和传统方法做公平对比——传统方法在中等尺寸空洞上表现尚可GAN方法优势不明显但到更大空洞时差距就拉开了。3. 从零开始构建修复实验的核心代码骨架3.1 数据准备与掩码生成训练一个够用的DCGAN修复模型我用的是公开的自然图像数据集统一缩放到64x64分辨率并做了像素归一化。数据集不大几千张图对我来说够用了——毕设重点在验证方法可行性不在刷量。数据增强只用了随机水平翻转没有做裁剪和旋转因为GAN训练本身就不稳定过多的数据增强反而让分布学习更难收敛。掩码生成完全在数据加载阶段动态完成每轮训练重新生成掩码变相增加了数据多样性。中心方形掩码的生成很简单确定空洞边长算中心坐标然后生成一个全0矩阵把对应区域置为1。不规则掩码稍微麻烦一点先用随机点做平滑曲线再把曲线范围内的像素置为1。这里要注意掩码的值域必须是{0, 1}千万不能随手写成255否则图像叠加的时候会出问题。处理图像和掩码的时候建议直接用Tensor或者NumPy数组处理配合矩阵索引十几行代码就够。这类数据处理尽量保持在GPU之外完成因为它不是瓶颈——把GPU时间留给训练更划算。3.2 生成器与判别器网络设计要点我实现的生成器结构大体抄的DCGAN原版但稍作修改以适配修复任务。原版生成器输入是100维噪声我的做法是在输入端把带孔图像通过卷积下采样后与噪声拼接再一起送入反卷积部分。这么做的好处是既保留了原始DCGAN的生成能力又引入了缺失区域的上下文信息。如果你不想改动输入结构也可以用“两阶段生成”的思路先用一个普通CNN粗修一版再用DCGAN细化。但那样相当于多训练一个模型工作量翻倍作为毕设不太划算。我更推荐单生成器配合联合损失的方案——结构简单容易跟理论对应。判别器相对标准不多讲。需要注意输出层的维度常规DCGAN输出一个标量即可但如果想让梯度更稳定可以试试输出一个NxN的矩阵对每个Patch单独判断真伪这就是PatchGAN的思路。不过我实测在64x64分辨率下标量输出已经够用PatchGAN带来的提升有限反而增加实现复杂度。毕设求稳的话先跑标准结构。3.3 训练循环的细节处理训练GAN本质上是一个交替优化的过程。每一轮迭代里先固定生成器、训练判别器再固定判别器、训练生成器。交替训练的目的是让两个网络不断升级博弈水平但如果任何一方训练过快另一方就跟不上整体就会崩溃——这是GAN训练不稳定的根源。具体操作上判别器的输入有三类真实原图、生成器的修复结果、以及“用真实图像直接挖洞”的样本。训练判别器时真实图对应标签1修复结果对应标签0。训练生成器时它只关心能否让判别器把修复结果判为1同时加上上下文损失。学习率我用的Adam优化器的默认值但把学习率设为0.0002这是DCGAN原论文中特别强调过的一个细节不要用太大的学习率否则判别器会迅速收敛到过于强大导致生成器梯度消失。批大小取了64在64x64分辨率下单卡显存完全吃得消。另外为了让训练更平稳我还对生成器损失做了个小调整不是直接最小化判别器的判断误差而是最大化预测为真实图像的概率的对数。这是一个经典的小技巧能改善早期梯度饱和问题。代码上往往就一两行的差异但对训练曲线的影响很明显。4. 训练与调参那些论文里没写的实测教训4.1 训练一开始loss不下降问题出在哪我第一版代码跑起来之后生成器的损失基本不动输出一片混沌的噪声。排查了一圈问题竟然出在像素归一化上——图像被归一化到了[0, 1]而生成器输出层是Tanh取值范围是[-1, 1]。判别器面对两个尺度不一样的输入直接学“自闭了”不管生成器输出什么它都能轻易区分出来。把输入图像改到[-1, 1]之后损失一下子就活动了起来。这个错误非常典型几乎每个第一次做GAN的人都会碰到。在GAN体系里“输入数据的分布形态”比在分类任务中敏感得多因为判别器本质上是在做分布对比你给它两个不同分布的数据它就变成一个简单的“尺度识别器”而不是语义判别器。所以动手训练之前第一件事永远是确认生成器输出层和输入图像的取值范围一一对应。4.2 生成结果偏模糊如何调整损失权重训练能跑通之后下一个常见问题就是生成结果偏模糊边缘不锐利。检查生成的修复图整体颜色是对的但细节像蒙了一层雾。这时候通常要考虑两点。第一点上下文损失权重过大。L1/L2损失天然偏好“平均”如果上下文损失在总损失里占绝对主导感知损失根本使不上力。我在实验里做了权重扫描λ_context从1调到10λ_perc从0.01调到1最后发现λ_context1、λ_perc0.1这个组合在模糊度和真实性之间平衡得最好。但你直接抄我的值不一定最优跟数据集复杂度、空洞大小都有关系重点是你得理解这个调参方向。第二点生成器容量不够。DCGAN的生成器是几层反卷积堆起来的如果图像本身纹理丰富浅层网络学不出高频细节。你可以尝试加深通道数比如从64通道起步翻倍到128或者增加一层卷积。但因为毕设强调可复现性不要一上来就大改结构先用损失调权效果不够再动容量。4.3 判别器太强生成器直接摆烂训练后期还有个高概率事件是判别器“掉线”——它学会了一种简单粗暴的方式判断真假比如直接看亮度平均值生成器怎么努力都骗不过它梯度反而失去指导意义。此时生成器的损失会持续上涨但输出质量越来越差。我在实验中遇到过一次明显严重的过拟合信号判别器在训练集上准确率接近99%但生成器输出的图像开始出现重复纹理的伪影像是把训练集中的某个局部区域硬贴上去。解决办法有三个方向一是给判别器加Dropout削弱它的判别能力二是用标签平滑——把真实图像的标签从1改成0.9让判别器不要过于自信三是训练判别器时降低每轮更新次数比如每训练2轮生成器才训练1轮判别器。其中标签平滑是投入产出比最高的一个操作代码改动极小却能显著降低训练后期的不稳定性。我三个方法都试了最终保留的是标签平滑判别器降频更新组合效果最稳。5. 评估指标与毕设答辩的展示思路5.1 PSNR与SSIM的局限毕设答辩的时候评委老师最常问问题之一就是“你怎么量化你的修复效果”。这时候不能只说“看起来还行”得有数据。我用了两个最常见的指标PSNR峰值信噪比和SSIM结构相似性。PSNR衡量的是像素级的误差数值越高代表重建越接近原图但它在感知相关性上很弱——一张整体加亮、稍微模糊的图可以拿到很高的PSNR但人眼看着就是不对劲。SSIM引入了亮度、对比度和结构三个维度的比较比PSNR稍微贴近人眼但对纹理细节的敏感度依然有限。所以在展示时我就强调一个观点PSNR和SSIM是修复结果的“及格线”指标不是“优秀线”指标。我用DCGAN修复出来的图PSNR往往不如传统方法高因为GAN会“发挥创造力”生成一些像素值不同但语义合理的纹理结构——这在指标上吃亏但在人眼观感上反而更好。需要有意识地解释这个差异不能回避。为了证明这一点我做了一组对比表格把原图、掩码图、传统方法结果、DCGAN修复结果放在同一页幻灯片上并标注各自的PSNR/SSIM。当评委看到DCGAN的指标略低但肉眼效果明显更好时这个矛盾本身就变成了一个很好的讨论点。5.2 可视化对比与消融实验的呈现技巧毕设答辩的展示不只是念报告更重要的是展示你做了哪些思考。我准备了三条线的对比结果不同掩码尺寸下的修复效果对比、不同损失权重下的效果对比、以及与传统方法的对比。每条线都用并排四列图像展示从左到右依次是原图、带掩码图、基线方法结果、我的方法结果。这里有个很实用的排布技巧把效果最好、视觉冲击力最强的三张图放在展示开头和结尾——第一印象和最后印象最是深刻。中间穿插指标曲线和失败案例。对失败案例也要放。只展示成功案例会让答辩显得不够严谨而“大块掩码下颜色出现偏色”“高纹理区域细节恢复不完整”这两个失败案例恰恰可以引出你的后续工作方向基本都是加分项。消融实验方面我做了两组一是去掉感知损失只保留上下文损失结果纹理模糊二是去掉上下文损失只保留感知损失结果颜色和结构出现失真险情。这两组对照足以说明“两者缺一不可”。这个实验的成本很低但说服力很强——因为它直接支撑了你的核心设计决策。5.3 答辩现场会用到的几个关键解释口径整理几个我答辩时被问到的、也是最核心的问题提前准备好回答口径就行稳妥程度直接上升一个台阶。第一个问题“你的方法和Context Encoder有什么区别”我的回答是核心框架同源都是编码-解码生成器加联合损失但我在生成器输入端保留了原图上下文信息而不只是用纯噪声生成这减轻了生成器重建已知区域的压力让它可以集中精力处理缺失区域。导师听完一般会点头。第二个问题“DCGAN已经是好几年前的模型为什么毕设还选它”回答要点有两个其一毕设的重点不是训练最大最新的模型而是完整地理解生成式图像修复的原理链路其二DCGAN结构简单更容易做可控的实验和分析——在此基础上替换骨干结构就是自然的后续工作。这个回答既诚实又显示了思考深度。第三个问题“你的方法在真实场景里能直接用吗”这里就参照实际情况说明坦诚说明局限当前数据规模和分辨率是主要限制但实验验证了方法的有效性后续换用更大模型、在更高分辨率数据上训练以及自定义掩码生成策略都是明确可行的方向。这种回答比吹牛更让评委信服。6. 一些关于毕设项目管理的额外经验说了很多技术细节最后聊点项目管理的琐碎心得。毕设周期看起来长实际能用的时间非常有限前中期往往又被专业课占据。我的经验是首先把进度按“四周死线”切块。第一周搞定数据管线和掩码生成第二周跑通基础DCGAN训练第三周加入修复模块和联合损失第四周开始全套对比实验并整理数据。只要每周有实际产出中期检查的时候就非常有底气。另外一个容易踩的坑是实验记录。训练GAN的时候每改一个参数就是一次新实验如果不记录清楚超参数、数据和训练轮数过一个星期回来看结果列表完全不知道哪张图是哪一版跑出来的。我的做法是每次实验开始前生成一个带时间戳的文件夹里面存一份配置文件训练结束自动保存模型权重和损失曲线这样一个文件夹对应一次完整实验复盘的时候非常清楚。这个习惯从毕设第一天就该养成后面写论文的时候能省一半时间。最后图像修复这个方向是真的能“越做越深”的不只是交差。我在完成毕设后又顺着这条线看了注意力机制、扩散模型的相关论文整个生成式图像修复的脉络一下子就串起来了。如果你的毕设也选了类似题目不妨多留一点时间给触类旁通收获往往比完成项目本身更大。
阅读完成 · 觉得有帮助?
咨询建站