padding_idx:为什么零向量仍需要注意力mask

黎 浩然/ 18 10 月, 2026/ 大语言模型/LARGELANGUAGEMODEL/LLM, 教程/TUTORIAL, 计算机/COMPUTER/ 0 comments

Embedding设置padding_idx,并不会自动告诉后面的注意力层忽略padding位置。即使pad向量恰好全零,它仍可能进入softmax分母,改变真实token的权重。一个只有两项的反例就能看清:分数都是0,值分别为2和0,未遮蔽输出是1;排除pad后才是2。

文章目录
  1. padding_idx约束的是嵌入查表
  2. 零值没有从softmax分母消失
  3. 补齐长度会暴露这种错误
  4. 十二项检查复现分母效应
  5. 布尔mask要按具体API解释
  6. 键被屏蔽,不代表pad查询输出为零
  7. 全padding样本要有明确处理策略
  8. 逐层定位,而不是只改一个参数
  9. 来源与补发说明

本文把嵌入行、注意力mask、池化和损失四件事分开,用十二项精确检查复现补齐长度带来的变化,并给出适合迁移到真实模型的核验方式。代码是标准库数学模型,没有运行PyTorch或融合注意力内核。Read in English。

padding_idx约束的是嵌入查表

PyTorch Embedding文档说明,padding_idx对应项不贡献嵌入查表的梯度,新建模块时这一行默认全零,也可以被改成其他padding向量。这个参数描述的是嵌入层行为,不是对整个网络所有后续算子的统一屏蔽指令。

因此至少有两个独立问题:查表返回什么向量,以及后续注意力允许哪些键参与。把两者混在一起,容易得到“pad行是零,所以后面不需要mask”的错误结论。后续模块若根本没收到长度或有效位置,也没有足够信息自动推断你的padding约定。

实际网络还可能叠加位置表示、带偏置的线性投影或其他变换。零嵌入经过这些操作后不一定仍是零。即使在没有这些因素的最简单情形,下一节的归一化反例也已经成立。

零值没有从softmax分母消失

单个查询对两个键的分数设为s₁=s₂=0。softmax给出的权重均为exp(0)/(exp(0)+exp(0))=1/2。若两个值分别为v₁=2、v₂=0,输出就是(1/2)×2+(1/2)×0=1。

第二个值不贡献分子,却仍让第一个值的权重从1降到1/2。若明确把第二个键排除,只有第一个键参加归一化,输出才回到2。mask解决的是参与集合,不是简单把参与者的值改成零。

未遮蔽:权重½、½
值2、0 → 输出1
遮蔽pad:权重1、0
值2、0 → 输出2
原创零分数反例:值为零的pad仍分走未遮蔽softmax的一半权重;mask改变的是归一化参与者。

这里所有分数为零,可以由零查询构造出来;值与键是独立给定的教学量。它不是某个Transformer的实测隐藏状态,也不需要假设真实模型的所有注意力分数通常为零。

补齐长度会暴露这种错误

把同一个有效值2后面追加m个零值pad,并保持所有分数为零。不遮蔽时,每项权重都是1/(m+1),结果变成2/(m+1)。pad越多,结果越小,尽管有效内容根本没有变化。

这给了一个有用的回归测试方向:固定有效token及其位置语义,只改变补齐数量,检查有效位置的结果是否保持预期一致。若结果变化,应逐层检查mask和归约;不能仅凭这个现象就断定某个具体内核有缺陷。

比较时要控制dropout与其他随机因素,也要允许实际浮点实现的合理误差。左补齐如果同时改变位置编号,就不是只改变padding数量的单变量实验;应先对齐位置语义,再解释差异。

十二项检查复现分母效应

代码利用“允许位置的分数全为零”这一前提,直接计算均匀加权平均。它不用exp近似,不声称代替通用softmax实现。空集合和全部屏蔽被应用层明确拒绝。

# Exact attention toy: all logits are zero, so allowed weights are uniform.
from fractions import Fraction as F

def zero_score_attention(values, allowed):
    if len(values) != len(allowed):
        raise ValueError("shape mismatch")
    kept = [F(v) for v,ok in zip(values,allowed) if ok]
    if not kept:
        raise ValueError("no valid key")
    return sum(kept,F(0))/len(kept)

for pads in [0,1,2,5]:
    values = [2] + [0]*pads
    assert zero_score_attention(values,[True]*len(values)) == F(2,1+pads)
    assert zero_score_attention(values,[True]+[False]*pads) == 2
