ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

旋转:IMRoPE朴素

2026/8/9 4:01:24 拓冰建站 浏览量
旋转:IMRoPE朴素

IMRoPE朴素.h

// IMRoPE朴素.h —— 多模态分段旋转位置编码(IMRoPE)的朴素标量实现// 用途:给 Q/K 向量注入位置信息的旋转位置编码,支持多模态的 4 段频率划分(文本/图像/视频/其他)// 说明:M1 朴素实现——逐对惰性计算 cos/sin,不建缓存;为后续 AVX-512 优化(M2)提供教学对照// 数学公式(纯文本,标准 RoPE + IMRoPE 段划分):// 标准 RoPE 对第 k 对维度 (x[2k], x[2k+1]) 旋转角度 θ_k:// x'[2k] = x[2k]·cos θ_k − x[2k+1]·sin θ_k// x'[2k+1] = x[2k]·sin θ_k + x[2k+1]·cos θ_k// θ_k = pos / base^(2k/d) (d = 段内维度数,pos = token 位置)// IMRoPE 分段:头部维度按每 64 维划分为一段,第 s 段的基数为 频率基数 × 段频率基数[s],// 段内按标准 RoPE 旋转(段内第 j 对的指数为 2j/64)#pragmaonce// 引入基础类型(浮点/向量/索引)#include"公共/基础定义.h"// 引入错误处理(参数防御时抛运行错误)#include"公共/错误处理.h"// 每段维度:IMRoPE 固定将头部按每 64 维划分为一段// 说明:qwen35moe 头部维度 256 = 4 段 × 64 维,对应 4 个段频率缩放constexprsize_t 每段维度=64;// RoPE配置:旋转位置编码的可配置参数// 字段:频率基数 = 基准频率基数(qwen35moe 为 1e7);// 段频率基数 = 每段的频率缩放(IMRoPE 为 4 段),第 s 段的实际基数为 频率基数 × 段频率基数[s];// 旋转维度 = 参与旋转的前缀元素数(qwen35moe 为 64,后 192 维不旋转)// 说明:段频率缩放 0 表示该段不旋转(qwen35moe 段3 缩放为 0);具体模型段缩放值在任务 13 集成时确定structRoPE配置{浮点 频率基数;向量<浮点>段频率基数;size_t 旋转维度;};// IMRoPE朴素:多模态分段旋转位置编码,就地旋转向量前 配置.旋转维度 个元素// 参数:向量 = 头部 Q/K 向量(容量 ≥ 头维度);头维度 = 向量元素总数;// 位置 = token 位置编号;配置 = 频率基数 / 段缩放 / 旋转维度// 说明:仅处理前 配置.旋转维度 个元素,按 2 维度一对旋转;// 每 64 维切换段频率(见 每段维度),段内按标准 RoPE 逐对旋转;// 段缩放 ≤ 0 时该段不旋转voidIMRoPE朴素(float*向量,size_t 头维度,size_t 位置,constRoPE配置&配置);

IMRoPE朴素.cpp

// IMRoPE朴素.cpp —— 多模态分段旋转位置编码(IMRoPE)朴素实现的实现文件// 数学(纯文本):// 标准 RoPE:θ_k = pos / base^(2k/d),旋转公式:// x'[2k] = x[2k]·cos θ_k − x[2k+1]·sin θ_k// x'[2k+1] = x[2k]·sin θ_k + x[2k+1]·cos θ_k// 多模态分段:头部按每 64 维划分为 4 段,第 s 段基数 = 频率基数 × 段频率基数[s],// 段内第 j 对的旋转角度 θ = pos / 段基数^(2j/64)#include"内核/旋转/IMRoPE朴素.h"// 引入标准头:余弦/正弦/幂(逐对计算 cos/sin 与 基数^指数)#include<cmath>// IMRoPE朴素:就地旋转向量前 配置.旋转维度 个元素// 实现:防御校验 → 逐对旋转;每对独立计算 cos/sin(惰性,不建缓存——M1 朴素);// 每 64 维切换段频率;段缩放 ≤ 0 时该段跳过voidIMRoPE朴素(float*向量,size_t 头维度,size_t 位置,constRoPE配置&配置){// 防御:旋转维度不得超过头部维度,否则旋转会越界写内存if(配置.旋转维度>头维度){抛出运行错误("旋转维度超出头部维度");}// 防御:旋转按 2 维度一对进行,旋转维度必须是偶数if(配置.旋转维度%2!=0){抛出运行错误("旋转维度必须是偶数");}// 对数:旋转维度内按 2 维一对的旋转对数constsize_t 对数=配置.旋转维度/2;// 逐对旋转:每对角度独立计算(惰性 cos/sin)for(size_t 对号=0;对号<对数;++对号){// 当前对覆盖的起始维度号(2 维一对)constsize_t 维号=2*对号;// 段号:每 64 维切换一段(IMRoPE 固定段宽 每段维度)constsize_t 段号=维号/每段维度;// 防御:段号超出配置的段频率数组时抛错(配置须覆盖旋转触及的每一段)if(段号>=配置.段频率基数.size()){抛出运行错误("段频率基数不足:段号超出配置");}// 段内对号:当前对在所属段内的序号(0..每段维度/2-1)constsize_t 段内对号=(维号%每段维度)/2;// 该段实际基数 = 频率基数 × 段缩放(双精度计算避免浮点舍入)const长浮点 段基数=(长浮点)配置.频率基数*(长浮点)配置.段频率基数[段号];// 段缩放 ≤ 0 表示该段不旋转(如 qwen35moe 段3 缩放 0),直接跳过if(段基数<=0.0){continue;}// 旋转角度:θ = 位置 / 段基数^(2×段内对号/每段维度)(双精度减小误差)const长浮点 角度=(长浮点)位置/std::pow(段基数,(长浮点)(2*段内对号)/每段维度);// 惰性计算本对的 cos/sin(M1 朴素,不建缓存)const长浮点 余弦=std::cos(角度);const长浮点 正弦=std::sin(角度);// 先取原始两维(避免就地更新时第二维已污染第一维的计算)const长浮点 原第零维=向量[维号];const长浮点 原第一维=向量[维号+1];// 标准 RoPE 旋转公式(就地写入)向量[维号]=(浮点)(原第零维*余弦-原第一维*正弦);向量[维号+1]=(浮点)(原第零维*正弦+原第一维*余弦);}}