最近在跟着教程用PyTorch搭一个简单的DCGAN,想在自拍数据集上生成点真人脸的假图。结果每次训练到差不多200个epoch左右,判别器loss就突然飙到20多,生成器loss直接掉到0附近,然后整个模型就废掉了,出来的全是噪点。我确认过数据归一化是[-1,1],学习率设的是0.0002,用的是Adam优化器。有人说是梯度爆炸或者模式崩塌,但我不知道怎么判断具体是哪种,也不知道该调什么参数。有没有大佬给个排查思路?或者有什么靠谱的GAN训练trick可以分享?先谢过。
用PyTorch写GAN训练到一半loss爆了,有人遇到过类似情况吗?
全部回复
共 163 条试试把判别器加个梯度惩罚,或者把学习率降到1e-4,我调这个参数治好了类似问题。
这种情况我碰到过好几回,大概率是判别器学得太快把生成器压死了,属于典型的模式崩塌前兆。可以试试把判别器的学习率调低到生成器的三分之一,或者给判别器加一些标签平滑,让它的loss不要那么自信。另外检查一下有没有用BatchNorm,DCGAN里生成器和判别器对BN的用法挺讲究的,搞反了也容易炸。
这个现象太典型了,基本就是模式崩塌+判别器过拟合。建议你试一下给判别器加Dropout或者Label Smoothing,能有效防止它学得太快。另外可以把生成器的学习率调低到0.0001,或者每几个epoch给判别器做一次梯度裁剪,限制一下更新幅度。我之前遇到过类似情况,还把判别器的更新次数改成生成器的一半,也就是每更新一次生成器才更新一次判别器,这样平衡一点。
说到这个我可太有同感了,之前跑DCGAN也卡在差不多的位置,差不多150到200轮的时候loss直接起飞。你这情况其实两个特征都有:判别器loss突然暴涨、生成器loss归零,说明判别器太强把生成器彻底碾压了,属于典型的训练不平衡。建议先试试调低判别器的学习率,比如把生成器保持0.0002,判别器降到0.0001甚至更低,或者每隔几个batch只更新一次判别器。另外可以检查下梯度更新时有没有做梯度裁剪,我当初加了一个max_norm=1.0的clip就稳了很多。还有个小trick是给判别器加一点标签平滑,把真实标签从1改成0.9,虚假标签从0改成0.1,这样能防止判别器过于自信。你用的自拍数据集如果图像尺寸不一致或者有模糊图,也可能导致模型在某个epoch突然学到噪声特征,建议先跑个简单的landscape数据集验证下代码本身有没有问题。最后想问下,你的自拍数据集大概多少张图?太小的话也容易崩。
这情况太经典了,我第二次跑DCGAN也遇到过一模一样的崩法。你可以先看下判别器是不是学得太快,把生成器按在地上摩擦了,一个简单办法是把判别器学习率调低或者试试用SGD优化生成器。另外检查下有没有用BatchNorm,有时候BN在batch size小的时候会让训练特别不稳定。我之前是把生成器的loss换成feature matching才稳住的,你可以搜下这个trick。
我之前用WGAN-GP之后基本没再炸过,说实话DCGAN对超参太敏感了。你那个现象更像是判别器收敛太快导致梯度传不回去,可以试试给判别器加个谱归一化,或者减少判别器每轮的更新次数。还有,如果自拍数据集没做对齐和裁剪,背景干扰也会让模型容易崩溃,这个也挺常见的。
遇到过,后来发现是我数据加载那里忘了打乱顺序,导致每个batch都是同一批人像,模型直接记住分布了。你可以先看看loss崩之前判别器的输出是不是一直在0附近,如果是的话就是它太强了,把生成器的梯度彻底压没了。建议把Adam的betas改成(0.5, 0.999),然后每训练一次判别器就训练两次生成器,平衡一下。
这情况太典型了,我赌五毛不是梯度爆炸,就是判别器太强直接把生成器按在地上摩擦。你那个loss曲线明显是D收敛得太快,G的梯度消失,跟模式崩塌的症状不完全一样——崩塌一般是loss来回震荡然后G输出同一张图,你这个是直接崩成噪点,更像D把真假分得太彻底了。先别急着调学习率,试试把D的更新频率降下来,比如每训练两次G再训一次D,或者给D加个label smoothing,把真标签从1改成0.9,假标签从0改成0.1,能有效延缓D过拟合。另外检查下你的batch size,如果太小比如16以下,D的梯度会特别不稳,建议提到64。还有一招是给G和D都加谱归一化,虽然会慢一点但稳定性提升明显。我之前也遇到过类似情况,最后发现是D的最后一层没用sigmoid,导致BCEWithLogitsLoss输入重复套了激活,你确认下是不是这个低级错误。如果还不行,就把学习率降到0.0001,同时给D用RMSprop,别用Adam,有时候Adam在GAN里反而太激进。最后推荐你看下GAN的三大trick合集,就是That's the trick那篇博客,中文翻译版也好找,里面讲的初始化权重和特征匹配方法能救急。
我之前也遇到过一模一样的情况,基本可以锁定是模式崩塌。你先试试把判别器的学习率调低点,比如0.00005,然后给生成器加个label smoothing,让真实标签从1变成0.9,这招对我挺管用的。另外建议你把BCE loss换成WGAN-GP那种梯度惩罚的写法,稳定性会好很多,虽然代码稍微复杂点但值得折腾一次。还有个小trick,每次更新判别器时多跑几步,生成器少跑几步,比例可以调到5:1,我当时就是这么救回来的。要是还不行就检查下batchnorm是不是在生成器里加多了,有时候反而会加剧震荡。
这情况八成是判别器收敛太快把生成器压死了,试试调低它的学习率或者加label smoothing。
我之前训DCGAN也踩过一模一样的坑,200轮准时炸,后来发现是判别器收敛太快,把生成器梯度直接压没了。你可以先试试把判别器学习率降到0.00005,或者给生成器加个标签平滑,真标签从1改成0.9,假标签从0改成0.1,这招对稳定loss挺管用的。另外如果你的自拍数据集比较小,可以试试每训练一次生成器就训练两次判别器,或者反过来,让两边别一边倒。还有个小技巧是监控一下判别器输出均值,如果一直往0.5靠就是模式崩塌,如果瞬间冲到0.9以上大概率是梯度爆炸,这时候可以试试梯度裁剪。
我遇到过一模一样的,DCGAN训到后期discriminator loss突然起飞基本就是梯度爆炸,你可以先试试把判别器里的卷积层都加上spectral norm,这个对稳定训练特别管用。另外建议把生成器和判别器的学习率分开设,生成器用0.0002,判别器降到0.00005,我这么调之后就没再崩过。你那个模式崩塌的判断其实也沾点边,但先别急着改网络结构,把BatchNorm换成InstanceNorm也有效果,自拍数据集本身多样性不够的话很容易触发这些问题的。
我之前跑DCGAN也遇到过一模一样的情况,200轮附近D的loss突然爆炸,G直接摆烂。你可以先试着把D的训练频率降下来,比如每训练两次G再训一次D,或者给D加个标签平滑,真实标签从1改成0.9,能稳不少。另外检查下D的最后一层是不是用了Sigmoid,配合BCEWithLogitsLoss有时候数值会飘,换成BCELoss或者把D输出改成不带激活的logits试试。如果还炸,就把学习率调到0.0001甚至5e-5,Adam的beta1建议从0.9改成0.5——DCGAN原论文里就是这么设的,对稳定性影响挺大。
这个现象太经典了,我赌五毛钱不是单纯梯度爆炸,而是判别器收敛太快把生成器按在地上摩擦。你想想,200个epoch左右,判别器loss飙到20多,这基本就是它把真实样本和假样本彻底分开了,梯度回传对生成器来说全是死路,生成器loss掉到0附近反而说明它已经放弃治疗了。我之前跑CelebA也遇到过一模一样的情况,后来发现是标签平滑没做,把真实标签从1换成0.9,假标签从0换成0.1,判别器就不会那么自信了。另外你可以试试给生成器加一点特征匹配损失,就是拿中间层的特征做MSE,比只用最终输出稳定得多。还有个土办法,把判别器的学习率调成生成器的三分之一,比如生成器0.0002,判别器0.00005,这样能强制它慢半拍。还有个容易忽略的点,你确认一下BN层是不是用的batch size太小?我当初batch size设16,结果BN统计量抖动得厉害,换成64之后明显稳了。最后实在不行就上谱归一化,虽然慢点但真的治这种突然暴毙的毛病。
这情况八成是D收敛太快把G压死了,试试把D的学习率调低或者每训练几次D再训一次G。
之前我也炸过,把batch size调大点或者加个标签平滑立马稳很多。
我之前做类似任务也踩过这个坑,尤其200轮这个点,很典型的判别器学太快了。你可以试试把判别器学习率调低到0.0001,或者给生成器加一点标签平滑,真实标签从1换成0.9,能缓解不少。另外强烈建议每次迭代里判别器更新次数减半,让生成器先喘口气,我这么改之后稳定多了。还有个小技巧,就是盯着判别器输出值看,别只看loss,如果输出值一直逼近0或1,基本就是判别器太强了。
我之前跑DCGAN也碰到过一模一样的情况,200轮左右D的loss突然起飞,八成是判别器学得太快把生成器碾压死了。你可以试试把D的更新频率降下来,比如每训练两次G再训一次D,同时把D的learning rate调小到1e-4甚至5e-5。另外检查下有没有用BatchNorm,如果用了可以换成InstanceNorm试试,自拍数据集分布太窄的话这个挺管用的。模式崩塌的话会看到生成图多样性变差,但你是直接变噪点,更像梯度爆炸,可以看看判别器最后一层是不是没加激活函数。
遇到过,典型的模式崩塌,先把学习率降到0.0001再加个梯度惩罚试试。
这个现象太经典了,基本就是D收敛太快把G压死了,典型的不平衡。你先别急着调学习率,把判别器最后几层的weight clipping或gradient penalty加上试试,很多这种爆loss都是因为D的梯度太猛。另外可以试试把D的训练频率降下来,比如每训练5次G再训1次D,或者给D加个dropout,让它别那么“聪明”。我之前也遇到过类似情况,后来发现是batch size太大导致D太稳定,调小一半反而好了。你那个自拍数据集如果背景太单一,也容易让D走捷径,多加点随机裁剪或旋转试试。
我之前也踩过这个坑,后来发现多半是判别器收敛太快,把生成器压得太死导致的。你可以试试把判别器的学习率调低一点,或者用label smoothing,把真实标签从1换成0.9,能缓解不少。另外检查下有没有用BatchNorm,DCGAN里如果生成器和判别器的BN层设置不对,也特别容易炸。我那时候还加了梯度惩罚,虽然慢了点但稳定多了,你可以先用小批量试下。
这个现象太经典了,基本就是D收敛太快把G彻底压死了,属于典型的训练失衡。你可以试试把D的学习率调低一点,或者给D的loss加个标签平滑,比如正样本目标从1改成0.9,能缓解不少。另外检查下D的最后一层是不是用了Sigmoid,配合BCELoss的话数值容易飘,换成BCEWithLogitsLoss会更稳。我上次遇到类似情况是把D改成每训练两次才更新一次,G每步都更新,节奏就正常了。
我遇到过一模一样的,200轮左右爆loss基本就是判别器太强了,生成器梯度直接失效。你可以先试试把判别器学习率降到0.00005,或者每训练一次判别器就训练三次生成器,平衡一下两者速度。另外查一下有没有用BatchNorm,DCGAN里用BN但注意别在生成器输出层加,不然容易震荡。还有个小技巧是给判别器加一点标签平滑,把真实标签从1换成0.9,能有效防止它过度自信。要是还不行就降低batch size试试,我上次从64降到32就稳住了。