assert zero_score_attention([2,6,0],[True,True,False]) == 4
for values,mask in [([],[]), ([0],[False]), ([2],[True,False])]:
    try:
        zero_score_attention(values,mask)
    except ValueError:
        pass
    else:
        raise AssertionError("expected ValueError")
print("12 padding-attention checks passed")

本地十二项检查通过:四种补齐数量分别验证未遮蔽和正确遮蔽的结果,再检查两个有效值的平均,以及空输入、全部屏蔽、长度不匹配三种拒绝路径。抛异常是这段教学函数选择的契约,不代表所有框架对全屏蔽行都有相同返回行为。

布尔mask要按具体API解释

scaled_dot_product_attention文档中,布尔attn_mask的True表示参加注意力;浮点mask则加到分数上。数值0的浮点mask不等于排除位置,因为它只是加零。应按目标API的规则构造可见性,而不是根据变量名猜测。

MultiheadAttention的key_padding_mask采用另一种布尔约定:True表示忽略对应键。仅就这个key_padding_mask参数而言,一个“True代表有效”的张量,不能不经转换就当作“True代表padding”的张量使用;不能把此对比推广成所有mask参数的通用约定。迁移接口时,核对极性比核对dtype更重要。

还要给每个维度写出含义:批、头、查询位置与键位置。形状能广播只说明运算可以执行,不证明同一个样本的有效键被正确应用到它自己的查询上。先用很短、不同长度的两个样本检查可见矩阵,再扩展到真实批次。

键被屏蔽,不代表pad查询输出为零

键mask限制其他位置能读取哪些键。padding位置本身作为查询时,仍可能读到有效键并产生非零结果。是否保留、清零或丢弃这些输出,取决于后续模块如何使用它们,不能把“屏蔽pad键”理解成所有pad行自动消失。

例如句向量使用平均池化时,如果把补齐行也加入平均分母,结果仍会随长度变化。即便这些行已经清零,分母若使用总补齐长度,也会稀释表示。应分别定义参与求和的元素与计数规则。若mᵢ表示有效位置,分母为正时可写成Σmᵢhᵢ/Σmᵢ;全padding导致分母为零,仍需单独制定处理策略。

嵌入行
注意力键可见性
池化分母
损失参与范围
原创职责图:嵌入查表、注意力键、池化表示与损失分别需要明确的padding规则。

损失层也有独立约定。忽略padding标签能让某些位置不直接计入loss,却不能撤销前面未遮蔽注意力对有效位置表示的影响。修复损失mask,不能代替修复特征计算中的可见性。

全padding样本要有明确处理策略

如果某个查询没有任何有效键,普通softmax的归一化集合为空。不要把一个任意“很大的负数”当作通用解决方案:若所有分数都被设置成相同有限值,归一化仍可能给出均匀权重。

应用可以拒绝无有效内容的样本,或设计并验证明确的零输出路径;选择应与后续池化、损失及批处理契约一致。不同后端、版本和mask表达可能有不同边界处理,本文不承诺它们一定返回NaN或一定返回零。

真实测试应同时覆盖无padding、部分padding、全部padding,以及同批次不同长度。除输出外,还要检查损失和梯度是否符合预期,不能只确认一次前向没有报错。

逐层定位,而不是只改一个参数

先检查token ID和有效长度,再查看嵌入输出、位置变换、注意力可见矩阵、有效查询输出,最后查看池化与损失归约。每层记录清楚“哪些位置参与”,就能把补齐相关变化定位到具体环节。

此前SDPA推理时的dropout检查关注随机失活配置;本篇的补齐回归测试同样需要控制它,但主要检查归一化参与集合。两类问题应分别构造最小例子,不要一次同时改动后难以判断原因。

如果你已经设置padding_idx,仍看到同一内容因补齐长度不同而变化,下一步应该检查注意力和归约链路。若本文的最小反例与分层核验方法帮你定位了问题,欢迎通过文末支持区自愿支持。

来源与补发说明

依据PyTorch 2.8的Embedding、SDPA及MultiheadAttention文档核对。两幅图、均匀注意力反例和十二项检查为原创内容;未运行PyTorch或GPU内核。本篇保留2026年10月18日19:00文章日期,实际于2026年10月19日补发。

支持

如果文中的解释或示例帮你解决了问题、节省了时间,欢迎自愿打赏支持本站。

微信支持二维码,点击查看大图
微信
支付宝支持二维码,点击查看大图
支付宝
Buy Me a Coffee,点击支持本站
Buy Me a Coffee

二维码可点击放大。更多支持方式见支持页面。

Share this Post

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注

*
*