pyrotch 网络权重参数不更新,损失函数不下降,梯度为None

4,311 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情

因为接手的课题要用到GAN网络,我就参考GAIN的损失函数,对网络结构做了个改写。 因为GAIN源码是tensorflow写的。但是我平时的习惯就是pytorch,想到以后也会常用他的主体结构,就想用pytorch重写下GAIN网络。以为很简单的事,结果出事了。

bug描述:

具体来说就是,机器不学习了。损失函数不是陷入了局部最优点那种降不下去,是从一开始就没降下去。

排查原因

  • 首先我想到的原因是学习率过小的问题。 毕竟他的两个损失函数虽然降的少,但是至少都在在波动啊。

尝试调了调学习率,卵用没有。继续排查。

  • 我想到这个波动可能是是因为随机种子没指定。根本原因可能是参数没更新。

因为我试了试输出验证集的RMSE。从我每次输出的RMSE也可以看到。网络参数可能根本没更新。

  • 输出optimizer优化器的网络参数
print(optimizer.param_groups[0])

比较了下,果然是参数没有更新。

参数不更新的解决方案参考

参数不更新,不外乎几个解决方法哈

  1. 用torch.autograd.Variable,把输入转换为Variable。注意加参数, requires_grad=True
  2. 计算出loss后,loss = loss.requires_grad_()。这个方法跟第一种效果一样,都是给他梯度 但是,经过自查,我的模型没有这样的问题。这个时候,我输出了下梯度。
  • 我觉得问题应该出在梯度上,毕竟我对它很不熟悉。
print([x.grad for x in optimizer.param_groups[0]['params']])

梯度如果是None或者0,说明梯度没有传到该变量,顺着代码往下一直输出变量的梯度,直到梯度出现为止,然后检查为啥梯度消失了。
输出梯度后, 检查梯度乘上学习率是否过小, 比如梯度为5e-2,学习率为1e-4,而变量的值只保留五位小数,那么此时由于学习率过小使得更新被变量忽略,需要把学习率调高。

以上是我查到的参考资料,但是并没有告诉我梯度为什么为NONE,还需要继续探究。

原因探究

知道我翻到一个老哥说的奇怪bug

他的问题是模型构建了搞了两次,然后梯度没了。

很显然,我可能也存在这样的问题。

解决问题

def transform(x):
    return Variable(x.to(torch.float32), requires_grad=True).cuda()

我因为要用到GPU加速,并且有些数据的随机生成偷懒用的比较顺手的numpy所以数据就需要多次数据转换,为此我专门搞了个transform方法解决这个问题。

可能,每次转换把这个变量从GPU里搞到CPU里再搞回来,它的梯度都会出现一些我不知道的变化。

一开始我的代码是这样的。

后来我保证了每次运算的变量都是GPU里的,然后就解决问题了。

个人总结

之前写pytorch都是个人学习的小案例,没有用到GPU加速,对这些变化不太熟练。结果就踩了坑了,希望能给遇到这个问题的入门炼丹师提供一些解决bug的思路。