cannot assign module before Module.__init__() call:先初始化父类再挂载子层

简介: PyTorch中`nn.Module`子类必须**先调用`super().__init__()`**,再赋值子模块(如`self.embedding`),否则触发`AttributeError`。因模块注册依赖父类初始化完成。修复后需验证`named_parameters()`是否包含所有层,并确保前向/反向传播正常。(239字)

原帖的 QuestionClassifier 继承 nn.Module,但 init 一开始就给 self.embedding 赋子模块:

AttributeError: cannot assign module before Module.__init__() call

nn.Module 的注册机制要先初始化

把一个 EmbeddingLayer 赋给 self.embedding 时,nn.Module 会登记子模块,因而父类初始化必须已经完成。原题不是缺少 embedding 参数,而是构造函数调用顺序错误。修复这一层后,还需检查 EncoderRNN 等自定义子层是否遵循同样顺序。

nn.Module 需要先初始化内部参数与子模块注册结构。每个自定义模块构造函数都应先调用父类初始化,然后再创建和挂载层。

下面是可以独立运行的最小结构,对应原题的顺序问题:

import torch
from torch import nn

class QuestionClassifier(nn.Module):
    def __init__(self, vocab_size, embedding_dim):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.drop = nn.Dropout(0.1)

    def forward(self, token_ids):
        return self.drop(self.embedding(token_ids))

model = QuestionClassifier(10, 4)
print("josh050608")
print("modules:", list(model._modules))
print("parameters:", [name for name, _ in model.named_parameters()])
assert model(torch.tensor([[1, 2]])).shape == (1, 2, 4)

在原项目中,在 QuestionClassifier.init 的第一段加 super().__init__(),原来的 EmbeddingLayer、EncoderRNN 和 Dropout 保留在其后。也要检查这两个自定义子类是否同样调用了父类初始化。

不要等到子层已经赋值后再补调用,也不要多次调用父类初始化,否则可能清空之前的注册。旧 Python 写法 super(QuestionClassifier, self).__init__() 也表达同一意图。

验证能够构造实例,named_parameters() 能列出 embedding 与编码器参数,再建立优化器和执行前向。仅去掉赋值行让构造不报错,会同时丢掉真正需要训练的层。

不只验证构造,还要确认参数确实进入训练

下面的独立模型保留 embedding → 编码 → 分类的结构,但用简单平均代替原题未提供的 EncoderRNN。它只验证注册和反向,不是原模型的等价实现:

import torch
from torch import nn
class TextClassifier(nn.Module):
    def __init__(self, vocab_size, embedding_dim, classes):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.output = nn.Linear(embedding_dim, classes)
    def forward(self, token_ids):
        return self.output(self.embedding(token_ids).mean(dim=1))

model = TextClassifier(10, 4, 2)
names = dict(model.named_parameters())
assert "embedding.weight" in names and "output.weight" in names
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
optimizer.zero_grad()
logits = model(torch.tensor([[1, 2], [3, 4]], dtype=torch.long))
loss = nn.CrossEntropyLoss()(logits, torch.tensor([0, 1]))
loss.backward()
assert model.embedding.weight.grad is not None
assert model.output.weight.grad is not None
optimizer.step()
print("registered names:", list(names))

不要用直接给 self.__dict__ 填模块或删除 nn.Module 继承来绕开错误,那会破坏参数发现、设备迁移和 state_dict。也不要在已经创建子层后再次调用父类初始化,可能清空已注册的内容。

回到 QuestionClassifier,在 super 调用之后按原来的参数构建 EmbeddingLayer、EncoderRNN 和 Dropout,再检查 named_parameters() 是否覆盖应训练的层。最后做一个短 token 批次的前向和 backward,确认优化器指向当前模型参数,才能说明构造顺序修复没有丢掉网络组件。

参考:原始求助帖;技术依据:nn.Module(2.5)、Embedding(2.5)。

