news 2026/8/11 14:48:30

ROPE编码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ROPE编码

参考:https://www.zhihu.com/tardis/bd/art/647109286

def apply_rotary_pos_emb(x: torch.Tensor, pos: torch.Tensor) -> torch.Tensor: """ apply rotary position embedding x: [b, num_heads, num_tokens, head_dim] pos: [b, num_tokens, 2] returns: [b, num_heads, num_tokens, head_dim] """ b, num_heads, num_tokens, head_dim = x.shape assert head_dim % 2 == 0, "head_dim必须为偶数。" rotary_dim = head_dim // 2 pos = pos.unsqueeze(1) # [b, 1, num_tokens, 2] freq_base = 10000.0 rotary_idx = torch.arange(rotary_dim, device=x.device, dtype=x.dtype) inv_freq = 1.0 / (freq_base ** (rotary_idx / rotary_dim)) # [rotary_dim] angle_x = pos[..., 0:1] * inv_freq # [b, 1, num_tokens, rotary_dim] angle_y = pos[..., 1:2] * inv_freq # [b, 1, num_tokens, rotary_dim] angle = angle_x + angle_y # [b, 1, num_tokens, rotary_dim] freqs_cis = torch.polar(torch.ones_like(angle), angle) # [b, 1, num_tokens, rotary_dim] x_ = x.reshape(*x.shape[:-1], -1, 2) # [b, num_heads, num_tokens, rotary_dim, 2] x_ = torch.view_as_complex(x_) # [b, num_heads, num_tokens, rotary_dim] x_rot = torch.view_as_real(x_ * freqs_cis).reshape(*x.shape[:-1], -1) # [b, num_heads, num_tokens, head_dim] return x_rot def apply_rotary_pos_emb_2d_split(x: torch.Tensor, pos: torch.Tensor) -> torch.Tensor: """ x: [b, h, t, d] pos: [b, t, 2], pos[..., 0]=x, pos[..., 1]=y return: [b, h, t, d] """ b, h, t, d = x.shape assert d % 4 == 0, "2D RoPE通常要求head_dim能被4整除" d_half = d // 2 # x-part / y-part d_quarter = d // 4 # complex pairs per axis x_pos = pos[..., 0] # [b, t] y_pos = pos[..., 1] # [b, t] inv_freq = 1.0 / ( 10000.0 ** (torch.arange(d_quarter, device=x.device, dtype=x.dtype) / d_quarter) ) # [d/4] angle_x = x_pos[:, None, :, None] * inv_freq[None, None, None, :] # [b,1,t,d/4] angle_y = y_pos[:, None, :, None] * inv_freq[None, None, None, :] # [b,1,t,d/4] freqs_x = torch.polar(torch.ones_like(angle_x), angle_x) # [b,1,t,d/4] freqs_y = torch.polar(torch.ones_like(angle_y), angle_y) # [b,1,t,d/4] x1 = x[..., :d_half] # [b,h,t,d/2] x2 = x[..., d_half:] # [b,h,t,d/2] x1_c = torch.view_as_complex(x1.reshape(b, h, t, d_quarter, 2)) # [b,h,t,d/4] x2_c = torch.view_as_complex(x2.reshape(b, h, t, d_quarter, 2)) # [b,h,t,d/4] x1_rot = torch.view_as_real(x1_c * freqs_x).reshape(b, h, t, d_half) x2_rot = torch.view_as_real(x2_c * freqs_y).reshape(b, h, t, d_half) return torch.cat([x1_rot, x2_rot], dim=-1)

a.主要是因为PE在原理上有一个问题,所以提出了RoPE
b.我们自然的想到,在LLM领域,有一个叫RoPE的东西,这是一种相对位置编码,也是在建模相对关系,只不过建模的是一个句子里,不同位置的单词之间的相对位置关系;
c.RoPE的特点就是,我在query/key上加入绝对特征(绝对位置),在attention的计算过程里,这种关系会巧妙地转变为相对位置特征,这和我们的目标不谋而合,这样,就省去了显示计算相对关系矩阵的开销
d.虽然在Attention is all you need里提出了上述正余弦对PE,但是在Bert, GPT等文章里仍然选择使用learnable PE,也即用一组初始化的可学习向量用作PE,而且效果看起来都要更好一些
e.因为PE的有一个原理上的问题

在q和k上增加了旋转,在v上面没有

