You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何修改PyTorch网络__init__中层定义顺序会改变模型准确率?

问题描述

我搭建了如下继承自nn.Module的RNN神经网络模型,代码实现如下:

class RNN(nn.Module):
    def __init__(self, input_size, hidden_size,  num_layers1, num_layers2, num_layers3, num_classes):
        super(RNN, self).__init__()
        self.num_layers1 = num_layers1
        self.num_layers2 = num_layers2
        self.num_layers3 = num_layers3
        self.hidden_size = hidden_size 

        self.transformer = nn.TransformerEncoderLayer(d_model=100, nhead=20, layer_norm_eps=1e-04, dropout=0.3, dim_feedforward=2048, norm_first=True, activation= "relu", batch_first=True)

        self.fc1_bn = nn.BatchNorm1d(125)
        self.conv1 = torch.nn.ConvTranspose1d(in_channels=125, out_channels=125, kernel_size=6)   
        self.layerNorm = torch.nn.LayerNorm(7)

        self.drop2 = torch.nn.Dropout(DROPOUT2)  
        self.conv2 = torch.nn.ConvTranspose1d(in_channels=125, out_channels=125, kernel_size=5)   
        self.layerNorm2 = torch.nn.LayerNorm(512)

        self.maxpool1d = nn.LPPool1d( 1,1)
        self.fc2_bn= nn.BatchNorm1d(125)

        self.lstm2 = nn.LSTM(200, hidden_size, num_layers2, batch_first=True ,dropout = .2 ) 

        #
        #self.maxpool1d2 = nn.LPPool1d( 1,1)          
        self.lstm3 = nn.LSTM(hidden_size, hidden_size, num_layers3, batch_first=True  )
        self.drop3 = torch.nn.Dropout(DROPOUT3)


        self.lstm4 = nn.LSTM(200, 200, num_layers3, batch_first=True  )
        
         
        self.fc = nn.Linear(hidden_size, num_classes)    

        self.fc2 = nn.Linear(100, 200)   
        self.fc3 = nn.Linear(205, 200)   
        self.fc4 = nn.Linear(512, 512)   
        self.fc5 = nn.Linear(3, 100)  


    def forward(self, x):
        h02 = torch.zeros(self.num_layers2, x.size(0), self.hidden_size).to(device) 
        c02 = torch.zeros(self.num_layers2, x.size(0), self.hidden_size).to(device) 
        h03 = torch.zeros(self.num_layers3, x.size(0), self.hidden_size).to(device) 
        c03 = torch.zeros(self.num_layers3, x.size(0), self.hidden_size).to(device) 

        #out = self.conv1(x)

        out = F.relu(self.fc5(x))
        out = self.transformer(out)
        out = F.relu(self.fc2(out))
        #out = self.fc1_bn(out)
        
        

        out = self.conv1(out)
        out = F.relu(self.fc3(out))
        out = self.maxpool1d(out)
        
        
        out, _ = self.lstm2(out, (h02,c02))
        out = F.relu(self.fc4(out)) 
        #out = self.fc1_bn(out)

        out, _ = self.lstm3(out, (h03,c03))   

        out = out[:, -1, :]    
        out = self.fc(out)       
        return out

实验过程中我发现,若修改__init__方法内任意模块的定义顺序,模型准确率会出现大幅变化;若保持原有定义顺序不变,准确率则不会出现异常波动。我原以为__init__方法仅用于声明神经网络的各个组成模块,并不会实际参与前向传播计算,为什么仅调整模块的定义顺序就会影响模型的最终输出结果?

原因说明
  • 核心原因是PyTorch会在实例化nn.Module子类时,按照__init__中模块的定义顺序依次初始化每个模块的权重参数,权重初始化需要调用随机数生成器,调整模块顺序会直接改变随机数的消耗顺序,最终每个模块拿到的初始权重完全不同。
    举例:原本先定义Transformer层再定义BN层,初始化时随机数序列会先分配一段值给Transformer的权重,再分配下一段给BN层;如果调换两者顺序,BN层会先占用原本分给Transformer的随机值,Transformer只能取后面的随机值做初始化,所有模块的初始权重从根源上发生了变化。
  • 如果固定了全局随机种子来保证实验可复现,模块定义顺序就是决定初始权重取值的关键变量之一。初始权重不同,模型训练的收敛路径、最终收敛到的局部最优点都会变化,准确率自然会出现大幅波动。
  • 上述代码中定义了conv2、drop2、layerNorm、layerNorm2、fc2_bn、lstm4多个模块,但这些模块根本没有在forward方法中被调用。这些未使用的模块在实例化时同样会消耗随机数,哪怕它们不参与前向传播,只要定义顺序变了,一样会打乱后续实际参与计算的模块的初始权重取值。
  • 容易忽略的细节:PyTorch中nn.Module的parameters()、children()、named_modules()等接口遍历模块时,严格按照__init__里的模块注册顺序返回结果。如果训练时用到了参数遍历逻辑(比如分层设置学习率、权重衰减、不同层使用不同优化器),模块顺序变化会导致训练策略的实际生效对象错位,进一步影响最终训练结果。

内容的提问来源于stack exchange,提问作者samuel fipps

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:24:15