GAN训练易崩溃的根本原因是JS散度在分布不重叠时梯度消失,导致生成器无法更新;同时判别器过强或过弱均使生成器缺乏有效梯度信号,引发模式崩塌或训练震荡。

为什么GAN训练容易崩溃?
PyTorch里跑nn.BCELoss配原始GAN目标函数,几乎必然遇到梯度消失或模式崩塌。根本原因不是代码写错,而是判别器(D)太强时,生成器(G)收到的梯度接近零;D太弱时,G又学不到有效信号。这不是超参调得不够细的问题,是目标函数本身在JS散度非饱和区缺乏平滑梯度。
实操建议:
- 永远不用原始GAN的log(1-D(G(z)))作为G的损失——改用log(D(G(z)))(即“非饱和损失”)
- 判别器每步更新后,用torch.nn.utils.clip_grad_norm_限制其梯度范数,比如设max_norm=1.0
- 避免BatchNorm在D最后一层和G第一层同时使用——D末层BatchNorm会放大噪声,G首层则易导致输出分布偏移
Wasserstein GAN(WGAN)在PyTorch里怎么落地?
WGAN的核心是把D换成“批评家”(critic),并强制其满足Lipschitz约束。PyTorch里最稳妥的做法不是靠权重裁剪(weight_cliping),而是用梯度惩罚(Gradient Penalty)。
关键步骤:
- D的输出层**必须去掉Sigmoid**,直接输出标量分数
- 在D的loss中加入梯度惩罚项:gp = ((grad_norm - 1) ** 2).mean(),其中grad_norm是对插值样本求D输出对输入的梯度范数
- 总D loss为:loss_d = -d_real.mean() + d_fake.mean() + 10 * gp(系数10是常用λ)
- G loss就是-d_fake.mean(),不加任何sigmoid或log变换
Batch size和优化器选择对稳定性影响有多大?
小batch(如16或32)会让D的梯度估计方差大,尤其在高分辨率图像上,极易引发震荡。Adam优化器默认的betas=(0.9, 0.999)对GAN也不友好——0.9的动量会累积D的剧烈波动,传给G。
实操建议:
- Batch size至少设为64,128更稳;显存不够就用梯度累计(accumulate_grad_batches)
- D和G**必须用不同的Adam实例**,且D用betas=(0.5, 0.999),G用betas=(0.0, 0.999)(即关掉一阶动量)
- 学习率别贪大:lr=2e-4是安全起点,调高前先确认D的loss在-1.5 ~ 0.5之间小幅摆动
如何快速诊断当前训练是否已失稳? 不能只看loss曲线。真正有用的信号藏在中间输出里:
检查点:
- 打印D对真实样本的输出均值(d_real.mean().item()):持续>0.8且不再下降,说明D过强
- 检查G生成样本的像素值范围:如果长期卡在[0, 1]之外(未做clamp或tanh后处理),说明G梯度爆炸
- 用torch.autograd.grad手动算一次D对fake样本的梯度,看grad.norm()是否>100——这是梯度爆炸的明确标志
- 每100步保存一张生成图,肉眼比对:连续3次都出现大面积灰斑或条纹,基本可判定模式崩塌
WGAN-GP的梯度惩罚项系数、critic更新步数(常设n_critic=5)、以及生成器输出激活函数(tanh还是scaled sigmoid)三者之间存在隐性耦合,调其中一个就得重新观察另外两个的表现。这点容易被忽略。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