Rope原理解析

核心原理,就是将attention中的qk矩阵相乘等价于复数相乘。而q中带上旋转角度,也是一个复数相乘。
从二维旋转矩阵推导出复数指数形式,是理解 RoPE 为何能高效实现“相对位置建模”的关键。我们可以分三步走:从矩阵乘法到复数乘法,再到欧拉公式。
第一步:二维旋转矩阵 (Matrix Form)在二维空间中,将一个向量x=[x1,x2]T\mathbf{x} = [x_1, x_2]^Tx=[x1,x2]T顺时针旋转θ\thetaθ角度,标准的旋转矩阵RθR_\thetaRθ定义为:Rθ=(cos⁡θ−sin⁡θsin⁡θcos⁡θ)R_\theta = \begin{pmatrix} \cos \theta & -\sin \theta \\ \sin \theta & \cos \theta \end{pmatrix}Rθ=(cosθsinθsinθcosθ)当我们把位置信息mmm注入 Query 向量qqq时:f(q,m)=Rmθ⋅q=(cos⁡mθ−sin⁡mθsin⁡mθcos⁡mθ)(q1q2)=(q1cos⁡mθ−q2sin⁡mθq1sin⁡mθ+q2cos⁡mθ)f(q, m) = R_{m\theta} \cdot q = \begin{pmatrix} \cos m\theta & -\sin m\theta \\ \sin m\theta & \cos m\theta \end{pmatrix} \begin{pmatrix} q_1 \\ q_2 \end{pmatrix} = \begin{pmatrix} q_1 \cos m\theta - q_2 \sin m\theta \\ q_1 \sin m\theta + q_2 \cos m\theta \end{pmatrix}f(q,m)=Rmθq=(cosmθsinmθsinmθcosmθ)(q1q2)=(q1cosmθq2sinmθq1sinmθ+q2cosmθ)第二步:映射到复数空间 (Complex Mapping)二维向量[q1,q2]T[q_1, q_2]^T[q1,q2]T可以完美映射到复平面上的一个复数q=q1+iq2q = q_1 + iq_2q=q1+iq2。同样地,旋转矩阵RmθR_{m\theta}Rmθ在复数空间中对应的是复数旋转算子eimθe^{im\theta}eimθ。根据复数乘法法则:(q1+iq2)⋅(cos⁡mθ+isin⁡mθ)(q_1 + iq_2) \cdot (\cos m\theta + i \sin m\theta)(q1+iq2)(cosmθ+isinmθ)展开得到:=(q1cos⁡mθ−q2sin⁡mθ)+i(q1sin⁡mθ+q2cos⁡mθ)= (q_1 \cos m\theta - q_2 \sin m\theta) + i(q_1 \sin m\theta + q_2 \cos m\theta)=(q1cosmθq2sinmθ)+i(q1sinmθ+q2cosmθ)你会发现,这个复数的实部和虚部,刚好对应第一步中旋转矩阵变换后的两个分量。所以:f(q,m)⟷q⋅eimθf(q, m) \longleftrightarrow q \cdot e^{im\theta}f(q,m)qeimθ第三步:计算内积与相对位置 (Dot Product)现在我们要计算位置mmmqqq和位置nnnkkk的内积。在向量空间中,内积是⟨q,k⟩\langle \mathbf{q}, \mathbf{k} \rangleq,k;而在复数空间中,两个复数向量的内积等于q⋅k∗q \cdot k^*qk的实部(Re\text{Re}Re)。带入旋转后的复数:⟨f(q,m),f(k,n)⟩=Re[(qeimθ)⋅(keinθ)∗]\langle f(q, m), f(k, n) \rangle = \text{Re} \left[ (q e^{im\theta}) \cdot (k e^{in\theta})^* \right]f(q,m),f(k,n)⟩=Re[(qeimθ)(keinθ)]利用共轭性质KaTeX parse error: Double superscript at position 13: (ab)^ = a^ b^̲以及(einθ)=e−inθ(e^{in\theta})^ = e^{-in\theta}(einθ)=einθ:**Re[q⋅eimθ⋅k∗⋅e−inθ]\text{Re} \left[ q \cdot e^{im\theta} \cdot k^* \cdot e^{-in\theta} \right]Re[qeimθkeinθ]指数合并:Re[q⋅k∗⋅ei(mθ−nθ)]=Re[q⋅k∗⋅ei(m−n)θ]\text{Re} \left[ q \cdot k^* \cdot e^{i(m\theta - n\theta)} \right] = \text{Re} \left[ q \cdot k^* \cdot e^{i(m-n)\theta} \right]Re[qkei(mθnθ)]=Re[qkei(mn)θ]