相关文章
|
2天前
|
缓存 Unix PyTorch
OSError: [Errno 24] Too many open files:两个 DataLoader 可以 zip,先查文件描述符
原帖双Loader并发读取ZIP导致“Too many open files”(Errno 24),实为文件描述符泄漏或生命周期管理不当,非ZIP不支持DataLoader。需排查Dataset中图像/HDF5/ZIP句柄是否及时释放,并优先采用单Loader配对Dataset保障数据一致性与资源可控性。(239字)
|
2天前
|
并行计算 PyTorch 算法框架/工具
Expected all tensors to be on the same device, cuda:0 and cpu:恢复训练时检查 SGD 动量
该问题源于断点续训时优化器状态(如SGD动量缓冲区)未与模型参数同设备,导致`optimizer.step()`中跨设备张量运算失败。前向/反向可正常执行,但动量更新报错“cuda:0 and cpu”。需检查并统一`param`、`grad`及`optimizer.state`中所有Tensor的设备。
|
2天前
|
并行计算 PyTorch Linux
libtorch_python.so: cannot open shared object file:文件缺失时先修复 torch 安装
该问题核心是 PyTorch 1.0.1.post2 安装不完整,`torch/lib/` 下缺失关键文件 `libtorch_python.so`,非环境变量(LD_LIBRARY_PATH)可解决。需先用 `importlib.util.find_spec` 定位真实安装路径,核对文件存在性;再通过 `pip show -f torch` 验证分发完整性。切勿混用版本或复制库文件。
|
2天前
|
并行计算 PyTorch Linux
RuntimeError: CUDA error: device-side assert triggered:Colab 先重启,再找首次断言
该文详解CUDA断言错误调试策略:强调先重启运行时、启用`CUDA_LAUNCH_BLOCKING=1`,用最小张量验证环境;区分“会话已坏”与新操作触发,主张逐段定位而非臆测标签越界,提供实用边界检查函数与验证流程。(239字)
|
2天前
|
并行计算 PyTorch 异构计算
can’t convert CUDA tensor to numpy:只取分类索引时直接用 torch.argmax
原帖因直接对CUDA张量调用`.data.numpy().argmax()`报错:“无法将CUDA张量转为NumPy”。正确做法是:在GPU上用`output.argmax(dim=1).item()`获取单图预测索引,避免全量拷贝,仅传回标量,高效且安全。(239字)
|
2天前
|
PyTorch 算法框架/工具 索引
ValueError: only one element tensors can be converted to Python scalars:张量列表先检查形状,再 stack
该文解析PyTorch中`list(tensor)`引发的`ValueError`根源:列表含多元素张量时,不可直接转Python标量。强调应通过`tensor.shape`或遍历打印各张量尺寸来查形状;同形张量用`torch.stack`(增维)而非`cat`或`item`;异形则保留原结构,避免强行转换。
|
2天前
|
数据可视化 PyTorch 算法框架/工具
only batches of spatial targets supported:三通道分割 one-hot 转为每像素类别编号
该报错源于PyTorch交叉熵要求标签为`[N, H, W]`(3D),但输入了`[N, 3, H, W]`(4D)掩码。需先验证三通道是否为互斥one-hot,再用`argmax(dim=1)`转为整型标签,并妥善处理全零未标注像素(设`ignore_index`),避免误判为背景类。(239字)
|
2天前
|
PyTorch 算法框架/工具 异构计算
Expected object of scalar type Float but got scalar type Double for argument #4 'mat1':NumPy 输入与 Linear 权重怎样统一类型
PyTorch中`RuntimeError: Expected Float but got Double`常因输入Tensor(float64)与模型权重(float32)类型不一致导致。关键在第一层Linear的输入与权重dtype需统一:可将数据转为float32(推荐),或模型整体升为float64。务必检查`tensor.dtype`而非数值显示,并确保`loss.backward()`前类型已对齐。(239字)
|
2天前
|
机器学习/深度学习 索引
The size of tensor a (133) must match tensor b (10):分类任务换 MSELoss 后先查标签含义
原帖网络输出133类logits,CrossEntropyLoss支持类别索引输入(如`[10]`),而MSELoss要求`outputs`与`target`形状严格匹配(如`[10,133]`)。报错因`target`为`[10]`,无法广播匹配`[10,133]`输出,本质是两类损失对标签格式约定不同。
|
2天前
|
PyTorch 算法框架/工具 索引
RuntimeError: expected scalar type Long but found Float:NLLLoss 要改 labels,不要把 images 转 long
该问题源于`NLLLoss`要求标签为`torch.long`类型(类别索引),但输入为`float`。需确保标签是整数编号(非概率/小数),并在`DataLoader`中统一配对图像与标签,避免双Loader错位;推荐改用`CrossEntropyLoss`配原始logits,或`LogSoftmax+NLLLoss`组合。(239字)

热门文章

最新文章