F12|Mask不是黑箱:把“谁能看谁”写成一张表
从具体对象与小例子开始,理解计算过程与适用条件。
本章目录
Mask是可见性表,不是额外语义
怎样防止读到未来,或者把PAD读成内容?
把注意力的分数表看成一张“谁可以读谁”的座位表。行代表接收者,列代表提供者;禁止格子不能参与概率分母。因果限制、PAD限制可以同时存在,但一个负责时间顺序,一个负责有效内容,不能互相替代。
输入与适用条件:前3帧用3个有效位置;第4帧是明确的屏蔽数值对照;第5帧另设past=3、new=2展示缓存偏移。图内始终标出当前条件。
1 / 5 · 处理绝对位置0
窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。
位置不是数字大小比赛。因果规则只允许当前查询读取自己和更早的Key;后面的位置即使已经在训练输入数组中,也不能读。
允许Key位置 ≤ 0默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。
为什么需要
防止训练偷看目标,并排除只为组批存在的填充内容。
怎样实现
先按实际位置和有效长度构造关系,再核对所用API布尔mask语义。
可能的代价与误解
不同API的True可能表示允许或禁止;全行无可见Key还需明确策略,不能直接做普通softmax。
如何判断是否做对
用能暴露未来泄漏的数据,比较正确掩码与故意写错偏移的结果。
先给掩码一个不神秘的定义
Mask(掩码)是一份控制哪些元素允许参与某项运算的标记。在注意力里,一行是一个查询位置,一列是一个被读取位置。因此一个格子回答“这一行能不能读这一列”。
填充标记、注意力可读关系、训练损失计分位置都可能被称为mask,但用途不同。看见mask这个词,先问它控制什么,而不是只背一组0和1。
因果限制怎样防止读未来
三个位置0、1、2,在自回归训练和推理所用的因果注意力中,常见允许关系是:
| 查询位置\Key位置 | 0 | 1 | 2 |
|---|---|---|---|
| 0 | 允许 | 禁止 | 禁止 |
| 1 | 允许 | 允许 | 禁止 |
| 2 | 允许 | 允许 | 允许 |
叫“因果”是因为当前位置不能依赖尚未发生的后续Token,不是在声称模型学到了现实世界的因果关系。训练时整段答案可以一起送入;掩码限制每个位置只能利用前缀,目标通常是预测下一个Token。
填充限制与因果限制怎样合在一起
继续用第二条输入[4,2,0]。前两个位置是真实内容,第三个是PAD。对真实查询0、1,可读取列必须同时满足“不是PAD”和“不在未来”。它们的关系为:
query0 -> key0允许,key1禁止,key2禁止
query1 -> key0允许,key1允许,key2禁止
PAD查询行本身不是本次有意义的输出,不用它继续生成,也不让其预测计入正常损失。实际内核怎样避免全屏蔽行的数值问题,要遵守接口语义,不能盲目把整行都填负无穷。
批量输入还有样本边界;第0条不能因为同在一个batch就读到第1条。若将多个样本拼在一条序列中,需要另行处理跨样本可读关系,单独插一个结束Token不天然形成矩阵隔离。
“禁止”具体怎样改变softmax
一个常见数学表达是在禁止位置的分数加上负无穷,使其指数为0;允许位置加0,保留原分数,然后对一行归一化。
若先对所有位置softmax,再把禁止项清零而不重新归一化,剩余权重总和会小于1,通常不是原本要的注意力。
全行没有任何允许项时,softmax没有正常的有限候选可归一化,朴素计算可能出现NaN,即“不是有效数值”。工程实现要明确处理或避免这种行,而不是让NaN悄悄传下去。
不同API可能用布尔True表示允许,也可能表示屏蔽;也可能接受加性浮点mask。不要把本文1=允许直接当成任何库的通用布尔约定。
已有缓存时,表为什么不再是小正方形
先把缓存理解为“之前算好的中间结果”,详细内容在F16。假设已有3个历史位置,新算2个位置。这次只有2个Query,但可以读5个Key:
新位置3:[允许,允许,允许,允许,禁止]
新位置4:[允许,允许,允许,允许,允许]
因此表是[2,5]。第一行并不是只能读第一列,因为它的真实位置已经是3。规则是“Key逻辑位置不大于当前Query逻辑位置”,不是简单在一个2×5表左上角画小三角。
Loss mask又是什么
训练样本含问题与回答时,可能只给回答部分的下一Token预测计损失。loss mask决定哪些预测被评分;attention mask决定读取哪些条件。不给用户问题计损失,不意味着模型不能读用户问题。
这一差异以后用于解释训练:模型可以借助问题预测答案,即使问题本身不是本批直接评分的目标。
3个历史位置加2个新位置,掩码怎样展开
输入与条件。历史位置为0、1、2;新输入为位置3、4。现在只有2个查询,但共有5个Key可比较。这里用“能读/禁读”避免不同API的布尔极性混淆。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1列出列 | Key列标为0、1、2、3、4 | 所有列均包含真实位置,不是五个新输入。 |
| 2第1个新查询 | 绝对位置3只能看≤3的位置 | [能读,能读,能读,能读,禁读]。 |
| 3第2个新查询 | 绝对位置4能看≤4的位置 | [能读,能读,能读,能读,能读]。 |
| 4修改分数 | 把禁读列分数设为负无穷再softmax | 该列权重变0;不能只把原始分数乘0。 |
| 5错误对照 | 对2×5表直接套左上角小三角 | 第1行只能读位置0,错误丢掉历史位置1、2和当前位置3。 |
把过程连起来。因果判断比较绝对位置,不能拿新块中的第几行直接当全序列位置。
边界与反例。全被屏蔽的一行没有标准softmax分布,教学程序明确拒绝;生产核可能有自己的约定。
课后自检
已经有2个历史Token,只新增1个Token,新的Query应能读几个Key?
查看参考答案收起参考答案
只对助手答案算损失,是否应把用户问题在attention里屏蔽?
查看参考答案收起参考答案
机制依据:[TR][F-PADDING][F-CACHE]。本节数值与情景除另注外均为原创教学示例;来源不代替中文讲解。