DROPE

Dynamic Rotary Positional Embedding(动态旋转位置编码)

. 为什么需要 “Dynamic” (D)?普通的 RoPE(如 Llama 中使用的)通常处理的是离散的整数索引(第 1 个词、第 2 个词……)。但在自动驾驶中,输入往往是连续的物理坐标(比如障碍物在 BEV 下的x=15.5m,y=3.2mx=15.5m, y=3.2mx=15.5m,y=3.2m)。DRoPE 的核心改进:连续性建模: 它不直接使用整数 index,而是将物理距离作为输入。动态频率缩放: 为了让模型能处理更广阔的感知范围(比如从 50 米扩展到 200 米),它会动态调整旋转的基底频率(Base Frequency),这类似于大语言模型中的 NTK-aware Scaling。2. DRoPE 在 2D/3D 空间中的运作在你之前的代码逻辑中,角度是x⋅θ+y⋅θx \cdot \theta + y \cdot \thetaxθ+yθ。DRoPE 可能会引入自适应权重:Angle=fscale(dist)⋅(x⋅θx+y⋅θy)\text{Angle} = f_{scale}(dist) \cdot (x \cdot \theta_x + y \cdot \theta_y)Angle=fscale(dist)(xθx+yθy)通过这种方式,模型可以:感知距离的非线性: 远处的障碍物对当前规划的影响应该逐渐减弱,DRoPE 可以通过旋转频率的控制,让远距离的向量在内积时自然产生更大的衰减。坐标系对齐: 动态地根据自车的速度(Ego-speed)或朝向调整编码相位,保持空间的一致性。

# 伪代码:引入动态缩放 dist = torch.norm(pos[..., :2], dim=-1, keepdim=True) # 根据距离动态调整频率基数,例如距离越远,旋转越慢(保留更多全局信息) dynamic_inv_freq = inv_freq / (1 + torch.log(1 + dist)) angle_x = pos[..., 0:1] * dynamic_inv_freq angle_y = pos[..., 1:2] * dynamic_inv_freq
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 15:39:29

Jazzer进阶:自定义sanitizers开发指南与最佳实践

Jazzer进阶:自定义sanitizers开发指南与最佳实践 【免费下载链接】jazzer 项目地址: https://gitcode.com/gh_mirrors/ja/jazzer Jazzer是一款强大的Java模糊测试工具,通过自定义sanitizers可以显著提升漏洞检测能力。本文将深入探讨如何开发自定…

作者头像 李华
网站建设 2026/7/14 15:39:30

基于鱼群算法的单目标工艺参数最优化-响应面(RSM)附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码及仿真咨询…

作者头像 李华
网站建设 2026/7/14 15:39:45

SpongeAPI完全指南:从零开始构建你的Minecraft插件帝国

SpongeAPI完全指南:从零开始构建你的Minecraft插件帝国 【免费下载链接】SpongeAPI A Minecraft plugin API 项目地址: https://gitcode.com/gh_mirrors/sp/SpongeAPI SpongeAPI是一个强大的Minecraft插件开发接口,它为开发者提供了创建自定义插件…

作者头像 李华
网站建设 2026/7/14 15:39:42

Front-End Checklist安全检查清单:防范XSS和CSRF攻击的最佳实践

Front-End Checklist安全检查清单:防范XSS和CSRF攻击的最佳实践 【免费下载链接】Front-End-Checklist 🗂 一份完美的前端开发清单——专为现代网站和追求极致的开发者打造 项目地址: https://gitcode.com/gh_mirrors/frontendche/Front-End-Checklist…

作者头像 李华
网站建设 2026/7/14 15:39:43

解锁GitHub Actions新效能:macOS 14 ARM64镜像深度解析与应用指南

解锁GitHub Actions新效能:macOS 14 ARM64镜像深度解析与应用指南 【免费下载链接】runner-images actions/runner-images: GitHub官方维护的一个仓库,存放了GitHub Actions运行器的镜像文件及相关配置,这些镜像用于执行GitHub Actions工作流…

作者头像 李华