pad_sequence默认按dim=0对齐,输出为[max_t, b, d];需设batch_first=true得[b, max_t, d],输入须≥2d,掩码应基于长度构造torch.bool张量,pack_padded_sequence要求lengths降序排列。

用 pad_sequence 合并变长张量时,为什么输出形状不对?
因为 pad_sequence 默认按**序列维度(dim=0)** 对齐,即把每个张量看作一个“时间步”列表,自动在开头补零到最长序列长度。如果你传入的是 shape 为 [T_i, D] 的张量(比如 [5, 128]、[3, 128]),结果会是 [max_T, B, D],而不是你可能期望的 [B, max_T, D]。
常见错误现象:RuntimeError: expected 3D input for 3D weight —— 比如后续接 LSTM 或 Transformer,它们通常要求 batch 在第 0 维。
- 必须显式设置
batch_first=True才能得到[B, max_T, D]形状 - 所有输入张量必须至少是 2D(不能是 1D 向量),否则
pad_sequence会报错ValueError: Expected at least 2D tensor - 如果张量是
[D](比如单个词向量),先用.unsqueeze(0)变成[1, D]
怎么同步生成对应掩码(mask)?
PyTorch 不提供自动掩码,但逻辑很直接:原序列长度已知,补零位置就是无效位置。关键是别用 == 0 判断 —— 输入本身可能含零值,掩码就错了。
正确做法是基于原始长度构造布尔掩码:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
from torch.nn.utils.rnn import pad_sequence import torch <h1>假设 sequences = [t1, t2, t3], 每个 t_i.shape == [T_i, D]</h1><p>lengths = [t.size(0) for t in sequences] padded = pad_sequence(sequences, batch_first=True, padding_value=0.0) # [B, max_T, D]</p><h1>生成 mask: [B, max_T], True 表示有效位置</h1><p>mask = torch.arange(padded.size(1)).expand(len(lengths), -1) </p><h1>或更简洁(推荐):</h1><p>mask = torch.zeros(len(lengths), padded.size(1), dtype=torch.bool) for i, l in enumerate(lengths): mask[i, :l] = True </p>
- 用
torch.arange+ 比较比循环更快,但可读性略低;小批量用循环更稳 - 掩码 dtype 必须是
torch.bool(不是torch.uint8),否则传给nn.TransformerEncoder会静默失败或报错 - 如果后续要喂给
packed_padded_sequence,则不需要手动掩码,但必须用lengths参数排序+降序
遇到 RuntimeError: lengths array must be sorted in decreasing order 怎么办?
这是 pack_padded_sequence 的硬性要求,和 pad_sequence 无关 —— 但很多人想边 pad 边 pack,就踩进这个坑。
- 先对原始序列按长度降序排列:
sequences, lengths = zip(*sorted(zip(sequences, lengths), key=lambda x: x[1], reverse=True)) - 再调用
pad_sequence(顺序已变,不影响 padding 结果) - 最后用
pack_padded_sequence(padded, lengths, batch_first=True, enforce_sorted=True) - 注意:如果用了
enforce_sorted=False,PyTorch 内部会重排,但返回的 packed 输出与原始 batch 顺序不一致,解包后需额外还原顺序
padding_value 设为非零值会影响模型吗?
绝大多数情况下不影响,只要你没在损失计算或注意力中误把 padding 当有效 token 处理。但两个细节容易被忽略:
- Transformer 的
src_key_padding_mask是布尔掩码,和padding_value无关;它只靠你传入的mask决定哪些位置忽略 - 某些自定义 embedding 层若对输入做了归一化(比如 LayerNorm 接在 Embedding 后),而 padding 用了非零值,会导致 norm 计算污染 —— 此时必须用
0.0,并在 embedding 后加mask * output显式清零 - 分类任务中,如果用
torch.nn.CrossEntropyLoss,它默认 ignore_index=-100,但不会自动忽略 padding;你需要自己把 padding 位置的 logits 设为极小值,或用loss(..., ignore_index=0)配合标签掩码
最稳妥的做法:padding_value 固定用 0.0,掩码单独管理,不要依赖数值特征判断有效位。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










