记录一次马虎导致的BUG
事情起因:
最新在跑项目的代码,一切都好好的,直到我突发奇想加了个新model之后,一切诡异了起来。。。
代码逻辑是每训练一轮会在开发集上测三次,然后log打印每次测出的loss以及PRF指标,在改了model之后,在每一次打印的log中所有的数值都丝毫没有变化。。。
出现问题:
训练时以及开发集上loss丝毫不变
这说明了虽然模型每一轮都在训练,但是模型中待学习的参数却丝毫没有得到更新。
调试过程:
print(probs.grad)
print(targets.grad)
print("probs:{}".format(probs.requires_grad))
print("targets:{}".format(targets.requires_grad))
loss = criterion(probs, targets)
print("loss:{}".format(loss.requires_grad))
训练时:
None
None
probs:True
targets:False
loss:True
测试时:
None
None
probs:False
targets:False
loss:False
一切正常,其中.grad只有在loss.backward()之后才会计算自己的梯度,并在此后累计梯度,所以默认输出None是正常的
因此可以排除问题出在模型内部的可能性
现在来排查函数之外,首先怀疑优化器函数写的不对,几次尝试后,发现问题依然不在这里。。。
突然发现一处代码,之前由于模型较大出现out of memory,所以曾经把参数放到CPU去优化,定义获取参数代码如下:
if args.optimize_on_cpu:
param_optimizer = [(n, param.clone().detach().to('cpu').requires_grad_()) for n, param in net.named_parameters()]
else:
param_optimizer = net.named_parameters()
这样的话在使用优化器更新参数,即optimizer.step(),时,要进行以下三个步骤:
1)对于模型的每一个参数,若该参数有梯度,则把该参数的梯度的值(para_model.grad.data)copy给对应的优化器的参数(若对应的优化器参数的梯度为None则为其赋予梯度);若模型某一参数的梯度为None,则给对应的优化器的参数的grad也复制为None;
2)梯度回传后,进行模型参数的更新;
3)将优化后的优化器的各个参数值copy到模型的各个参数上。
if args.optimize_on_cpu:
is_nan = set_optimizer_params_grad(param_optimizer, net.named_parameters(), test_nan=True)
optimizer.step()
copy_optimizer_params_to_model(net.named_parameters(), param_optimizer)
else:
optimizer.step()