目录
- 摘要
- Abstract
- 1 GFPGAN
- 1.1 总体结构
- 1.2 实验研究
- 1.3 代码分析
- 总结
摘要
本周主要的学习内容是GFPGAN模型。GFPGAN是一种基于生成对抗网络(GAN)的模型,其利用封装在预训练的人脸GAN中的丰富多样的先验进行人脸图像的修复。这种生成面部先验(GFP)通过空间特征变换层被整合到面部恢复过程中,使得GFPGAN能够实现真实性和保真度的良好平衡。 得益于强大的生成面部先验和精致的设计,GFPGAN只需一次前向传递即可共同还原面部细节并增强色彩。GFPGAN 的出现,解决了传统模型因输入质量低而无法提供准确的几何先验信息的问题。本周,作者将从总体结构、实验研究以及代码分析三部分对GFPGAN进行学习。
Abstract
The main content of this week’s study is the GFPGAN model. GFPGAN is a model based on Generative Adversarial Network (GAN)that leverages rich and diverse priors encapsu-lated in a pretrained face GAN for blind face restoration.This Generative Facial Prior (GFP) is incorporated intothe face restoration process via spatial feature transformlayers, which allow our method to achieve a good balanceof realness and fidelity. Thanks to the powerful genera-tive facial prior and delicate designs,GFP-GAN couldjointly restore facial details and enhance colors with just asingle forward pass. The emergence of GFPGAN has solved the problem of traditional models being degraded due to low input quality. This week, the author will study GFPGAN from three parts: overall structure, experimental research, and code analysis.
1 GFPGAN
GFPGAN是一种基于生成对抗网络(GAN)的模型,由腾讯应用研究中心开发的一种面向实际应用的人脸修复算法,利用预训练的人脸生成对抗网络中封装的丰富多样的先验知识进行盲人脸修复。近年来,GFPGAN在图像生成与修复领域备受瞩目。它凭借其强大的生成能力和高度逼真的修复效果,成为了众多研究者、开发者乃至普通用户关注的焦点。本次的学习基于一篇名为Towards Real-World Blind Face Restoration with Generative Facial Prior的论文。
在论文中作者提出了一种名为GFPGAN的模型,与最先进的面部修复方法在实际的低质量图像上的相比较,其中包括:HiFaceGAN 、DFDNet 、Wan和 PULSE 。以前的方法难以恢复正确的面部细节或保留面部特征,但论文提出的GFPGAN在真实性和保真度之间取得了良好的平衡,伪影要少得多。此外,强大的生成面部先验使其能够联合进行修复和色彩增强。
1.1 总体结构
GFPGAN作为GAN的一种变体模型,其结构主要也是生成器和判别器两部分。生成器负责将低分辨率图像转换为高分辨率图像,而判别器则用于判断生成的图像是否真实。生成器采用了残差块(Residual Block)作为基础模块,通过堆叠多个残差块来实现深度网络的构建。此外,为了进一步提高模型的性能,GFPGAN还引入了注意力机制,如通道注意力(Channel Attention)和空间注意力(Spatial Attention)。
生成器
生成器的结构如下图所示,其由包括一个降解去除模块(U-Net)和一个预先训练的面部GAN作为面部先验两部分组成。两部分由Flatent和Fspatial连接,MLP实际上就是由多个linear层所组成,而Fspatial则是包含U-Net中decoder部分的多个尺度的特征图。它们之间通过潜在的代码映射和若干通道分割空间特征变换进行连接(CS-SFT)层。
降级去除模块旨在显式地去除降级,并提取Flatent和Fspatial的“干净”特征,从而减轻后续模块的负担。而使用U-Net作为退化移除网络主要是为了增加大模糊消除的感受野以及生成多分辨率特征。
模型中会在U-Net的每个decoder层计算一个Restoration Loss,以此得到Flatent和Fspatial中的“干净”特征。Restoration Loss的定义如下所示:
在生成器中,输入图片首先经U-Net层得到瓶颈处的Flatent,Flatent在经MLP处理后得到中间潜在编码W,及16个512的latent code,w再经styleGAN处理得到FGAN,即中间卷积的特征。styleGAN每层生成的特征图(FGAN)的后半部分进行一个空间上的仿射变换,即平移和缩放操作。该操作是通过两个卷积层得到的。
由于每一层的FGAN和Fspatial的大小和维度是相对应的,所以他们可以直接进行相乘或者相加的操作,
判别器
判别器结构如下图所示,它会对人脸的整体、局部(眼睛和嘴巴)以及身份保留信息三部分进行判别然后得到三个LOSS。
(1) Adversarial Loss:
(2) Facial Component Loss:
(3) Identity Preserving Loss:
1.2 实验研究
1.数据集
训练数据集:作者在FFHQ数据集上训练GFP-GAN,该数据集由70,000张高质量图像组成。在训练期间,作者将所有图像的大小调整为 512。 GFP-GAN 是在合成数据上训练的,这些合成数据近似于真实的低质量图像,并在推理过程中泛化到真实的图像。
测试数据集:
(1) CelebA-Test:CelebA-Test 是一个合成数据集,其中包含来自其测试分区的 3,000 张 CelebA-HQ 图像。生成方式与训练期间的生成方式相同。
(2)LFW: LFW 包含低质量野外图像。作者将验证分区中每个标识的所有第一个映像分组,形成 1711 个测试映像。
(3)CelebChild-Test:CelebChild-Test包含从互联网上收集的180张名人的童脸。它们质量低下,其中许多是黑白老照片。
(4)WebPhoto:这是作者在现实生活的互联网中抓取了 188 张低质量照片,提取 407 张人脸来构建 WebPhoto 测试数据集。这些照片具有多种多样且复杂的退化。 其中一些是老照片,在细节和颜色上都有非常严重的退化。
2. 实验评估
(1)广泛使用的非参考感知指标:FID 和NIQE。
(2)采用像素度量(PSNR和SSIM)和感知度量(LPIPS )进行CelebA-Test withGround-Truth (GT)。
(3)在ArcFace特征嵌入中用天使测量身份距离,其中较小的值表示与GT的同一性更近。
3.实验流程:
(1)作者采用预训练的StyleGAN2和512个输出作为生成面部的先验。StyleGAN2的通道倍增器设置为一,以缩小模型大小。用于降解去除的UNet由7个下采样和7个上采样组成,每个采样都有一个残差块。对于每个cS-SFT层,作者使用两个卷积层分别生成α和β的仿射参数。
(2)训练小批量大小设置为12。通过水平翻转和颜色抖动来增强训练数据。作者考虑三个组成部分:左眼、右眼、嘴巴对面部成分的损失,因为它们在感知上很重要。每个组件都按ROI裁剪对齐与面部对齐。
(3)使用Adam 优化器训练模型,总共进行了800k次迭代。学习率设置为2 ×10,然后在第
700k、750k次迭代中衰减了2倍。作者使用PyTorch框架实现模型,并使用四个NVIDIA Tesla P40 GPU对其进行训练。
(4)实验结果
论文中通过与其他先进的人类修复方法比较呈现GFP-GAN的实验成果。其中包括: HiFaceGAN、DFDNet、PSFRGAN、Super-FAN和Wan。用于面部恢复的GAN反转方法:PULSE 和mGANprior也用于比较。除此还将GFP-GAN与图像恢复方法进行了比较:RCAN、ESRGAN和DeblurGANv2,并在面部训练集上对它们进行了微调,以便进行公平的比较。
合成CelebA测试
测试是在两种设置下进行的:
-
盲人脸恢复,其输入和输出具有相同的分辨率,定量结果如下图所示。
-
4倍人脸超分辨率。请注意,我们的方法可以接受上采样的图像作为人脸超分辨率的输入,定量结果如下图所示。
在这两种设置下,GFP-GAN都实现了最低的LPIPS,这表明GFPGAN的结果在感知上接近真实值。GFP-GAN还获得了最低的FID和NIQE,表明输出分别与真实人脸分布和自然图像分布具有近距离。除了感知性能外,GFP-GAN还保留了更好的身份,由面部特征嵌入的最小程度表示。
但需注意以下两点:
1)GFP-GAN的FID和NIQE低于GT并不意味着其性能优于GT,因为这些“感知”指标在粗尺度上与人类意见分数密切相关,但在更精细的尺度上并不总是密切相关;
2)像素指标PSNR和SSIM与人类观察者的主观评价[2,41]相关性不佳,GFP-GAN在这两个指标上并不擅长。
结果如上图所示,主要的发现有以下几点:
1)得益于强大的生成式面部先验,GFPGAN可以恢复眼睛(瞳孔和睫毛)、牙齿等的忠实细节。
2)GFPGAN在修复中将面部视为整体,也可以生成逼真的头发,而以前依赖组件字典(DFDNet)或解析映射(PSFRGAN)的方法无法产生忠实的头发纹理。
3)GFP-GAN能够保持保真度,例如,它产生自然的闭口没有像PSFRGAN那样强制添加齿。除此,GFP-GAN还可以恢复合理的眼睛注视方向。
LFW、CelebChild和WedPhoto测试
为了测试模型的泛化能力,作者在三个不同的真实数据集上评估了GFP-GAN。定量结果如下图所示。
GFP-GAN在这三个数据集上都取得了优越的性能,显示出其显著的泛化能力。尽管PULSE也能获得较高的感知质量(较低的FID分数),但它无法保留面部身份。如下图所示,GFP-GAN能够联合进行人脸恢复和色彩增强,利用强大的生成先验来处理真实生活中的照片。作者的方法能够在复杂的现实世界退化条件下生成合理且逼真的面部,而其他方法则无法恢复忠实的面部细节或会产生伪影(特别是在图5中的WebPhoto-Test)。
除了眼睛和牙齿等常见面部组件外,GFP-GAN在头发和耳朵方面也表现得更好,因为GFP先验考虑的是整个面部,而不是单独的部分。通过SC-SFT层,GFP-GAN能够实现高保真度。大多数先前的方法无法恢复闭着的眼睛,而GFP-GAN能够成功地恢复它们,并且产生的伪影更少。
1.3 代码分析
GFPGAN的项目代码是开源的,代码地址为:https://github.com/TencentARC/GFPGAN
接下来我将以我自身学习的实际情况对项目的一部分代码进行简单分析。
(1)Input处理
Dataset的代码如下:
def __getitem__(self, index):
......
#直接看return内容
if self.crop_components:
return_dict = {
'lq': img_lq,
'gt': img_gt,
'gt_path': gt_path,
'loc_left_eye': loc_left_eye,
'loc_right_eye': loc_right_eye,
'loc_mouth': loc_mouth
}
return return_dict
else:
return {'lq': img_lq, 'gt': img_gt, 'gt_path': gt_path}
这里返回的主要有三项:img_lq,img_gt, gt_path,分别是LR输入、真值,和gt的路径。loc_left_eye、loc_right_eye、loc_mouth是使用眼睛和嘴巴位置信息时,作为可选输出。
其中img_lq是由img_gt变换得到的LR图像,img_gt是高分辨图像
再来看一下img_lq的生成过程
def __getitem__(self, index):
...#数据读入部分
# ------------------------ generate lq image ------------------------ #
# blur
kernel = degradations.random_mixed_kernels(...)
img_lq = cv2.filter2D(img_gt, -1, kernel)
# downsample
scale = np.random.uniform(self.downsample_range[0], self.downsample_range[1])
img_lq = cv2.resize(img_lq, (int(w // scale), int(h // scale)), interpolation=cv2.INTER_LINEAR)
# noise
if self.noise_range is not None:
img_lq = degradations.random_add_gaussian_noise(img_lq, self.noise_range)
# jpeg compression
if self.jpeg_range is not None:
img_lq = degradations.random_add_jpg_compression(img_lq, self.jpeg_range)
# resize to original size
img_lq = cv2.resize(img_lq, (w, h), interpolation=cv2.INTER_LINEAR)
# random color jitter (only for lq)
if self.color_jitter_prob is not None and (np.random.uniform() < self.color_jitter_prob):
img_lq = self.color_jitter(img_lq, self.color_jitter_shift)
# random to gray (only for lq)
if self.gray_prob and np.random.uniform() < self.gray_prob:
img_lq = cv2.cvtColor(img_lq, cv2.COLOR_BGR2GRAY)
img_lq = np.tile(img_lq[:, :, None], [1, 1, 3])
if self.opt.get('gt_gray'): # whether convert GT to gray images
img_gt = cv2.cvtColor(img_gt, cv2.COLOR_BGR2GRAY)
img_gt = np.tile(img_gt[:, :, None], [1, 1, 3]) # repeat the color channels
# BGR to RGB, HWC to CHW, numpy to tensor
img_gt, img_lq = img2tensor([img_gt, img_lq], bgr2rgb=True, float32=True)
# random color jitter (pytorch version) (only for lq)
if self.color_jitter_pt_prob is not None and (np.random.uniform() < self.color_jitter_pt_prob):
brightness = self.opt.get('brightness', (0.5, 1.5))
contrast = self.opt.get('contrast', (0.5, 1.5))
saturation = self.opt.get('saturation', (0, 1.5))
hue = self.opt.get('hue', (-0.1, 0.1))
img_lq = self.color_jitter_pt(img_lq, brightness, contrast, saturation, hue)
...#像素值范围映射unit8,正则化
...#return
主要就是模糊、加噪、随机像素值抖动、随机灰度化、随机色彩变化等过程生成LR图像
(2)GFPGANv1
这块算是整个结构中内容最多的一部分了,该部分是对输入图像的通道进行降维,产生latent code,通过MLP送到生成器中。首先经过一个3通道到512通道的变换,然后再做通道和空间都进行下采样的6个相同操作,这部分是BasicSR里面的ResBlock函数完成的,可以自行查一下相关实现,最终输出latent code和需要进行空间特征约束的condition。
其中一部分作用是将img_lr 变成 latent code
def __init__(self, ...)
first_out_size = 2**(int(math.log(out_size, 2)))
#ConvLayer
self.conv_body_first = ConvLayer(3, channels[f'{first_out_size}'], 1, bias=True, activate=True)
# downsample
in_channels = channels[f'{first_out_size}']
self.conv_body_down = nn.ModuleList()
for i in range(self.log_size, 2, -1):
out_channels = channels[f'{2**(i - 1)}']
self.conv_body_down.append(ResBlock(in_channels, out_channels, resample_kernel))
in_channels = out_channels
self.final_linear = EqualLinear(channels['4'] * 4 * 4, linear_out_channel, bias=True, bias_init_val=0, lr_mul=1, activation=None)
...
def forward(self, ...)
# encoder
feat = self.conv_body_first(x)
for i in range(self.log_size - 2):
feat = self.conv_body_down[i](feat)
unet_skips.insert(0, feat)
feat = self.final_conv(feat)
style_code = self.final_linear(feat.view(feat.size(0), -1))
...
另外一部分产生Fspatial再通过卷积操作得到两个系数作为condition约束,送到下面的代码中处理
def __init__():
# for SFT modulations (scale and shift)
self.condition_scale = nn.ModuleList()
self.condition_shift = nn.ModuleList()
for i in range(3, self.log_size + 1):
out_channels = channels[f'{2**i}']
if sft_half:
sft_out_channels = out_channels
else:
sft_out_channels = out_channels * 2
self.condition_scale.append(
nn.Sequential(
EqualConv2d(out_channels, out_channels, 3, stride=1, padding=1, bias=True, bias_init_val=0),
ScaledLeakyReLU(0.2),
EqualConv2d(out_channels, sft_out_channels, 3, stride=1, padding=1, bias=True, bias_init_val=1)))
self.condition_shift.append(
nn.Sequential(
EqualConv2d(out_channels, out_channels, 3, stride=1, padding=1, bias=True, bias_init_val=0),
ScaledLeakyReLU(0.2),
EqualConv2d(out_channels, sft_out_channels, 3, stride=1, padding=1, bias=True, bias_init_val=0)))
然后将上面的两部分送到StyleGAN2Generator中处理,在逐层进行卷积运算时,将前面产生的conditions约束也加入运算。
总结
在实际应用中,GFPGAN模型已经成为人脸修复和增强的重要工具之一,为增强现实、AI主播制作等领域带来了更加自然、逼真和智能的交互体验。随着技术的不断发展和完善,GFPGAN模型将会在未来发挥更加重要的作用。通过本周的学习,我对wav2lip有了初步的认识和了解,尽管GFPGAN相较于过去的技术有显著提升,但其也是存在不足。作者提出,当真实图像退化严重时,GFPGAN还原的面部细节会因伪影而扭曲。这是因为合成降级和训练数据分布与实际不同造成的。解决方法是从真实数据中学习这些分布,而不是仅仅使用合成数据,这将是未来研究的一个突破口。