问题阐述
最近在修改一份code,需要进行如下迁移:
- python2.7 -> python3
- pytorch v0.3.1 -> pytorch v1.0.1
但是performance相对出现了显著下滑。一瞥过去,便容易认为是pytorch的版本切换导致的performance下滑。但是经过实验,我发现在python2.7下用pytorch v1.0.1训练,仍然能取得promising performance。也就是说这个问题变成了:保持pytorch同一版本,仅更换python的版本,就会导致performance出现较大的变化。
然后我仔细分析了model部分,发现是由weight_norm引起的变化,语句如下:
weight_norm(nn.Linear(hid_dim[0], hid_dim[1]), dim=None)
那么把weight_norm注释掉就可以了吧。直接调用nn.Linear?如下
nn.Linear(hid_dim[0], hid_dim[1]
的确可以,因为performance并不十分依赖weight_norm,所以并没有太大下滑。不过继续深入分析,我发现问题并不那么简单。
首先了解下weight_norm,这是官网的doc:就是对输入的module进行weight normalization,公式如下,其中v为这个类的weight_v和weight_g是Weight_norm类的属性
当调用weight_norm()函数时,会创建Weight_norm类,并初始化weight_g、weight_v两个属性,其中weight_v就是直接从nn.Linear.weight“复制”过来的权重,过程如下。这里附上官网的源码链接
# add g and v as new parameters and express w as g/||v|| * v
module.register_parameter(name + '_g', Parameter(norm_except_dim(weight, 2, dim).data))
module.register_parameter(name + '_v', Parameter(weight.data))
这个问题的示例如下:
这里运行在不同的python环境,但同一版本pytorch,且我固定了seed,也就是说下面的所有初始化参数应该一致
- 当初始化linear的维度较低时,weight_g一致:
# python 3.7
weight_norm(nn.Linear(20, 20), dim=None).weight_g
"Parameter containing: tensor(2.6137, requires_grad=True)"
# python 2.7
weight_norm(nn.Linear(20, 20), dim=None).weight_g
"Parameter containing: tensor(2.6137, requires_grad=True)"
- 当初始化linear的维度较高时,weight_g不一致:
# python 3.7
weight_norm(nn.Linear(2048, 2048), dim=None).weight_g
"tensor(295.5971, requires_grad=True)"
# python 2.7
weight_norm(nn.Linear(2048, 2048), dim=None).weight_g
"tensor(26.1274, requires_grad=True)"
pytorch forum下的解答
这是我在pytorch forum下的问题链接,大家感兴趣的可以关注下,有细致的解答,我会在第一时间进行更新:https://discuss.pytorch.org/t/is-weight-norm-different-in-different-python-versions/71108
更新:感谢来自ptrblck的解答,我也测试了一下,weight_norm这个在pytorch v1.4版本下是不存在这个问题的,其在python2.7和3.7下的运行结果完全一致,不受维度影响。