ARTICLE DETAIL

资讯详情

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

GPEN人脸修复:基于GAN先验与渐进式解码的盲脸修复技术

GPEN人脸修复:基于GAN先验与渐进式解码的盲脸修复技术 1. 为什么人脸修复不能直接套通用超分模型1.1 一张真实模糊人脸上的“退化”远比你想象的复杂先说个真实场景。上个项目我接手了一批上世纪九十年代的扫描老照片人物脸部几乎糊成一团五官边缘全是锯齿肤色上还有大块扫描噪点和JPEG块效应。刚开始我想得很简单不就是超分辨率嘛把ESRGAN、Real-ESRGAN这些成熟模型拉出来跑一遍就行。结果效果非常难看——背景纹理和衣服边缘倒是还行但只要一到人脸区域修复结果就出现严重的“塑料感”皮肤像涂了一层蜡眼睛和嘴巴的位置偶尔还会跑偏更别提身份特征的一致性了。为什么通用超分模型会在人脸区域拉胯核心原因有两个。第一真实人脸退化的构成很复杂它不只是单一的高斯模糊或双三次下采样而是模糊核、运动模糊、传感器噪声、压缩伪影、色彩偏移等多种损伤的叠加。这种“盲退化”问题简单假设单一退化模型的通用超分框架根本拟合不了。第二人脸这个目标本身要求太高。你修复一只猫的照片五官略有点失真观感上基本可以接受但人脸是结构极其密集的对象眼睛、鼻子、嘴、发际线的比例如果偏差几个像素人眼立刻就会觉察到“不像本人”。这已经不是单纯提高分辨率能解决的问题。GPEN这篇论文最打动我的地方就在这里——它捕捉到了问题的本质人脸修复光靠“超分”不够你得在信息不足的前提下把人脸结构“脑补”出来。这就需要一个强大的先验。1.2 “先验”是什么为什么人脸修复一定要有它拿一个最简单的例子来说。给你一张16×16像素的模糊人脸图里面只有一坨肉色的色块。要把它恢复成清晰的512×512人脸信息量缺口至少是1000倍。谁来填补这个缺口只能靠先验。所谓先验就是模型脑子里预先储存的“人家长什么样”的知识——比如眼睛通常是一对对称的深色椭圆鼻梁有一条高光嘴唇有两条弧线发际线大致在额头某个位置。人脸修复领域常见的先验有几种面部关键点坐标、人脸解析图segmentation map、参考人脸库还有业界用得越来越多的GAN生成先验。关键点和解析图属于“几何先验”它们能告诉你五官大概在哪个位置、哪块区域是皮肤哪块是头发但填不出皮肤的毛孔细节和头发的发丝走向。参考人脸库属于“检索先验”效果不错但依赖库的覆盖度遇到大角度侧面、夸张表情就很容易找错人。而GAN生成先验就是提前训练一个高质量人脸生成模型比如StyleGAN让它把人脸生成分布全部记住修复时再从中检索最接近的真实人脸结构。GPEN选择的是最后一条路预训练的StyleGAN把它当作一个“先验知识库”直接嵌入到人脸修复网络中。这个思路的直觉是——既然我手里有一个能生成逼真人脸的模型说明它已经掌握了人脸的真实分布。那遇到一张模糊人脸时我只要在它的隐空间里找到对应的那一组潜码latent code再用这组潜码去生成高清图不就等于“按记忆修复”了吗。1.3 直接索引隐空间为什么不够还要有“嵌入网络”顺着这个思路最早的一批做法是直接把低质量图片映射到StyleGAN的W空间找到潜码后固定生成器不动反推高清图。这类方法后面被统称为GAN Inversion。我自己试过这类方法优点是生成的人脸极其逼真纹理细节可以说“无中生有”到了以假乱真的程度但缺点同样明显反演过程通常会丢掉输入图片中的真实身份信息修完以后确实是一张好看的脸但仔细一看“这个人”已经不是你照片里的那个人了。这在老照片修复场景里属于完全不可接受的失败——用户最在意的就是“还是我爷爷”。另一个问题是效率。直接在隐空间里做逐像素优化一张图可能要跑几十次甚至上百次迭代根本没法落地到实际产品。所以GPEN的设计目标就很明确了既要利用GAN生成先验的强项又要保住输入图的真实身份信息还要做到前向推理一步到位。它不打算抛弃GAN先验也不打算完全依赖GAN先验而是把两条路拧成一条——下面我拆开讲它的网络结构你会发现这个“拧”的动作才是整篇论文最值钱的地方。2. GPEN网络结构拆解全局编码器与渐进式解码2.1 为什么偏偏选StyleGAN作为先验库GPEN选取的先验库是StyleGAN2。可能有人会问GAN生成器这么多为什么是StyleGAN而不是ProGAN或者StyleGAN3这个选择完全不是心血来潮核心原因有三个。第一StyleGAN的隐空间编辑特性极其优秀。StyleGAN在训练时会把潜码通过一个映射网络变换到W空间再通过AdaIN的方式在不同分辨率层级注入风格信息。这意味着W空间的分层控制能力很强——粗层控制姿态、脸型、五官位置细层控制皮肤纹理、光照、颜色。对修复任务来说这种分层特性太合适了低分辨率输入贡献的信息可以用来约束粗层高分辨率细节则交给细层脑补。第二StyleGAN2对生成图像的质量和分布覆盖度非常高。GPEN直接使用在FFHQ数据集上预训练好的StyleGAN2权重连预训练成本都省了。FFHQ覆盖了7万张高清人脸图姿态、年龄、肤色、光照条件都非常丰富这个分布足够支撑真实世界人脸修复的需求。第三有一个很容易被忽略的工程原因——StyleGAN2的生成器里天然支持不同分辨率的输出。它本来就是渐进式生成结构从4×4一路生成到1024×1024每个分辨率层都有对应的feature map。GPEN的渐进式解码器设计完全可以复用这套结构零成本拿到多尺度特征。2.2 全局分支编码器如何提取真实身份信息GPEN的网络结构可以拆成两个大分支。第一个分支叫全局编码分支Global Branch它做的事情比较“传统”把低质量输入图喂给一个编码器经过一系列卷积、下采样、残差块提取出一个紧凑的特征向量或者说是潜码的预测结果。但这里有个细节需要注意——GPEN的编码器并不预测一个StyleGAN的输入潜码 z而是直接预测W空间的风格向量。为什么会这样因为W空间的维度比单一潜码大得多它允许每一层用不同的风格向量表达能力更强能更精细地还原输入的细节信息。如果只预测一个16维的z再通过映射网络生成w信息瓶颈太明显修复出来的图会丧失跟输入图的对应关系。W的维度大约18×512虽然大了不少但对编码器来说依然是个“压缩”的过程。编码器的主干结构类似ResNet内部还引入了特征金字塔结构来融合不同尺度的特征。这个设计针对的场景很实际一张模糊人脸的不同区域退化程度可能完全不同比如眼睛部位略微清楚但下巴部位已经完全糊掉。多尺度特征融合就是为了让网络能够从“局部还算清晰”的区域提取更多有效信息去补足“完全糊掉”的区域。不过只是提取特征还不够。如果编码器直接输出一套W向量相当于让一个模型同时干“理解图像内容”和“理解GAN隐空间语义”两件事训练难度会非常大改动。GPEN偏偷懒一点它把提取出的多尺度特征跟StyleGAN生成器的中间特征融合让生成器自己参与进来把身份信息带进去。这个“带进去”的动作就要靠第二个分支来完成。2.3 渐进式解码从粗糙空间到高清图的分层重建第二个分支是渐进式解码器Progressive Decoder。别被名字吓到它的思路其实不复杂从StyleGAN2预训练模型里拉一条生成链路出来从4×4逐步上采样到512×512每一级都用全局分支提供的特征做一次“修正”。具体一点说GPEN不会让StyleGAN直接根据预测的W向量生成一张完整的高清人脸而是把生成过程“切开”。在每一层生成分辨率的时候它都会把编码器对应尺度的特征图拼接到生成器的中间特征上再通过一层1×1卷积混合。初始阶段网络主要靠StyleGAN先验生成人脸的整体结构和五官布局随着层数加深、分辨率提高全局分支的特征逐渐占据主导地位把输入图里的真实身份细节一点点“雕刻”回去。这个设计好在哪你可以把它想象成素描画人像的过程。一个经验丰富的画师不会一开始就抠眼睛眉毛的细节而是先起大形定头骨比例、脸部轮廓再一层层添加五官、明暗、纹理。StyleGAN提供的就是画师脑中预先练好的“起形能力”而全局分支提供的则是被画者本人的真实面貌信息。起形靠经验深入靠观察两者缺一不可。2.4 全局分支与渐进分支的融合adaptive feature modulation两个分支不是简单的特征拼接就完事了。GPEN用的是adaptive feature modulation机制把全局分支的特征经过sigmoid激活后作为权重去调制渐进解码器每一层的特征通道。也就是说不是把两套特征机械相加而是让全局特征学会“哪些通道要放大、哪些通道要抑制”。这比直接拼接或者相加要灵活得多也更容易训练。这一点在论文的消融实验中有明确体现。去掉adaptive modulation换用简单的加法融合后修复结果的人脸结构一致性下降明显皮肤纹理也容易出现不自然的条纹。毕竟StyleGAN生成的纹理特征是偏“平均脸”的如果不去根据输入图动态调整强度很容易把用户的特征冲淡。从整体上来看GPEN的网络结构其实回答了这样一个问题如何在不重新训练一个超大GAN的前提下把一个专用修复任务接到已有的通用先验库上。答案是不要端到端生成也不要完全依赖反演而是用一条“引导生成”的链路让先验和实际信息在每一个尺度上都进行对话。3. 损失函数设计三路损失如何稳住训练3.1 对抗损失让人脸“真”起来的第一推动力GPEN的训练损失不是一个单独的指标而是一套组合拳。第一拳是标准的GAN对抗损失作用于全局分支的输出。它的任务很简单判别器要努力分辨哪张图是生成器修复出来的、哪张图是真实高清图同时生成器要努力骗过判别器。这种博弈会逼迫生成器输出的图像不断向真实人脸的分布靠拢。如果你做过GAN相关实验一定知道对抗损失的问题——训练不稳定容易模式崩塌。GPEN的应对策略是把对抗损失主要放在全局分支的高分辨率输出上让StyleGAN预训练模型内部的结构天然起到稳定作用而不是从零训练一个生成器。等于说生成器的大部分权重已经“半成品”状态网络只需要学习如何引入输入信息这比完全初始化训练要稳定太多。我个人经验里对抗损失的权重设定也有讲究。GPEN论文里的默认配置是对抗损失、特征匹配、重建损失按不同权重叠加ratio控制在1:1:10附近。重建损失的大权重确保了生成图像不偏离输入太远对抗损失则把剩下的自由空间全部用于提升真实感。反过来如果对抗损失权重太大图像会变得“过于好看”但丢失身份这可就是灾难了。3.2 重建损失与感知损失像素级与语义级的双向对齐第二拳是重建损失通常采用L1或L2范数。它要求修复后的图像跟真实高清图在像素层面尽可能接近。这个损失简单直接但它有一个众所周知的问题像素级距离不能很好地反映人眼的感知相似度。两张图只差一个像素位置L2距离可能很小但人眼看起来完全是两个人。为了弥补这个缺陷GPEN在像素重建之外还用了感知损失perceptual loss有时也叫特征匹配损失。做法是把修复图和GT图一起输入一个预训练的分类网络通常是VGG然后在中间层的特征图上计算L1距离。这一步的核心逻辑是低层特征接近意味着纹理细节一致高层特征接近意味着语义内容一致。感知损失不要求像素级对齐但要求场景内容一致这非常契合人脸修复的语义需求。值得强调的是GPEN的感知损失有个专门的细节它不是在VGG任意一层都算特征距离而是从预训练的StyleGAN判别器特征中进行匹配。这个设计很巧妙因为判别器特征本身就是为了区分真假人脸而优化的它的特征空间里天然编码了人脸的关键判别信息用它的特征做重建约束等于是在“人脸相似度这个维度”上做对齐比通用的VGG感知损失更贴合任务。这个细节很多讲GPEN的文章都没提但我觉得它恰恰是GPEN效果好的核心原因之一。3.3 身份损失防止“修完换了一个人”第三拳是身份损失Identity Loss。人脸修复里最容易翻车的点不是清晰度不够而是修复完“不像本人”。早期的GAN修复方法修图后经常像给用户免费整了个容这在商业产品中是灾难级的体验。GPEN为了压制这个问题引入了预训练人脸识别模型如ArcFace或FaceNet提取身份特征再计算修复图与GT图身份特征之间的余弦相似度或L2距离。身份损失会逼迫生成器在提升真实感的同时确保同一个人的两张图被识别模型判定为同一个人。这个损失的引入也解释了GPEN内部结构的取舍。如果没有全局编码分支提供的真实信息仅靠StyleGAN生成先验输出结果在身份特征上必然跑偏。而身份损失的存在让网络必须把输入图中那些微妙的身份细节比如颧骨的形状、眼睑的曲度保留下来。这就是我之前说的“好看”和“是本人”两件事GPEN靠损失函数组合同时进行优化。3.4 三路损失如何平衡才不至于训练崩溃三路损失不是简单相加就完事。我复现训练时发现它们之间存在明显的对抗关系重建损失过强会造成图像模糊化因为L1/L2对高频细节持保守态度对抗损失过强又会让图像锐利过头甚至失真身份损失则在两者之间做牵制。GPEN在这三者间通过经验权重做平衡并配合多尺度判别器、学习率衰减等trick让训练过程基本收敛稳定。具体模型收敛时我观察到loss曲线有几个典型阶段。前几千步重建损失下降最快因为网络在学习最基本的图像对应关系随后感知损失开始起作用图像的语义细节逐步清晰等到训练中期对抗损失开始产生明显波动这个阶段输出的图像逐渐变得锐利但同时也会开始出现伪影到最后阶段身份损失会把那些“加戏”过头的生成结果拉回来让主体特征更贴近输入。对比同样采用GAN先验的GFPGANGPEN的训练相对更好跑。这主要得益于渐进式解码器在每个尺度上都有重建监督梯度信号不会因为网络太深而消失。训练小技巧方面我建议在微调阶段逐步降低重建损失的权重给对抗损失留出更多空间这样最终输出会更锐利。4. 训练数据与退化模拟论文没写透的工程细节4.1 FFHQ作为训练数据源为什么够用GPEN的训练数据主要来自FFHQ高清人脸数据集。FFHQ包含7万张1024×1024的高质量人脸图涵盖不同年龄、性别、肤色、姿态和光照条件多样性非常好。但直接用FFHQ训练有个问题拿去跟真实低质量照片比FFHQ的图太“干净”了——每张图都是专业相机拍的高清图几乎没有噪声和模糊。所以训练时的核心思想是拿干净高清图作为GT再人为制造低质量版本作为输入让模型学习去退化degradation过程。这个思路在超分领域并不新鲜但是退化模型的设计直接决定了模型在真实场景中的泛化能力。4.2 退化模拟的关键参数模糊、下采样、噪声、JPEG压缩GPEN论文中低质量数据的生成遵循一个典型组合退化公式先做模糊处理高斯模糊核尺寸从7×7到21×21随机然后下采样缩放因子4、8、16甚至32再加入高斯噪声最后做JPEG压缩。实际操作中这些参数并不是固定的。随机性非常重要——模糊核的大小和方向要随机采样下采样比例要随机选择噪声强度要在一个范围内浮动JPEG品质参数也要变化。这样训练出来的模型才不会过拟合特定退化模式才能应对真实世界中几乎无限的退化组合。如果你自己复现训练我建议重点调一下模糊核的下限。模糊核太小比如只有3×3退化太轻模型学不到太多东西但模糊核太大超过31×31输入图的信息几乎被抹除干净身份特征已经不存在了再怎么修复也只能得到一张“平均脸”。我在实验中发现模糊核在15×21左右配合4倍下采样得到的退化难度跟实际老照片最接近。还有一个比较容易踩的坑——训练时尺寸的匹配。FFHQ的高清图是1024×1024但GPEN的解码器终点是512×512所以GT一般要预先缩到512。低质量图则根据退化因子缩到32、64或128不等。输入太小会导致提取不到身份特征输入太大又会让编码器学到“偷懒”的捷径——不靠GAN先验也能大致恢复进而影响对极端退化场景的泛化能力。4.3 多尺度训练策略与颜色增强的细节GPEN训练的另一个特色是多尺度训练。它不会把输入固定缩到同一个尺寸而是随机选择不同的退化尺度例如某个minibatch是64×64输入下一个batch是128×128让模型同时处理不同分辨率级别的输入。这个操作的作用是让网络的多尺度特征融合模块真正学“活儿”——它必须学会根据不同输入分辨率调整融合权重。同时论文还设置了颜色变换增强。真实老照片普遍存在偏色问题泛黄、褪色、偏青都很常见。如果不做颜色增强模型看到一张偏黄的老照片时可能直接按照“干净肤色”的分布强行纠正结果输出一张肤色发紫或发灰的可疑图像。训练中添加小幅度的色相、饱和度、亮度随机扰动能提升模型对颜色偏移的鲁棒性。4.4 真实照片微调与伪GT让模型从实验室走进现实仅靠合成的低质量图训练出来的模型在真实老照片上的效果可能还不够。GPEN在论文里给了两种训练阶段第一阶段在合成退化数据上训练第二阶段用真实低质量人脸图做微调。微调时需要用到伪GT策略先用第一阶段训练好的模型对真实低质量图做一次修复再把修复结果当作权重很大的训练目标来继续训练。这个思路跟自监督学习非常接近目的是让模型逐渐适应真实分布的数据而不是只对人工退化规律有效。伪GT有一个潜在风险——第一阶段模型的错误修复结果会作为“正确答案”被放大。所以实际操作中要人工筛选质量较高的伪GT样本去掉那些五官扭曲、脸色异常的坏样本。这一步没有捷径我当初为了微调模型手动过滤了两千多张修复效果不佳的老照片虽然费时间但过滤后模型在真实照片上的表现明显上了一个台阶。5. 论文实验结果与代码复现踩坑记5.1 论文里的评测PSNR、SSIM、FID与用户调研GPEN论文的实验部分除了常规的PSNR和SSIM指标还引入了FIDFréchet Inception Distance和用户调研。这是一个很重要信号——PSNR高不代表修复效果好在盲人脸修复场景中感知质量比像素对齐更有说服力。论文里呈现的对比结果显示GPEN在PSNR上未必超过所有方法但在FID和用户偏好比例上明显领先。更值得关注的是论文与GFPGAN、HiFaceGAN等同期工作的对比。GPEN在低分辨率输入下比如缩小8倍甚至16倍依然能保持稳定的身份一致性而其他方法在这么强的退化下要么模糊一片要么走向“整容怪”。我自己拿了一组32×32的微型头像测试GPEN能恢复出可辨认的五官GFPGAN多少也能做到但细节上稍逊一筹而HiFaceGAN输出的脸型有明显变形。不过这里我要说句公道话GFPGAN和GPEN在高质量输入下比如128×128以上分辨率差距并不大普通人肉眼甚至很难分辨。差距主要出现在极端退化场景。所以选择哪个模型要看你的输入图质量分布。如果用户上传的照片基本在80×80以上两者皆可如果大量是缩略图级别的模糊小图GPEN优势更明显。5.2 推理环境准备PyTorch版本、facexlib与预训练权重先说明GPEN官方开源代码基于PyTorch实现。部署推理环境时需要准备PyTorch、torchvision、facexlib、numpy、opencv-python以及下载官方的预训练权重。GPU显存建议8G以上我用6G显存的卡跑512分辨率修复一张图大概3-5秒勉强能接受如果要跑批量任务最好上12G或更高。推理的核心代码非常简洁先做一次人脸检测和对齐把原图中的人脸框出来并裁剪成正方形然后用GFPGAN或GPEN模型做修复再把修复后的人脸贴回原图。GPEN官方仓库里提供的是GPEN-BFR-512模型它已经是在FFHQFlickrFace等数据上训练好的权重开箱即用。5.3 我踩过的几个坑Windows编译、装饰器兼容与对齐定位说到具体踩坑我有几个记忆犹新的。第一个是Windows环境编译。官方代码依赖StyleGAN2中使用的DCNdeformable convolution编译时需要Ninja支持。在Windows上如果你没安装对应版本的Ninja和Visual Studio构建工具第一次运行时会直接报shape mismatch或者找不到编译器的错误。解决方法是提前安装ninja并把VS的C生成工具链配好。这个步骤卡了我差不多一个下午倒不是说多难而是报错信息比较隐晦Google半天才能定位到是编译环境的问题。第二个是PyTorch版本的兼容性问题。官方代码里有一段用于推理时关闭梯度计算的装饰器旧版本写法在PyTorch 2.x下会报错甚至间接导致模型输出错乱。解决方法非常简单把原来的装饰器换成了torch.no_grad()。如果你直接用最新的PyTorch跑官方demo很可能会遇到这个坑提前改掉省得排查半天。第三个坑是人脸检测的对齐精度。GPEN官方对代码用MTCNN做检测对一般正脸照片效果很好但遇到大角度侧面照或者闭眼照片很容易检测失败修复程序直接崩掉。针对这种情况我补充了一个降级策略当检测不到人脸时就按图像中心做裁剪修复虽然效果不如检测对齐好但至少不会报错。这个兜底逻辑在实际项目中非常重要。5.4 实测效果偏色、遮挡、大角度侧脸的边界在哪代码环境配好后我在一批真实老照片上做了效果测试。第一组是偏色特别严重的照片黄色调GPEN能够基本纠正肤色但背景中原本泛黄的墙和衣物也会被一起“纠正”成偏蓝灰色调说明颜色校正逻辑主要还是以人脸为中心的场景内其他物体的颜色偏移控制不够精准。第二组是戴眼镜的人脸照片。GPEN对普通近视眼镜的还原效果还不错基本能保留眼镜边框结构但对反光很强烈的镜片修复结果经常出现镜片区域的纹理混乱像是把镜片当成了皮肤去生成。这不算GPEN的锅任何基于GAN先验的修复方法遇到眼镜反光都会有类似问题因为FFHQ里戴眼镜且反光的训练样本太少了。第三组是大角度侧脸。当人脸偏转角度超过45度时GPEN的身份保持能力会明显下降输出结果趋近于一张正脸的“融合面孔”。说白了还是因为FFHQ数据集中正脸和微侧脸的数据占绝对主导极端角度的覆盖不够。在真实产品中建议用额外的侧脸检测和针对性模型来处理这批case。5.5 批量推理时的高效处理思路如果你打算用GPEN处理成百上千张照片有几件事值得提前准备。第一是先跑一遍人脸检测和人脸对齐把所有检测到的人脸和对应的仿射变换矩阵保存下来。第二是分批推理如果显存充足可以一次batch处理多张人脸大幅提升吞吐率。第三是写好后处理逻辑把修复好的人脸按原来的位置贴回原图。这里要特别提醒贴回时要用羽化融合直接用硬mask会留下明显的边缘接缝。业界常用的做法是对mask做距离变换后再做高斯模糊模糊半径根据人脸大小动态调整接缝会自然很多。颜色匹配也非常关键。修复后人脸和周围背景的亮度、白平衡可能不一致在贴回前需要对修复区域做一次色彩迁移让肤色跟周围环境的光照条件协调。我见过不少团队实现到最后一步就因为没做颜色匹配贴回后的人脸像一块膏药一样贴在照片上一眼假。5.6 下一步的扩展思路从静态修复到视频、风格迁移GPEN的架构天然适合扩展到其他任务。我在自己项目中做过一个尝试把GPEN的预训练权重接到视频人脸修复的流程中对每一帧做人脸检测、修复、贴回再通过时域一致性模块平滑帧间闪烁。效果虽然不能跟商用的视频修复算法比但已经能明显改善老录像中的人脸清晰度。另外一个有趣的扩展方向是风格迁移。既然GPEN的渐进式解码器是从StyleGAN里借来的那StyleGAN支持的一切操作比如风格混合、属性编辑理论上都可以在GPEN修复后的潜空间里进行。这意味着你不仅能修复一张模糊老照片还能顺便改变照片里人物的光线方向、年龄甚至表情。当然这些都是后话需要额外叠加属性编辑的网络但至少底子是通的。回过头来看GPEN这篇论文之所以能在人脸修复领域留下名字核心不在于它用了多复杂的网络结构而在于它对“先验”这件事想得很透彻——把预训练GAN当作知识库把修复任务变成“在知识库的引导下逐步还原信息”的过程。这套方法论放到今天依然是很多生成式修复工作的基础框架。如果你正在做人脸修复、老照片翻新或相关方向的开发花时间把这篇论文和开源代码吃透绝对是一笔稳赚不赔的投入。
返回列表