我第一次看到“动态 NTK”这个名字时,满脑子都是问号:这跟神经网络训练里的神经正切核(Neural Tangent Kernel)有什么关系?
答案很简单:跟神经正切核理论没有任何关系。它是本地 LLM 社区昵称 emozilla 的开发者,在 Reddit 的 r/LocalLLaMA 上发帖提出的方案,目的是把 Llama 这类模型的上下文从 2048 硬拉到 8192、16384 甚至更长。因为零成本又有效,它很快被各大推理框架集成。
几个月后,Meta AI 和 EleutherAI 的研究者发表了YaRN 论文,把这类缩放方法的原理拆了个干净,并提出一套更系统的方案。于是你在很多文章里会看到一句话:YaRN 是动态 NTK 的升级版。
但我把两者的公式放在一起看时,发现这个说法掩盖了太多细节。它们面对同一个问题,答案却不在同一个维度上。

RoPE 究竟在旋转什么
在 LLaMA 这类使用旋转位置编码(RoPE)的模型里,位置信息不是加一个位置向量,而是把每个位置的词向量旋转一个角度。你不需要啃完整套矩阵运算,只需要抓住一个核心:每个维度都有自己的旋转速度。
第 i 个维度的速度是
θ_i = base^(-2i/d) 其中 base = 10000
这里 d 是每个注意力头的维度,i 从 0 取到 d/2−1。i 越小,转速越快,称为高频分量;i 越大,转速越慢,称为低频分量。
可以想象一块面板上装了好几十根转速不同的指针:秒针是高频,时针是低频。两个 token 的位置差,就是这些指针转过的角差。模型就是靠读这些角差,判断“这俩词隔着多远”。RoPE 的精妙之处在于,位置信息不是加到向量里,而是乘(旋转)进去的,这让它天然拥有更好的外推潜力。
直接拉长为什么崩:高频转圈,低频迷路
模型预训练时见过的最大位置差是 L(比如 LLaMA-2 是 4096)。你强行让它处理 8 倍的距离,会发生什么?
高频分量转得太快,在 L 的训练范围里已经转了很多圈。距离拉到 8 倍后,它照常转圈,但外推距离对应的旋转角,跟训练范围内某个短距离的旋转角是一模一样的(模 2π)。模型无法区分那个角差到底是远距离还是近距离——高频信息混叠了。
低频分量正好相反,转速太慢,在训练范围里可能连一圈都不到。8 倍距离后,它转到了从未出现过的刻度上。模型对这个角差没有任何先验,自然只能瞎猜。
一个是转圈转到认不出,一个是走到从没走过的刻度。两种崩溃方式完全不同,所以治它们的方案也注定不同。
动态 NTK:一个 Reddit 帖子的逆袭
早期统一方案是线性插值(PI):把位置距离除以缩放因子 α,把 8 倍的距离压回训练范围。缺点是高频也被压扁——高频是分辨相邻 token 精细位置的关键,你一压它,连短距离的感知都模糊了,而且固定缩放对短输入也不公平。
NTK 的思路是:不压缩位置本身,而是扩大 base。原始代码的核心就两行:
alpha = max(1, cur_len / train_len)
new_base = base * alpha ** (dims / (dims - 2))
替换 base 之后,每个维度的实际旋转速度变为
θ'_i = θ_i * alpha^(-2i/(d-2))
看两端:最高频 i=0 处的缩放系数是 1,也就是完全不缩放;最低频处缩放约等于 1/α,等于完全线性插值。中间维度平滑过渡。
说人话:高频继续外推,低频做插值,连续过渡。这比“一刀切压缩”精细太多了。
“动态”的含义在最后一行:α 不是预先写死的,而是推理时根据当前序列长度实时计算。短输入保持原速,长输入才放大 base。这也是它无需微调就能用的关键原因。
YaRN:高频不该动,低频才能压
但 YaRN 的作者们看完这类方案后,觉得 NTK 还不够彻底。NTK 对高频只是“少缩”,不是“不缩”。高频既然本来就是一圈圈混叠的分量,任何一点速度改动,都会进一步破坏模型对相邻位置的精细分辨。
YaRN 的 NTK-by-parts 方案把频率分成三段:
- 高频段:旋转周期远短于训练长度的维度,彻底不缩放,继续外推。
- 低频段:旋转周期接近甚至超过训练长度的维度,完全线性插值。
- 过渡段:介于两者之间,用斜坡函数把两种策略平滑衔接。
判别标准也很直觉:高频在训练范围里已经绕了不知道多少圈,多绕几圈不会造成额外伤害;低频在训练范围里是接近一一对应的,一旦超出,模型就面对完全陌生的角度。所以高频该外推,低频该插值。
这句话看起来简单,实则是整个 YaRN 的核心论断。
光改几何还不够,还得校准注意力分布
我最初读 YaRN 论文时,注意力全在分段缩放上,直接把温度补偿那一节跳过了。直到自己动手推导插值后注意力 logits 的变化,才意识到问题有多严重。
一旦旋转速度被放慢,相邻位置的角差缩小,注意力得分的分布被拉平,softmax 输出变得犹豫——最可能的词跟次可能的词差距缩小,输出质量肉眼可见下降。动态 NTK 没有管这件事,YaRN 管了:
t = sqrt(1 + ln(256 * L_new / 4096))
这个温度系数重新锐化注意力 logits,把被插值抹平的分布重新拉开。公式里的 4096 是预训练长度,换模型要跟着改。它看起来不起眼,却是 YaRN 区别于所有 NTK 变体的关键一层:不光管旋转几何,还管注意力分布的统计形状。
本质区别:一条连续缩放曲线 vs 一次分段决策
把两个方案放在同一张表里看,区别一目了然。
| 对比维度 | 动态 NTK | YaRN |
|---|---|---|
| 出身 | Reddit 社区方案 | Meta AI + EleutherAI 论文 |
| 缩放策略 | 连续:所有维度都缩放,高频幅度小、低频幅度大 | 分段:高频完全不动,低频全量插值,中间斜坡衔接 |
| 缩放依据 | 固定的频率指数曲线(经验设计) | 基于“周期 vs 训练长度”的信息论判断 |
| 动态与否 | 核心卖点:推理时按当前长度实时计算 | 论文主线是静态缩放;附录提供动态版本 |
| 注意力补偿 | 无 | 有温度系数重新锐化 |
| 微调要求 | 完全不需要 | 小倍率可不微调;大倍率强烈依赖微调 |
| 典型上限 | 直用约 2–4 倍 | 配合微调可达 64–128 倍 |
动态 NTK 的视角是:每个维度都该缩,只是幅度不同。它设计了一条从 1 到 1/α 的平滑缩放曲线,本质上是一个“数值补偿技巧”。
YaRN 的视角是:有些维度根本不能缩,有些维度必须缩。它先回答“哪些信息可以被牺牲,哪些必须保留”,再回答“怎么缩”。这不是公式差异,而是对问题的定义方式不同。
那实际用哪个?我的判断
如果只是临时把本地模型从 2048 拉到 4096,动态 NTK 依然是最优选:零成本、无微调、短输入零损失。它像一个聪明的补丁。
但如果你要把上下文真正拉到 16 倍、64 倍,在绝大多数情况下,任何“推理时缩放”都撑不住。YaRN 能达到 128k 乃至 192k,靠的不只是缩放公式,还有配合使用的微调。你应该把 YaRN 当成扩展上下文的基础设施,而不是神奇开关。
最后提醒一句:很多推理框架里已经内置了 rope_scaling 参数,里面的 dynamic 选项就是动态 NTK。把值调到 128k 不会让模型真的理解 128k 内容,它只是把刻度盘扩得很大。模型能否读懂刻度,取决于训练时有没有见过类似长度的文本。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/760.html