简单来说,nk 和 nv 共同组成了一个可学习的 “空”令牌(null token) 或 “哨兵”令牌(sentinel token)。这个特殊的令牌不来自任何输入,而是作为模型的一个内置参数,在每次注意力计算时被动态添加到序列的开头。
初始化
1 | self.null_kv = nn.Parameter(torch.randn(2, heads, 1, dim_head)) |
- 第一个维度是 2, 分别代表 key(k) 和 value(v)
- 1 代表这是长度为 1 的序列,即单个令牌
forward
1 |
|
核心目的
引入这样一个“空”令牌主要有两个核心目的,这让模型变得更加灵活和强大:
- 作为“信息池”或“空操作” (Information Sink / No-Op)
想象一下,序列中的某个查询令牌(query)可能在当前上下文中找不到任何与之强相关的其他令牌。如果没有 null_kv,它仍然必须将注意力权重分配给序列中的其他项。
提供一个“无处可去”时的选择:null_kv 提供了一个“无所谓”或“以上都不是”的选项。当一个 query 不需要从序列中任何特定部分提取信息时,它可以将大部分注意力权重分配给这个“空”令牌。
充当信息“垃圾桶”:这允许模型有效地执行“空操作”(No-Operation),即选择性地忽略当前上下文,而不是被迫整合不相关的信息。这在处理包含噪声或不重要元素的序列时特别有用。
- 作为“全局信息库” (Global Information Repository)
由于 null_kv 是一个可学习的参数,它不依赖于任何具体输入。在整个训练过程中,模型可以学会将一些全局的、与上下文无关的“知识”或“偏置”存储在 nv (null value) 中。
可学习的全局内存:任何位置的 query 都可以通过关注 nk (null key) 来从 nv 中读取这些存储好的全局信息。
类比:你可以把它想象成一个小的、可读写的“剪贴板”或“草稿纸”。模型在上面记录了一些普遍有用的信息(比如任务类型、通用特征等),序列中的任何令牌都可以随时查阅。