我在尝试使用nn.ModuleList()进行多任务学习,但当它们之前被训练过时,所有列表元素(即任务)的权重都会被调整。以下代码(基于这个笔记本)创建了一个名为MTL
的神经网络对象。
...
神经网络的结构如下:
...
权重的初始值是(你的会有所不同):
...
输出:
...
以下代码训练了神经网络,并在每个epoch后打印权重。第一个epoch将训练共享层和nn.ModuleList()的第一个元素(即任务1)。第二个epoch将训练共享层和nn.ModuleList()的第二个元素(即任务2)。
...
输出:
...
在第一个epoch之后,任务1的权重被调整,但任务2的权重没有调整(符合预期),但在第二个epoch之后,两个任务的权重都被调整了。这不应该发生。
你也可以看到,当你在整个小批量中打印权重时(只需取消注释print语句),即使所有层都被冻结且没有进行计算,权重总是会为第一个任务调整。
除了optimizer.zero_grad()
之外,还有什么其他缓存我需要清除吗?
回答:
如果你在训练过程中监控MTL.scoring_list[0][6].weight.grad
和MTL.scoring_list[1][6].weight.grad
,你会注意到,在第一个epoch中,MTL.scoring_list[1][6].weight.grad
是None,而在第二个epoch中,MTL.scoring_list[0][6].weight.grad
是一个零张量。
查看各种优化器的.step()
源代码,似乎它们并不检查.requires_grad
。它们只检查.grad
是否为None
。所以即使.grad
是一个零张量,optimizer.step
仍然会执行其操作。这是否会影响冻结的权重,取决于优化器执行的具体计算。
作为一个快速修复,你可以在param.requires_grad = False
之后添加param.grad = None
,这样优化器就会完全忽略这些参数。这似乎解决了问题。但你可能仍然需要考虑这对优化器在未来epoch的计算有何影响。