网络梯度为None、参数不更新解决思路(又名“魔改代码的报应”)

网络梯度为None,解决报错RuntimeError: Expected to have finished reduction in the prior iteration before starting a new one.

  • 报错提示
  • 问题来源
  • 排查
  • 参考博客
  • 我的解决思路

报错提示

RuntimeError: Expected to have finished reduction in the prior iteration before starting a new one. This error indicates that your module has parameters that were not used in producing loss. You can enable unused parameter detection by (1) passing the keyword argument find_unused_parameters=True to torch.nn.parallel.DistributedDataParallel; (2) making sure all forward function outputs participate in calculating loss. If you already have done the above two steps, then the distributed data parallel module wasn’t able to locate the output tensors in the return value of your module’s forward function. Please include the loss function and the structure of the return value of forward of your module when reporting this issue (e.g. list, dict, iterable).

问题来源

在原网络中新加了一个特征提取的模块,单卡不报错,双卡报上面的错

排查

出现这个错最本质的原因是有一部分网络的参数无法正常反向传播。
首先通过在loss.backward()后添加下面代码,找出是哪一处的参数梯度为None:

for name, param in model.named_parameters():
	if param.grad is None:
		print(name, param.grad_fn)

然后发现确实是我加的那一部分的模块的参数有问题,梯度都是None

参考博客

下面的博客给出了一些参考
参考博客1
参考博客2

我的解决思路

由于我加的这一部分是特征提取,不需要在这一步计算loss,而原来后面那一部分的网络的反向传播是没问题的,所以问题应该就是出在我写的这块。

排除了一系列loss没算、初始化没删、requires_grad没开等等一系列问题后,
我认为不能反向传播的原因可能是我把特征提取这一部分的输出后面加了一系列复杂的操作(涉及到一些复杂的维度变换),
然后才传到下一个网络中去,导致有些操作无法正确的追溯(比如for循环、scatter操作以及一些其他复杂的操作函数)。

接着我把所有的for循环删除,把直接计算的池化部分改为通过AvgPool2d()实现,就可以正常反向传播了!

所以出现了这个问题,且你对代码做了魔改的基础上,可以检查一下自己有没有在输出的特征向量上做一些复杂的操作,尽量把这些操作简化,同时也要注意尽量不要初始化一个新的tensor(这种中间变量的梯度也是没有的),没准就能行得通!

大半夜终于解决了困扰了好几天的bug,共勉!!!

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年8月23日
下一篇 2023年8月23日

相关推荐