跳转到内容

StyleGAN2 — 把 StyleGAN 的水滴瑕疵和潜空间纠葛一起修掉

是什么

StyleGAN2 是 NVIDIA 2020 年的一篇论文,做的事情一句话:把前作 StyleGAN 留下的两个明显毛病——图像里到处冒”水滴状斑点”和潜空间方向变化不平滑——分别用『把 AdaIN 换成权重解调』和『路径长度正则』修掉,并在 FFHQ 人脸生成上把 FID 从 4.40 降到 2.84

日常类比:StyleGAN 像一台已经能拍 1024×1024 大头照的高级单反,但底片上总有几粒固定瑕疵——拍 100 张同样位置都有。StyleGAN2 没换镜头,是发现”瑕疵”是相机内部某个零件设计错了(AdaIN 的 instance normalization),换掉这个零件再加一个”防止画面之间过度跳变”的稳定器(path-length regularization),照片就干净了。

代价:训练时间比 StyleGAN 多约 1.4 倍,但模型改动不大,整体仍是 NVIDIA 那条”逐分辨率加 style 控制”的路线。

为什么重要

不理解 StyleGAN2,下面这些事说不清:

  • 为什么 2020 年之后所有人脸生成 demo(thispersondoesnotexist 那批)默认用的是 StyleGAN2 而不是初代 StyleGAN——水滴消失了
  • 为什么”潜空间编辑”(性别、年龄、表情滑块)在 StyleGAN2 上突然好用——path-length regularization 让潜空间方向变得线性可解释
  • 为什么扩散模型出现之前,GAN 的最高峰是 StyleGAN2/3 而不是 BigGAN——前者在窄分布(人脸、车、卧室)上的 FID 至今难超
  • 为什么 AdaIN 这个 2017 年的”风格迁移神器”在 2020 年被抛弃——它的 per-instance 归一化会引入信息泄漏

核心要点

StyleGAN2 的修复可以拆成 三件事

  1. 诊断”水滴瑕疵”根因:StyleGAN 用 AdaIN(Adaptive Instance Normalization)注入风格——先把每张特征图减均值除标准差再乘风格 scale。论文发现 G 学会了一个偏门技巧:在某个特征图里做出一个超大值,让 instance normalization 的标准差被它支配,从而在归一化后”偷偷传递”信号。这个超大值在最终图像上就是那粒水滴。

  2. 权重解调(weight demodulation)替换 AdaIN:不再对特征图做 per-instance 归一化,改成把”风格 scale”直接乘进卷积权重,再对卷积权重整体做一次”理论上的输出方差归一”——纯数学操作,不依赖单张图的统计量。水滴消失,FFHQ FID 从 4.40 降到 4.34。

  3. path-length regularization(路径长度正则):希望潜空间 W 里走相同长度的步,输出图像变化也是同样长度。论文加一项 loss:让 G 对 W 的雅可比矩阵的奇异值尽量保持常数。效果:潜空间编辑(如年龄滑块)变线性、训练更稳、FID 再降。

附带的工程优化:

  • lazy regularization:正则项每 16 步算一次,几乎不掉指标,省 1/3 计算
  • 去掉 progressive growing:改用 skip connection 的 G + residual D,避免渐进训练带来的”特征定位偏好”
  • 大分辨率训练用 mixed precision:FP16 让 1024×1024 训练显存可控

实践案例

案例 1:AdaIN 到底有什么问题

AdaIN 的公式(伪代码):

def adain(x, style_scale, style_bias):
# x: [B, C, H, W]
mean = x.mean(dim=[2, 3], keepdim=True)
std = x.std(dim=[2, 3], keepdim=True)
x_norm = (x - mean) / (std + 1e-8)
return x_norm * style_scale + style_bias

问题:std单张图当前的标准差。如果 G 在某个位置故意放一个 1000 的尖峰,那 std 会被这个尖峰拉很大,归一化后整张图都被”压扁”,于是 G 就利用了”我能控制 std”这件事来跨层传递信号。论文反向追踪发现这粒尖峰在最终图像就是那个固定位置的水滴。

案例 2:weight demodulation 怎么消掉水滴

新的注入方式(伪代码):

def modulated_conv(x, weight, style_scale):
# weight: [out_c, in_c, k, k]
# style_scale: [B, in_c]
w = weight.unsqueeze(0) * style_scale.view(B, 1, in_c, 1, 1) # 调制
# 解调:让每个输出通道的方差归一
sigma = (w ** 2).sum(dim=[2, 3, 4], keepdim=True).sqrt() + 1e-8
w = w / sigma
return F.conv2d(x, w) # 实际实现用 grouped conv 让不同样本不同权重

关键:sigma 是从权重算出来的常数(不依赖 x),所以 G 没法靠”放大单点”来劫持归一化——水滴失去存在的理由。

