同一nn.Module实例用于两个子网络时权重是否共享?如何实现权重独立?
问题
场景说明
我定义了如下PyTorch网络作为最简示例:
class Convolution_Layers(nn.Module): def __init__(self, in, out, kernel): super(Convolution_Layers, self).__init__() self.conv2d = nn.Conv2d(in_channels=in, out_channels=out, kernel_size=kernel) self.conv2d_layers = nn.Sequential( self.conv2d, nn.ReLU, ) forward(self,x): return self.conv2d_layers(x) class Network_Model(nn.Module): def __init__(self): super(Network_Model, self).__init__() self.basic_conv = Convolution_layers(1,1,3) self.subnetwk_1 = nn.ModuleList().append([self.basic_conv]) self.subnetwk_2 = nn.ModuleList().append([self.basic_conv]) def forward(self,x1,x2): out1, out2 = x1, x2 for l in self.subnetwk_1: out1 = l(x1) for l in self.subnetwk_2: out2 = l(x2) return out1,out2
注:原代码存在两处小问题:forward方法缺少def关键字;实例化时类名拼写错误(Convolution_layers应为Convolution_Layers)。
疑问
- 由于
subnetwk_1和subnetwk_2使用的是同一个Convolution_Layers实例,二者是否会共享权重? - 我希望两个子网络的权重相互独立,但仅需定义一次基础卷积块并在多处复用,请问有更优实现方式?
解答
关于权重共享的问题
是的,subnetwk_1和subnetwk_2会完全共享权重。因为它们引用的是同一个Convolution_Layers实例self.basic_conv,PyTorch中Module的权重参数绑定在实例本身,所有对该实例的调用都会使用同一组权重,反向传播时梯度也会累积到这组权重上。
另外需要纠正代码中的一个错误:nn.ModuleList().append([self.basic_conv])的写法是无效的,append方法不会返回新的ModuleList,而是在原对象上修改,最终self.subnetwk_1和self.subnetwk_2会是None。正确写法应为:
self.subnetwk_1 = nn.ModuleList([self.basic_conv]) self.subnetwk_2 = nn.ModuleList([self.basic_conv])
实现独立权重的复用方案
要达成“定义一次基础块,多处复用且权重独立”的需求,推荐以下几种方式:
1. 直接多次实例化基础块
在父Module的__init__方法中创建多个独立的Convolution_Layers实例,基础块的定义只写一次:
class Network_Model(nn.Module): def __init__(self): super(Network_Model, self).__init__() # 创建两个独立实例,权重完全分离 self.subnetwk_1 = nn.ModuleList([Convolution_Layers(1,1,3)]) self.subnetwk_2 = nn.ModuleList([Convolution_Layers(1,1,3)]) def forward(self,x1,x2): out1 = x1 for l in self.subnetwk_1: out1 = l(out1) out2 = x2 for l in self.subnetwk_2: out2 = l(out2) return out1,out2
2. 用工厂函数封装基础块创建
如果基础块的参数较多或需要在多个地方复用,可以用工厂函数统一管理实例创建逻辑:
def create_basic_conv(in_ch=1, out_ch=1, kernel=3): return Convolution_Layers(in_ch, out_ch, kernel) class Network_Model(nn.Module): def __init__(self): super(Network_Model, self).__init__() self.subnetwk_1 = nn.ModuleList([create_basic_conv()]) self.subnetwk_2 = nn.ModuleList([create_basic_conv()]) def forward(self,x1,x2): out1 = x1 for l in self.subnetwk_1: out1 = l(out1) out2 = x2 for l in self.subnetwk_2: out2 = l(out2) return out1,out2
3. 动态实例化适配复杂场景
如果需要根据配置批量创建不同参数的块,可以结合配置列表动态生成:
class Network_Model(nn.Module): def __init__(self, conv_configs=[(1,1,3), (1,1,3)]): super(Network_Model, self).__init__() self.subnets = nn.ModuleDict() for i, cfg in enumerate(conv_configs): self.subnets[f"subnet_{i+1}"] = nn.ModuleList([Convolution_Layers(*cfg)]) def forward(self,x1,x2): out1 = x1 for l in self.subnets["subnet_1"]: out1 = l(out1) out2 = x2 for l in self.subnets["subnet_2"]: out2 = l(out2) return out1,out2
内容的提问来源于stack exchange,提问作者wkacct acctwk
相关产品推荐
相关产品推荐

