背景
我在训练一个模型时,发现每个epoch的loss都相等,而且在测试时模型效果非常差。
一、问题排查
每个epoch的loss都相等,说明模型参数没有更新,模型没学到应有的知识。
于是我试着打印每个epoch中模型的可训练参数,发现结果正如之前所料,参数没有更新,而且参数的grad_value等于None。
发生该问题的原因就是反向传播被阻断了。于是从loss的计算代码开始,一步步回溯整个计算图,查找可能会阻断反向传播的操作。
二、问题解决
在回溯中我发现,有一步操作是使用模型的输出output与一个列表A中的每个元素做相似性计算,然后构成了新列表A_similarity,接着使用这个新列表计算loss。这一步正是造成反向传播被阻断的原因。
因为A_similarity 是一个列表,列表中的元素是单独的张量,彼此之间没有直接的计算图连接,会导致计算图断裂。即使使用torch.tensor将A_similarity转换成tensor变量,也会丢失output原来的梯度。
解决办法就是使用torch.stack()对A_similarity列表中的张量进行一个堆叠,堆叠后的张量元素之间在计算图上就产生了联系,同时会保留原来的梯度,进而可以使得反向传播正常进行(我的猜测)。
注意:使用torch.stack()后,原变量的维度会发生变化。假设A_similarity列表中有20个元素,那么torch.stack(A_similarity)的形状为torch.Size([20, 1])