新增其他Parameter后nn.init.normal_初始化权重结果异常变化
问题根因
这个现象和已初始化参数被意外修改无关,本质是两个认知偏差导致的:
- 代码执行顺序和你预想的不一致:你注释掉的四个
*_Q线性层,写在四个*_h序列定义之后、自定义权重初始化的for循环之前。取消注释后,这四个Linear会在你给*_h做自定义初始化之前就完成实例化。 - PyTorch全局随机数生成器是全局共享状态:所有随机相关操作——包括新层实例化时自动执行的默认Kaiming初始化、你手动调用的
nn.init.normal_采样——都会消耗全局随机数序列,推进生成器的状态。
所谓“初始化完的权重发生变化”其实是错觉:
- 注释Q层时,实例化完四个
*_h就直接执行自定义初始化,此时全局随机数处于状态S1,正态分布采样得到的权重是固定一组值; - 取消Q层注释后,四个Q层实例化时的默认初始化会先消耗一段随机数,把全局状态推到S2,之后再给
*_h做normal初始化,采样得到的自然是完全不同的另一组值,看起来就像之前初始化好的权重变了。
复现问题的原始代码如下:
def __init__(self): self.tc_h = torch.nn.Sequential( torch.nn.Linear(512, 1024), torch.nn.ReLU(), torch.nn.Linear(1024, 512) ) self.tg_h = torch.nn.Sequential( torch.nn.Linear(512, 1024), torch.nn.ReLU(), torch.nn.Linear(1024, 512) ) self.vc_h = torch.nn.Sequential( torch.nn.Linear(512, 1024), torch.nn.ReLU(), torch.nn.Linear(1024, 512) ) self.vg_h = torch.nn.Sequential( torch.nn.Linear(512, 1024), torch.nn.ReLU(), torch.nn.Linear(1024, 512) ) #self.tc_Q = torch.nn.Linear(512, 512) #self.vc_Q = torch.nn.Linear(512, 512) #self.tg_Q = torch.nn.Linear(512, 512) #self.vg_Q = torch.nn.Linear(512, 512) for layer in [ self.tc_h, self.tg_h, self.vc_h, self.vg_h, #self.tc_Q, self.tg_Q, self.vc_Q, self.vg_Q, ]: for name, param in layer.named_parameters(): if name.endswith('weight'): nn.init.normal_(param, std=1024 ** -0.5)
验证与解决
可以通过两个简单操作验证逻辑、解决问题:
- 调整代码顺序:把四个
*_Q层的定义挪到自定义初始化for循环的后面。此时初始化*_h时Q层还没实例化,不会消耗随机数影响采样结果,后续Q层实例化的随机操作也不会改动已经赋值完成的*_h参数,不管加不加Q层,*_h的权重都能保持一致。 - 固定随机种子:如果需要严格复现初始化结果,最稳妥的方式是在模型
__init__最开头就加一行torch.manual_seed(你的固定种子值),等所有层都定义完成后再统一执行自定义初始化,只要层定义、初始化顺序不变,每次跑的初始化结果都完全一致。
补充说明
所有PyTorch内置的神经网络层在实例化时都会自动执行默认参数初始化,哪怕你后续打算手动重新初始化这一层,这个默认初始化的随机数消耗过程也不会跳过。不要依赖代码顺序的偶然性保证初始化结果一致。
内容的提问来源于stack exchange,提问作者zhangbw
相关产品推荐
相关产品推荐

