pytorch中正确使用padding mask需注意四点:1. src_key_padding_mask须为布尔张量,true标padding,构造应为(input_batch == pad_token_id);2. rnn/lstm必须用pack_padded_sequence且输入按长度降序;3. crossentropyloss需设ignore_index匹配label中padding值;4. generate时attention_mask须随解码步长动态扩展。

PyTorch里nn.TransformerEncoder怎么正确传入src_key_padding_mask
不传或传错src_key_padding_mask会导致模型在padding位置参与注意力计算,训练不稳定甚至发散。它必须是布尔型张量,形状为(batch_size, seq_len),True表示该位置是padding,需被mask掉。
常见错误:用0填充的int型input_ids直接转bool——这会让所有非零位置变成True,逻辑完全反了。正确做法是显式构造:
# 假设 input_batch.shape == (32, 512),pad_token_id = 0 src_key_padding_mask = (input_batch == 0) # shape: (32, 512),True=padding encoder_out = transformer_encoder(src, src_key_padding_mask=src_key_padding_mask)
注意:src_key_padding_mask只影响self-attention中的key和value,不影响query;且PyTorch默认不自动处理,必须手动传入。
自定义RNN/LSTM时如何用pack_padded_sequence避免padding干扰
pack_padded_sequence不是可选优化,而是必须步骤——否则LSTM会对padding位置做无意义状态更新,污染隐藏态,尤其在变长序列batch中会导致梯度异常和预测漂移。
关键约束有三个:
-
input必须按序列长度降序排列(enforce_sorted=True默认要求) -
lengths必须是CPU上的torch.int64一维张量 -
pack后必须立刻接LSTM,不能中间插其他层
# lengths = [128, 97, 64, ...],已从大到小排序 packed = nn.utils.rnn.pack_padded_sequence(x, lengths, batch_first=True, enforce_sorted=True) lstm_out, (h_n, c_n) = lstm(packed) padded_out, _ = nn.utils.rnn.pad_packed_sequence(lstm_out, batch_first=True)
漏掉pad_packed_sequence会导致输出维度错误;反过来,如果输入本就是等长序列,硬加pack反而引入额外开销。
训练时cross_entropy_loss怎么跳过padding位置的loss计算
直接对整个logits张量调用F.cross_entropy会把padding位置(如label=0)也计入损失,拉低有效token的梯度强度,收敛变慢。
标准解法是先展平再过滤:
- 将
logits和targets从(B, T, V)和(B, T)展平为(B*T, V)和(B*T,) - 用
targets != ignore_index生成mask(通常ignore_index = -100) - 只对mask为
True的位置计算loss
logits = model(x) # (32, 512, vocab_size) targets = labels # (32, 512),padding位置填-100 loss_fn = nn.CrossEntropyLoss(ignore_index=-100) loss = loss_fn(logits.view(-1, logits.size(-1)), targets.view(-1))
务必确认labels中padding对应值与ignore_index一致;若用0作padding,就设ignore_index=0,否则loss仍含噪声。
推理阶段generate函数如何防止mask失效导致死循环
Transformer解码器在自回归生成时,若未正确维护causal_mask和padding_mask,可能让模型“看见”未来token或重复关注已生成padding,造成重复输出或卡住。
核心要点:
- 每次新token加入,
past_key_values长度+1,对应attention_mask也要右扩一列1 - 手动构建
causal_mask时,用torch.triu(torch.full((seq_len, seq_len), float('-inf')), diagonal=1),不能手写循环 - 如果用
model.generate(..., attention_mask=attn_mask),确保attn_mask随step动态增长,而非固定长度
最稳妥的做法是复用Hugging Face transformers的generate逻辑,或严格校验每次forward调用中attention_mask的shape是否等于当前序列长度。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











