作者:来源于源码深度分析
论文:GFP-GAN: Towards Real-World Blind Face Restoration with Generative Facial Prior
机构:腾讯 ARC(Applied Research Center)
开源地址:github.com/TencentARC/…
一、概述
人脸修复(Face Restoration)是计算机视觉中的经典难题。传统方法在低质量输入图像面前往往捉襟见肘——尤其是面对真实世界中复杂混合的退化(模糊、噪声、压缩伪影等)时,修复效果有限且细节缺失。
GFPGAN(Generative Facial Prior GAN) 是腾讯 ARC 提出的突破性算法,其核心创新在于:
将预训练 StyleGAN2 蕴含的丰富生成式面部先验知识引入退化人脸修复,通过创新的空间特征变换(SFT)机制,在保真度与感知质量之间取得优异平衡。
本文将从项目结构、核心算法、关键代码实现三个维度,对 GFPGAN 进行全面深度的技术解析。
二、项目结构总览
GFPGAN-master/
├── gfpgan/ # 核心模块包
│ ├── archs/ # 网络架构定义
│ │ ├── gfpganv1_arch.py # GFPGAN v1(原版,需要CUDA扩展)
│ │ ├── gfpganv1_clean_arch.py # GFPGAN v1 Clean(纯PyTorch,跨平台)
│ │ ├── gfpgan_bilinear_arch.py # GFPGAN 双线性插值版本
│ │ ├── arcface_arch.py # ArcFace 人脸识别网络(用于身份损失)
│ │ ├── restoreformer_arch.py # RestoreFormer(Transformer-based)
│ │ ├── stylegan2_bilinear_arch.py # StyleGAN2 双线性版本
│ │ └── stylegan2_clean_arch.py # StyleGAN2 纯净版本
│ ├── data/
│ │ └── ffhq_degradation_dataset.py # FFHQ退化数据集(在线动态生成LQ)
│ ├── models/
│ │ └── gfpgan_model.py # 训练模型(损失计算、优化器管理)
│ ├── utils.py # GFPGANer 推理助手类
│ └── train.py # 训练入口
├── inference_gfpgan.py # 命令行推理脚本
├── options/
│ ├── train_gfpgan_v1.yml # 完整训练配置(含面部判别器、身份损失)
│ └── train_gfpgan_v1_simple.yml # 简化训练配置
├── scripts/
│ ├── convert_gfpganv_to_clean.py # 模型转换脚本
│ └── parse_landmark.py # 关键点预处理脚本
├── tests/ # 单元测试
├── inputs/ # 示例输入图像
├── results/ # 推理结果输出
└── requirements.txt # 依赖列表
项目依赖
basicsr>=1.4.2 # 腾讯开源图像修复基础库
facexlib>=0.2.5 # 人脸检测/对齐库
torch>=1.7 # PyTorch 深度学习框架
opencv-python # 图像处理
torchvision # 视觉工具
lmdb # 高效数据库(训练数据)
三、核心算法思想
3.1 问题定义:盲人脸修复
给定退化低质量图像 ,目标是恢复高质量图像 :
其中 为模糊核, 为下采样, 为噪声与压缩伪影。由于退化参数未知(即"盲"),这是一个严重欠约束问题。
3.2 核心创新:生成式面部先验(GFP)
GFPGAN 的关键洞察是:预训练的 StyleGAN2 模型已经学习了高质量人脸的完整先验分布,包括纹理细节、面部组件位置、光照等。
通过将退化图像"对准"StyleGAN2 的潜在空间,可以借助其生成能力补全缺失的细节。
3.3 整体网络架构:U-Net 编码器 + StyleGAN2 解码器
输入低质量图 (LQ)
│
┌────▼────────────────────────────────────────────┐
│ U-Net 编码器 │
│ 512×512 → 256 → 128 → 64 → 32 → 16 → 8 → 4×4 │
│ (逐步下采样,保存各级 skip 特征) │
└─────────────────────────────────────────────────┘
│ 风格码 style_code (512维)
│ 各层 SFT 条件 conditions
│
┌────▼─────────────────────────────────────────────┐
│ StyleGAN2 解码器(含SFT调制) │
│ 4×4 → 8 → 16 → 32 → 64 → 128 → 256 → 512×512 │
│ 每层注入 SFT 条件(scale + shift) │
└──────────────────────────────────────────────────┘
│
高质量修复图 (HQ)
四、核心架构深度解析
4.1 U-Net 编码器(Degradation Removal)
4.1.1 下采样路径
# gfpganv1_clean_arch.py - GFPGANv1Clean.__init__()
# 通道配置(narrow=1时)
channels = {
'4': 256, '8': 256, '16': 256, '32': 256,
'64': 256, '128': 128, '256': 64, '512': 32, '1024': 16
}
# 第一层卷积
self.conv_body_first = nn.Conv2d(3, channels[f'{first_out_size}'], 1)
# 下采样残差块链
self.conv_body_down = nn.ModuleList()
for i in range(self.log_size, 2, -1): # 从大到小(512→256→...→8)
out_channels = channels[f'{2**(i - 1)}']
self.conv_body_down.append(ResBlock(in_channels, out_channels, mode='down'))
每个 ResBlock(mode='down') 包含:
- Conv1 → LeakyReLU → 双线性下采样 → Conv2 → LeakyReLU
- Skip 连接:双线性下采样 → 1×1 Conv
4.1.2 风格码提取
# final_linear 将 4×4 特征图 flatten 后映射为风格码
self.final_linear = nn.Linear(channels['4'] * 4 * 4, linear_out_channel)
# forward() 中:
style_code = self.final_linear(feat.view(feat.size(0), -1))
# 当 different_w=True 时,为每个 StyleGAN2 层生成不同的 w code
if self.different_w:
style_code = style_code.view(style_code.size(0), -1, self.num_style_feat)
different_w 选项允许为 StyleGAN2 的不同层提供各自的风格码,增强了修复灵活性。
4.1.3 上采样路径(生成 SFT 条件)
# 上采样路径:逐级恢复空间分辨率
self.conv_body_up = nn.ModuleList()
for i in range(3, self.log_size + 1): # 从小到大(8→16→...→512)
out_channels = channels[f'{2**i}']
self.conv_body_up.append(ResBlock(in_channels, out_channels, mode='up'))
# SFT 条件生成网络(scale 和 shift 各一组)
self.condition_scale = nn.ModuleList()
self.condition_shift = nn.ModuleList()
for i in range(3, self.log_size + 1):
self.condition_scale.append(
nn.Sequential(
nn.Conv2d(out_channels, out_channels, 3, 1, 1),
nn.LeakyReLU(0.2, True),
nn.Conv2d(out_channels, sft_out_channels, 3, 1, 1)))
self.condition_shift.append(
nn.Sequential(
nn.Conv2d(out_channels, out_channels, 3, 1, 1),
nn.LeakyReLU(0.2, True),
nn.Conv2d(out_channels, sft_out_channels, 3, 1, 1)))
forward() 中的上采样流程:
for i in range(self.log_size - 2):
feat = feat + unet_skips[i] # U-Net 跳跃连接
feat = self.conv_body_up[i](feat) # 上采样
scale = self.condition_scale[i](feat)
shift = self.condition_shift[i](feat)
conditions.append(scale.clone())
conditions.append(shift.clone()) # 交替存放 scale, shift
4.2 空间特征变换(Spatial Feature Transform, SFT)
SFT 是 GFPGAN 的核心创新点,用于将编码器提取的图像退化信息注入 StyleGAN2 生成器的各个层:
# StyleGAN2GeneratorCSFT.forward() 中的 SFT 调制
if i < len(conditions):
if self.sft_half: # 仅对一半通道应用SFT
out_same, out_sft = torch.split(out, int(out.size(1) // 2), dim=1)
out_sft = out_sft * conditions[i - 1] + conditions[i]
out = torch.cat([out_same, out_sft], dim=1)
else: # 对全部通道应用SFT
out = out * conditions[i - 1] + conditions[i]
SFT 的设计哲学:
- 保留 StyleGAN2 先验:不修改 StyleGAN2 的权重(
fix_decoder=True),而是通过 SFT 将图像信息"注入"到生成过程 - 空间自适应:scale 和 shift 具有与生成特征相同的空间分辨率,允许像素级精细控制
sft_half模式:只对一半通道应用 SFT,保留另一半的生成先验,平衡修复与生成质量
4.3 StyleGAN2 调制卷积(ModulatedConv2d)
StyleGAN2 的调制卷积是风格注入的核心机制:
# stylegan2_clean_arch.py
class ModulatedConv2d(nn.Module):
def forward(self, x, style):
b, c, h, w = x.shape
# 风格调制权重
style = self.modulation(style).view(b, 1, c, 1, 1)
# weight: (1, c_out, c_in, k, k); style: (b, 1, c, 1, 1)
weight = self.weight * style # (b, c_out, c_in, k, k)
if self.demodulate:
# 去调制(归一化),确保风格不影响特征图统计量
demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + self.eps)
weight = weight * demod.view(b, self.out_channels, 1, 1, 1)
# reshape 为分组卷积
weight = weight.view(b * self.out_channels, c, self.kernel_size, self.kernel_size)
x = x.view(1, b * c, h, w)
out = F.conv2d(x, weight, padding=self.padding, groups=b)
return out.view(b, self.out_channels, *out.shape[-2:])
调制流程:
- 风格码通过全连接层映射为每个输入通道的缩放系数
- 与卷积权重相乘(调制)
- 去调制(demodulate)进行归一化,避免特征图方差失控
- 执行卷积
4.4 ArcFace 身份网络(ResNetArcFace)
用于计算身份保留损失(Identity Loss),确保修复后的人脸与原始人脸身份一致:
class ResNetArcFace(nn.Module):
"""基于 ResNet 的 ArcFace 人脸识别网络
输入: 128×128 灰度图
输出: 512 维身份特征向量
"""
def __init__(self, block, layers, use_se=True):
self.conv1 = nn.Conv2d(1, 64, kernel_size=3, padding=1, bias=False)
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
self.fc5 = nn.Linear(512 * 8 * 8, 512) # 输出512维特征
def forward(self, x):
# x: (B, 1, 128, 128) 灰度图
x = self.layer1(self.maxpool(self.prelu(self.bn1(self.conv1(x)))))
x = self.layer4(self.layer3(self.layer2(x)))
x = self.fc5(x.view(x.size(0), -1))
return self.bn5(x)
IRBlock(改进残差块)中引入了 SEBlock(通道注意力):
class SEBlock(nn.Module):
"""Squeeze-and-Excitation Block"""
def forward(self, x):
b, c, _, _ = x.size()
y = self.avg_pool(x).view(b, c) # 全局平均池化
y = self.fc(y).view(b, c, 1, 1) # 两层全连接 + Sigmoid
return x * y # 通道重标定
4.5 面部组件判别器(FacialComponentDiscriminator)
用于单独判别眼睛、嘴巴区域的真实性,提供精细化的面部细节约束:
class FacialComponentDiscriminator(nn.Module):
"""VGG 风格架构,处理裁剪出的眼部/嘴部区域"""
def __init__(self):
self.conv1 = ConvLayer(3, 64, 3, downsample=False) # 80×80
self.conv2 = ConvLayer(64, 128, 3, downsample=True) # 40×40
self.conv3 = ConvLayer(128, 128, 3, downsample=False)
self.conv4 = ConvLayer(128, 256, 3, downsample=True) # 20×20
self.conv5 = ConvLayer(256, 256, 3, downsample=False)
self.final_conv = ConvLayer(256, 1, 3, activate=False) # 判别分数
def forward(self, x, return_feats=False):
feat = self.conv3(self.conv2(self.conv1(x)))
rlt_feats = [feat.clone()] # 用于风格损失
feat = self.conv5(self.conv4(feat))
rlt_feats.append(feat.clone())
out = self.final_conv(feat)
return out, rlt_feats if return_feats else None
五、数据管线:FFHQDegradationDataset
5.1 在线退化合成
GFPGAN 训练时使用 FFHQ(70,000 张高清人脸)数据集,并在线实时合成退化图像,避免了固定退化集的过拟合问题:
def __getitem__(self, index):
img_gt = load_image(self.paths[index]) # 加载高清GT图
# ① 随机水平翻转
img_gt, status = augment(img_gt, hflip=True, rotation=False)
# ② 随机混合模糊(各向同性/各向异性高斯核)
kernel = random_mixed_kernels(
kernel_list=['iso', 'aniso'],
kernel_prob=[0.5, 0.5],
blur_kernel_size=41,
blur_sigma=[0.1, 10])
img_lq = cv2.filter2D(img_gt, -1, kernel)
# ③ 随机下采样(比例0.8~8倍)
scale = np.random.uniform(0.8, 8)
img_lq = cv2.resize(img_lq, (int(w//scale), int(h//scale)))
# ④ 随机高斯噪声
img_lq = random_add_gaussian_noise(img_lq, noise_range=[0, 20])
# ⑤ 随机JPEG压缩
img_lq = random_add_jpg_compression(img_lq, jpeg_range=[60, 100])
# ⑥ 恢复原始尺寸
img_lq = cv2.resize(img_lq, (w, h))
# ⑦ 颜色抖动、灰度化(可选)
...
return {'lq': img_lq, 'gt': img_gt, 'loc_left_eye': ..., 'loc_right_eye': ..., 'loc_mouth': ...}
5.2 面部组件坐标预处理
训练前通过 parse_landmark.py 提取 FFHQ 数据集中每张图的面部关键点(眼睛、嘴巴位置),存储为 .pth 文件,供训练时 ROI Align 使用:
def get_component_coordinates(self, index, status):
components_bbox = self.components_list[f'{index:08d}']
if status[0]: # 水平翻转时交换左右眼
tmp = components_bbox['left_eye']
components_bbox['left_eye'] = components_bbox['right_eye']
components_bbox['right_eye'] = tmp
# 计算各组件的矩形坐标 [x1, y1, x2, y2]
for part in ['left_eye', 'right_eye', 'mouth']:
mean = components_bbox[part][0:2]
half_len = components_bbox[part][2]
loc = np.hstack((mean - half_len + 1, mean + half_len))
六、训练策略与损失函数
6.1 多判别器体系
| 判别器 | 功能 | 架构 |
|---|---|---|
net_d(主判别器) | 判别整张 512×512 人脸 | StyleGAN2Discriminator |
net_d_left_eye | 判别左眼区域(80×80) | FacialComponentDiscriminator |
net_d_right_eye | 判别右眼区域(80×80) | FacialComponentDiscriminator |
net_d_mouth | 判别嘴巴区域(120×120) | FacialComponentDiscriminator |
6.2 损失函数体系
GFPGAN 使用了精心设计的多项损失:
# optimize_parameters() 核心部分
# 1. 像素级 L1 损失(权重 0.1)
l_g_pix = self.cri_pix(self.output, self.gt) # L1(output, gt)
# 2. 图像金字塔损失(提前终止,前50k iter有效)
pyramid_gt = construct_img_pyramid() # gt的多尺度版本
for i in range(self.log_size - 2):
l_pyramid = cri_l1(out_rgbs[i], pyramid_gt[i]) * pyramid_loss_weight
# 3. 感知损失(VGG19特征匹配 + 风格损失)
# 使用 VGG19 的 conv1_2, conv2_2, conv3_4, conv4_4, conv5_4 层
l_g_percep, l_g_style = self.cri_perceptual(self.output, self.gt)
# 感知权重=1,风格权重=50
# 4. 对抗损失(wgan_softplus)
fake_g_pred = self.net_d(self.output)
l_g_gan = self.cri_gan(fake_g_pred, True, is_disc=False) # 权重 0.1
# 5. 面部组件对抗损失(vanilla GAN)
# 使用 ROI Align 提取眼睛/嘴巴区域
all_eyes = roi_align(self.output, boxes=rois_eyes, output_size=eye_out_size)
fake_left_eye, fake_left_eye_feats = self.net_d_left_eye(left_eyes)
l_g_gan_left_eye = self.cri_component(fake_left_eye, True, is_disc=False)
# 6. 面部组件风格损失(Gram矩阵匹配)
def _comp_style(feat, feat_gt, criterion):
return criterion(gram_mat(feat[0]), gram_mat(feat_gt[0]).detach()) * 0.5 \
+ criterion(gram_mat(feat[1]), gram_mat(feat_gt[1]).detach())
comp_style_loss = (_comp_style(left_feats, real_left_feats, cri_l1)
+ _comp_style(right_feats, real_right_feats, cri_l1)
+ _comp_style(mouth_feats, real_mouth_feats, cri_l1)) * 200
# 7. 身份损失(ArcFace特征距离)
out_gray = gray_resize_for_identity(self.output, size=128) # 转灰度,缩放到128
gt_gray = gray_resize_for_identity(self.gt, size=128)
l_identity = cri_l1(network_identity(out_gray), network_identity(gt_gray)) * 10
# 判别器训练(WGAN-softplus + R1正则)
l_d = cri_gan(real_d_pred, True) + cri_gan(fake_d_pred, False)
# R1 梯度惩罚(每16步一次)
l_d_r1 = r1_penalty(real_pred, self.gt) * r1_reg_weight / 2 * net_d_reg_every
6.3 总损失权重汇总
| 损失项 | 权重 | 说明 |
|---|---|---|
| 像素L1损失 | 0.1 | 低层次保真 |
| 图像金字塔损失 | 1.0 | 多尺度约束(前50k步) |
| VGG感知损失 | 1.0 | 高层特征匹配 |
| VGG风格损失 | 50 | 纹理风格匹配 |
| GAN对抗损失 | 0.1 | 整体感知质量 |
| 面部组件GAN损失 | 1.0×3 | 眼睛/嘴巴细节 |
| 面部组件风格损失 | 200 | 细节风格质量 |
| 身份损失 | 10 | 身份保持 |
| R1梯度惩罚 | 10 | 判别器稳定性 |
6.4 EMA(指数移动平均)
# 用于稳定训练并获得更好的生成质量
self.model_ema(decay=0.5**(32 / (10 * 1000)))
# decay ≈ 0.9977
# 测试时使用 EMA 模型
if hasattr(self, 'net_g_ema'):
self.net_g_ema.eval()
self.output, _ = self.net_g_ema(self.lq)
七、推理流程解析
7.1 GFPGANer 类
GFPGANer 是推理阶段的核心封装类,集成了完整的处理流程:
class GFPGANer():
def enhance(self, img, has_aligned=False, only_center_face=False,
paste_back=True, weight=0.5):
# 阶段1:人脸检测与对齐
if not has_aligned:
self.face_helper.read_image(img)
self.face_helper.get_face_landmarks_5(...) # 5点关键点检测
self.face_helper.align_warp_face() # 仿射变换对齐至512×512
# 阶段2:逐脸修复
for cropped_face in self.face_helper.cropped_faces:
# 归一化到 [-1, 1]
cropped_face_t = normalize(img2tensor(cropped_face/255.), (0.5,), (0.5,))
# GFPGAN 推理
output = self.gfpgan(cropped_face_t, return_rgb=False, weight=weight)[0]
restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))
# 阶段3:粘贴回原图(含背景超分)
if self.bg_upsampler is not None:
bg_img = self.bg_upsampler.enhance(img, outscale=self.upscale)[0]
self.face_helper.get_inverse_affine(None)
restored_img = self.face_helper.paste_faces_to_input_image(upsample_img=bg_img)
推理流程图:
原始图像
│
▼
RetinaFace 人脸检测 → 检测到的人脸 bbox + 5 点关键点
│
▼
仿射变换对齐 → 512×512 标准化人脸
│
▼
归一化 [-1, 1]
│
▼
GFPGAN 网络推理(U-Net编码器 + StyleGAN2解码器 + SFT)
│
▼
逆归一化 → 修复后人脸
│
▼
逆仿射变换 + 粘贴回原图(可选 RealESRGAN 背景超分)
│
▼
最终修复结果
7.2 命令行推理
# 基本用法
python inference_gfpgan.py -i inputs/whole_imgs -o results -v 1.3 -s 2
# 参数说明
-v 1.3 # 选择模型版本(1.0/1.2/1.3/1.4/RestoreFormer)
-s 2 # 最终输出放大倍数
--aligned # 输入已对齐的人脸(跳过检测步骤)
--bg_upsampler realesrgan # 使用 RealESRGAN 超分背景
-w 0.5 # 调整修复强度权重
八、版本演进
| 版本 | 架构 | 主要特性 |
|---|---|---|
| v1.0 | GFPGANv1(原版) | 需要 CUDA 自定义算子,使用 StyleGAN2 算子 |
| v1.2 | GFPGANv1Clean | 纯 PyTorch 实现,去掉 CE(色彩增强),通道数×2 |
| v1.3 | GFPGANv1Clean | 更自然的修复效果,对低质量/高质量输入均友好 |
| v1.4 | GFPGANv1Clean | 更多细节 + 更好的身份保持 |
| RestoreFormer | Transformer-based | 基于 VQ-VAE 的 Transformer 架构,特征一致性更强 |
九、RestoreFormer 架构简介
作为 GFPGAN 项目中集成的另一方案,RestoreFormer 使用了完全不同的技术路线:
class VectorQuantizer(nn.Module):
"""VQ-VAE 离散特征量化器"""
def forward(self, z):
# 将连续特征映射为离散码本中最近的向量
d = ||z - e||² # 计算距离
z_q = embedding[argmin(d)] # 量化
# Straight-through 梯度估计器
z_q = z + (z_q - z).detach()
return z_q
RestoreFormer 的优势在于使用 Transformer 的全局注意力机制处理面部特征,避免了 CNN 的局部感受野限制,在处理严重退化时具有更好的特征一致性。
十、训练配置关键设置
# train_gfpgan_v1.yml(部分)
network_g:
type: GFPGANv1
out_size: 512
num_style_feat: 512
channel_multiplier: 1
fix_decoder: true # 冻结 StyleGAN2 解码器
input_is_latent: true # 编码器输出直接作为 w 空间输入
different_w: true # 每层使用不同的 w code
sft_half: true # SFT 仅应用于一半通道
train:
optim_g: {type: Adam, lr: 2e-3}
optim_d: {type: Adam, lr: 2e-3}
scheduler:
type: MultiStepLR
milestones: [600000, 700000] # 在 60万、70万步降低学习率
gamma: 0.5
total_iter: 800000 # 总训练 80万步
net_d_reg_every: 16 # 每16步进行一次 R1 正则化
十一、工程设计亮点
11.1 注册表机制
基于 BasicSR 的注册表系统,实现架构/模型/数据集的动态注册和实例化:
@ARCH_REGISTRY.register()
class GFPGANv1Clean(nn.Module): ...
@MODEL_REGISTRY.register()
class GFPGANModel(BaseModel): ...
@DATASET_REGISTRY.register()
class FFHQDegradationDataset(data.Dataset): ...
通过配置文件中的 type 字段即可动态实例化对应类,极大提升了扩展性。
11.2 模型转换脚本
# scripts/convert_gfpganv_to_clean.py
# 将原版 GFPGAN(含 CUDA 自定义算子)转换为 Clean 版本
# 实现跨平台(Windows/CPU)部署
11.3 Cog 部署支持
# cog.yaml - 用于 Replicate.com 云端部署
build:
python_version: "3.8"
run:
- pip install basicsr facexlib gfpgan
predict: "cog_predict.py:Predictor"
十二、总结与展望
GFPGAN 的成功来自于以下几个关键设计决策:
- 善用预训练先验:不从头训练 StyleGAN2,而是冻结其权重并利用其已学习的高质量先验,大幅降低训练难度
- SFT 优雅注入:通过轻量的 scale+shift 操作将图像信息注入生成过程,兼顾保真度与感知质量
- 多粒度判别:整图判别器 + 眼睛/嘴巴局部判别器,确保全局结构与局部细节双重优化
- 身份保留约束:引入 ArcFace 特征距离,防止修复后"换脸"现象
- 在线退化合成:动态生成退化图像,提升对真实退化的泛化能力
局限性:
- 对非人脸内容(背景)需借助 RealESRGAN 等单独处理
- 极端低质量输入(如严重遮挡)仍具挑战性
- 修复结果有时过于"美颜化",身份特征可能轻微偏移
后续工作:
- RestoreFormer 引入 Transformer 进一步提升修复一致性
- CodeFormer(NIPS 2022)在 GFPGAN 基础上引入可控保真度机制
- DiffBIR 等扩散模型方法开始挑战 GAN-based 人脸修复的主导地位
参考文献
- Wang X, et al. "GFP-GAN: Towards Real-World Blind Face Restoration with Generative Facial Prior." CVPR 2021.
- Karras T, et al. "Analyzing and Improving the Image Quality of StyleGAN." CVPR 2020.
- Deng J, et al. "ArcFace: Additive Angular Margin Loss for Deep Face Recognition." CVPR 2019.
- Wang X, et al. "Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data." ICCVW 2021.
- Zhou S, et al. "Towards Real-World Blind Face Restoration with Generative Facial Prior." (RestoreFormer)
本文对 GFPGAN 项目代码进行了全面深入的技术解析,如有疏漏欢迎指正。喜欢请点赞收藏 ⭐