WGAN-GP需梯度惩罚而非权重裁剪,因后者易致梯度消失或模式崩溃;GP通过在真实与生成样本插值点上强制判别器梯度范数≈1来稳定满足Lipschitz约束。

为什么WGAN-GP需要梯度惩罚而不是权重裁剪
Wasserstein GAN(WGAN)原本用权重裁剪来满足Lipschitz约束,但容易导致梯度消失或模式崩溃。梯度惩罚(Gradient Penalty, GP)是更稳定的替代方案:它在真实样本和生成样本的随机插值点上,强制判别器梯度范数接近1。PyTorch里不提供现成封装,必须手动计算 torch.autograd.grad 并构造惩罚项。
如何正确实现gradient penalty的计算逻辑
关键不是对所有batch统一算梯度,而是对每个插值样本单独求梯度再平均。常见错误是直接对整个batch的loss调用 grad,导致维度错乱或标量求导失败。
- 先用
torch.rand生成与batch同尺寸的插值系数alpha,形状为(batch_size, 1, 1, 1)(适配图像数据) - 构造插值样本:
interpolates = alpha * real_img + (1 - alpha) * fake_img - 用
discriminator(interpolates)得到logits,再用torch.autograd.grad对输入求梯度:参数create_graph=True必须设为True,否则二阶导无法回传 - 梯度张量展平后计算L2范数:
grad_norm = torch.sqrt(torch.sum(grad**2, dim=[1, 2, 3])),再算((grad_norm - 1) ** 2).mean()
WGAN-GP训练中容易漏掉的三个细节
这些细节不报错,但会让GP失效或训练发散:
-
discriminator的最后一层不能有sigmoid或softmax——WGAN要求输出原始分数(critic score) - 生成器更新时,
discriminator的参数必须requires_grad=False;但在计算GP时,discriminator必须全程train()模式且梯度开启 - GP系数(通常设为10)太小起不到约束作用,太大则主导loss、压制真实梯度信号;建议从10开始,观察
grad_norm的均值是否稳定在0.8~1.2之间
PyTorch里避免CUDA内存爆炸的写法
插值样本和梯度计算都在GPU上进行,但 torch.autograd.grad 默认会保留计算图。若在循环中反复调用且未清空中间变量,显存会线性增长。
立即学习“Python免费学习笔记(深入)”;
- 用
with torch.no_grad():包裹插值构造前的real/fake采样,减少无用图节点 - 计算完GP后,显式删除中间变量:
del interpolates, grad, grad_norm - 或者更稳妥地,在GP计算块内使用
torch.cuda.empty_cache()(仅调试阶段)
真正难的不是写出公式,而是让梯度惩罚在每步都精确作用于判别器输入空间——稍有偏差,Lipschitz约束就形同虚设。


















