PyTorch中自定义单算子nn.Module与官方层、Sequential的差异探究
自定义单卷积Module、直接实例化卷积层与nn.Sequential的差异分析
首先,你的model1代码存在致命错误
你定义的conv类里,__init__方法中的conv1是局部变量,既没有注册为Module的可训练参数/子模块,也没有绑定为类属性。当调用model1(input)时,forward方法里的conv1会因找不到变量直接抛出NameError。
正确的model1写法必须调用父类初始化方法,并将conv1设为类属性:
class conv(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(1,20,5) def forward(self,x): return self.conv1(x) model1 = conv() model1(input)
修正后,三个模型的核心差异
1. 类型与结构差异
model2是直接实例化的Conv2d类,类型为torch.nn.modules.conv.Conv2d,本身就是独立的卷积层模块。- 修正后的
model1是自定义的nn.Module子类,类型为你定义的conv类,内部封装了一个Conv2d子模块。 model3是nn.Sequential容器,类型为torch.nn.modules.container.Sequential,内部按顺序存放了一个Conv2d模块。
2. 功能与行为差异
仅看前向传播计算,三者输出结果完全一致,但其他场景下存在明显区别:
- 参数访问:
- model2可直接通过
model2.weight访问卷积核参数; - model1需通过
model1.conv1.weight访问; - model3需通过
model3[0].weight访问。
- model2可直接通过
- 模型序列化(保存/加载):
- 三者都能正常保存加载,但state_dict的键结构不同:
- model2的键为
weight、bias; - model1的键为
conv1.weight、conv1.bias; - model3的键为
0.weight、0.bias。
- model2的键为
- 三者都能正常保存加载,但state_dict的键结构不同:
- 扩展性:
- model1可随时在
__init__或forward中添加自定义逻辑(比如激活函数、分支计算); - model2是单一卷积层,无法直接扩展,需额外封装;
- model3只能按顺序追加模块,仅支持线性执行逻辑。
- model1可随时在
3. model3能否等同于model1?
仅在单一卷积层的前向计算场景下,二者输出一致,但在参数访问、序列化结构、扩展性上均有差异,不能说"任何场景下等同"。比如后续要修改卷积层参数时,二者的访问路径不同;若需添加新的计算逻辑,model1的修改灵活性远高于model3。
内容的提问来源于stack exchange,提问作者JunKyeong Choi
相关产品推荐
相关产品推荐