案例 3:path-length regularization 让潜空间编辑变可控

公式(简化):

def path_length_reg(G, w):
# 给 w 加微小扰动 y,看图像变化
y = torch.randn_like(G(w))
grad = autograd.grad((G(w) * y).sum(), w)[0]
path_length = grad.norm() # 雅可比向量积长度
return (path_length - moving_avg) ** 2

含义:让”在 W 里走 1 步”对应”图像里也走 ~固定长度 1 步”。训练完后做”年龄滑块”:在 W 里沿”年龄方向”走 5 步,图像看起来年龄递增 5 个等距档位,不会前 4 步几乎不变后 1 步突然变老。这是后续 InterFaceGAN、StyleCLIP 等编辑工作能 work 的基础。

踩过的坑

  1. 去掉 progressive growing 不是无痛:原 StyleGAN 渐进加层让低频先收敛、高频后续上。直接换成 skip-G + residual-D 后,训练初期 FID 会比 StyleGAN 难看,要训到 5M 张图后才追上。

  2. path-length regularization 系数难调:太大会让 G 倾向于”输出整张图都一样”(路径长度真的常数了,但内容塌缩),太小没效果。论文用 lazy reg 每 16 步一次配 weight=2 是经验值。

  3. weight demodulation 不能去 BatchNorm:论文发现 G 的某些 1×1 卷积仍要保留某种归一化,否则训练初期梯度爆炸。

  4. 复现成本仍然高:FFHQ 1024×1024 训一次要 8 块 V100 跑 9 天,社区版(rosinality/stylegan2-pytorch)单 GPU 跑 256×256 要一周以上。

  5. 数据集要”窄分布”:FFHQ 都是中间居中、光照统一的人脸;同一个 StyleGAN2 直接训 ImageNet 这种 1000 类杂图,FID 反而很差。论文也没尝试做 ImageNet——这是 BigGAN 路线的地盘。

适用 vs 不适用场景

适用

  • 单一窄分布的高分辨率图像生成(人脸、汽车、卧室、马、教堂)
  • 需要可解释潜空间编辑(人脸属性滑块、风格混合)
  • 预训练 + 反演(GAN inversion)做图像编辑工具

不适用

  • 大规模多类别(ImageNet 1000 类)→ 用 BigGAN 或扩散模型
  • 文本到图像 → 没有语言条件,走 Stable Diffusion 这条线
  • 训练资源紧张 → 1024×1024 至少 8×V100 一周
  • 想要 SOTA 通用图像质量 → 2022 年起扩散模型已全面反超

历史小故事(可跳过)

  • 2017 年:Huang & Belongie 提出 AdaIN,做风格迁移神器
  • 2018 年:NVIDIA Karras 团队的 ProgressiveGAN 把 GAN 推到 1024×1024 人脸
  • 2019 年初:同团队 StyleGAN(CVPR 2019)把 AdaIN 引入 G,让”风格”能逐分辨率注入,FFHQ 惊艳,但所有样本都有水滴瑕疵
  • 2019 年 12 月:StyleGAN2 论文挂 arXiv,CVPR 2020 接收
  • 2021 年:StyleGAN3 修了”texture sticking”(图像旋转时纹理粘着),这条线告一段落
  • 2022 之后:扩散模型(DALL·E 2、Stable Diffusion)在通用生成接管,StyleGAN 系列退守”人脸 / 单类别 SOTA”位置

学到什么

  1. 诊断比创新更重要:StyleGAN2 最大的贡献是诊断出”水滴是 AdaIN 的副作用”——这一步靠的是反向追踪激活值最大点,不是新算法
  2. per-instance 统计量是漏点:任何依赖单张图统计量的归一化(IN / LN 在某些位置)都给 G 一个”劫持归一化器”的机会,工程上要警惕
  3. 潜空间几何也要正则:不仅 loss 要管输出像不像真,还要管”潜空间走一步对应输出走多远”——这是后续编辑可控的前提
  4. Lazy regularization 是免费午餐:很多正则项每步算和每 16 步算结果差不多,训练流程里值得检查

一句话记忆

StyleGAN 的水滴瑕疵根源是 AdaIN 的 per-instance 标准差被 G 偷偷利用——把它换成”理论方差归一的权重解调”瑕疵就消失;再加一项让潜空间 W 走相同长度对应图像走相同长度的路径长度正则,编辑就线性了。

延伸阅读

关联

  • biggan-2018 —— 同期另一条 GAN 路线(ImageNet 多类别 vs StyleGAN2 单类别窄分布)
  • stable-diffusion —— 2022 年后在通用生成上反超 GAN 的范式
  • attention —— StyleGAN3 后续引入更强的位置编码思想,与 attention 的等变性研究相关

反向链接

  • attention —— Attention Is All You Need
  • biggan-2018 —— BigGAN — 把 GAN 暴力放大到 ImageNet 512×512