核心要点

  • Transformer 无循环/卷积结构,需显式注入位置信息。

  • 公式:PE(pos,2i)=sin(pos/10000^(2i/d)),PE(pos,2i+1)=cos(同一频率)。

  • 不同维度对应不同波长(频率几何衰减),便于模型表达相对位置。

  • 易错点:分母指数用 2i/d 且偶/奇维共享同一频率;用对数形式计算避免数值溢出。

标准回答

一、先把结论讲清楚

可以先说为什么需要它:Transformer 没有 RNNCNN 那种天然顺序结构,所以要显式注入位置信息

一、正弦位置编码怎么定义?

对位置 pos 和维度 i,偶数维用 sin,奇数维用 cos:PE(pos, 2i)=sin(pos / 10000^(2i/d)),PE(pos, 2i+1)=cos(pos / 10000^(2i/d))。

二、拆开机制和判断点

同一对偶/奇维共享同一个频率。

二、为什么用很多频率?

低维变化快,高维变化慢,等于用一组不同波长描述位置。这样模型既能感知短距离变化,也能表达较长距离关系。

三、实现时注意什么?

偶数维和奇数维要配对;分母指数是 2i/d_model

三、补上例子、边界和取舍

工程里常用 exp(-log(10000) * i / d_model) 来算频率,更稳定。下面用 NumPy 实现:

面试里可以补一句:手撕代码:实现正弦位置编码Positional Enco 在大模型场景下通常要同时权衡效果、延迟、成本和安全边界。回答时最好带一个例子,比如上下文过长、幻觉、缓存命中或工具调用失败时,系统应该如何降级和观测。

python
import numpy as np

def positional_encoding(seq_len, d_model):
    # 返回 (seq_len, d_model) 的正弦位置编码矩阵
    pos = np.arange(seq_len)[:, None]          # (L, 1)
    i = np.arange(0, d_model, 2)               # 偶数维索引 0,2,4,...
    # 用对数-指数形式计算频率,数值更稳定
    div = np.exp(-np.log(10000.0) * i / d_model)  # 1/10000^(2i/d)
    pe = np.zeros((seq_len, d_model))
    pe[:, 0::2] = np.sin(pos * div)            # 偶数维用 sin
    pe[:, 1::2] = np.cos(pos * div)            # 奇数维用 cos(同一频率)
    return pe

if __name__ == '__main__':
    pe = positional_encoding(seq_len=10, d_model=16)
    print(pe.shape)                            # (10, 16)
    print(pe[0, :4].round(3))                  # pos=0: sin=0, cos=1 交替

常见误区

⚠️ 常见踩坑

误区一:偶数维和奇数维频率没配对。 sin/cos 应该共享同一个频率。

误区二:指数写错。 公式里是 2i/d_model,对应实现时的偶数维索引。

追问

追问 1正弦位置编码相比可学习位置编码有什么优势?

正弦编码没有额外参数,而且是确定性函数,所以理论上 更容易外推到训练没见过的更长位置。可学习位置编码表达力强,但通常受最大长度限制。

追问 2RoPE 与正弦绝对位置编码有何不同?

RoPE 不把位置直接加到 embedding 上,而是在注意力里对 Q、K 做旋转,让点积自然包含相对位置信息。口头可以总结成:正弦位置编码是加法注入位置,RoPE 是在注意力匹配时注入相对位置

🔗 相似问题

同一考点的不同问法,换着练更稳

延伸学习

按主题分类的相关资源,便于系统复习