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

PyTorch中nn.Module子类属性式子模块赋值失效问题

问题分析与解决方案

你的问题并不是nn.Module的属性机制损坏,而是它重写的__setattr__方法为了管理子模块、参数和缓冲区,行为和普通Python类不同,导致你的@property setter没有按预期工作。

原因解释

nn.Module的__setattr__会根据赋值对象的类型和属性名做特殊处理:

  • 当赋值的是nn.Module或Parameter实例时,若属性名不以下划线开头,会将其注册到模块的_modules或_parameters字典中,而非直接存入实例的__dict__;
  • 若属性名以下划线开头,新版本PyTorch会直接存入__dict__,但旧版本可能仍会将其注册到_modules。

你的代码中,_submodule以下划线开头,在setter中执行self._submodule = new_submodule时,触发了nn.Module的__setattr__,导致赋值行为没有正确修改到你期望的属性存储位置,最终getter返回的还是旧值。

解决方案

有几种简单的方法可以解决这个问题:

方法1:直接操作实例的__dict__绕过__setattr__

修改setter方法,直接修改实例字典中的值,避免触发nn.Module的特殊处理:

@x.setter
def x(self, new_submodule):
    self.__dict__['_submodule'] = new_submodule

方法2:使用非下划线开头的属性名

将存储子模块的属性名改为普通名称(不带下划线前缀),让nn.Module正常管理子模块的注册与替换:

class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.submodule = nn.Linear(5, 5)

    @property
    def x(self):
        return self.submodule

    @x.setter
    def x(self, new_submodule):
        self.submodule = new_submodule

方法3:手动注册子模块(可选)

如果需要保留下划线前缀的属性名,可以在setter中手动调用register_module方法,确保子模块被正确更新:

@x.setter
def x(self, new_submodule):
    self.register_module('_submodule', new_submodule)

验证修改效果

无论使用哪种方法,重新运行代码后,赋值操作都会生效,输出会变为:

Initial module.x: Linear(in_features=5, out_features=5, bias=True)
After assignment attempt, module.x: Linear(in_features=5, out_features=2, bias=True)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:14:52