LLM 神经解剖学:不改权重登顶 AI 排行榜

2024 年中,HuggingFace Open LLM 排行榜是开源 AI 模型的竞技场。数千个模型在此角逐,参与者既有资金雄厚、博士云集的实验室,也有擅长微调、能起出各种奇幻名字的模型巫师(比如 Nous-Hermes、Dolphin、NeuralBeagle14-7B...)。它们争夺着六个基准测试(IFEval、BBH、MATH Lvl 5、GPQA、MuSR、MMLU-PRO)的榜首位置。
而当时排名第一的,是 dnhkng/RYS-XLarge。我的模型。
我没有训练新模型,没有合并权重,甚至没有运行过一步梯度下降。我做的要奇怪得多:我拿了一个现成的 720 亿参数模型,复制了其中间特定的一个由七层组成的模块,然后把结果缝合回去。整个过程没有修改任何权重。模型只是获得了更多用于思考的层。
这就是 LLM 神经解剖学(LLM Neuroanatomy)的发现故事。两个奇怪的观察,一个自制的 Transformer“大脑扫描仪”,加上在地下室数月的钻研,最终让我窥见了 AI 的内部结构。这个发现直到现在才公之于众*。
- ——因为我发现写博客比写科学论文有趣多了,而且我可以带你一步步了解这个发现是如何诞生的。
让我们从头说起,这个项目是怎么开始的。
“科学中最令人兴奋、预示着新发现的短语,不是‘我找到了!’,而是‘这有点意思……’”——艾萨克·阿西莫夫
线索一:你可以用 Base64 和 LLM 聊天
2023 年底,我在琢磨一个奇怪的大语言模型特性。你自己也可以试试——随便拿个问题,比如:
What is the capital of France? Answer in Base64!
把它编码成 Base64,得到一串不可读的字符串:
V2hhdCBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2U/IEFuc3dlciBpbiBCYXNlNjQh
把这个发给一个 2023 年的非推理型大语言模型(更新的推理模型会识别出这是 Base64,然后“作弊”使用工具调用)。但一个能力足够的 2023 年模型会回复类似这样的内容:
VGhlIGNhcGl0YWwgb2YgRnJhbmNlIGlzIFBhcmlzLg==
解码后是:“The capital of France is Paris.”(法国的首都是巴黎)。
好吧,我承认。我当时玩这个是为了尝试越狱模型(而且成功了),但我脑子里一直挥之不去一个想法。
模型解码了输入,以某种方式理解了它,并且在 Transformer 堆栈的前向传播过程中,还有时间重新编码它的回答。它看起来真的能在 Base64 接口下思考。这对于复杂问题、多步推理甚至创意任务都有效。
这效果不应该这么好。诚然,模型在整体上训练时见过大量 Base64,但这种格式的通用转换肯定远远超出了其训练分布。分词器(Tokenizer)会把它切成完全不同的子词单元。位置模式也无法识别。但它就是能工作……有意思……
我无法停止思考这个问题。如果一个 Transformer 能接受英语、Python、中文和 Base64,并在所有这些格式中产生连贯的推理,那么在我看来,早期层一定扮演着翻译器的角色——将到达的任何格式解析成某种纯粹、抽象的内部表示。而后期层则扮演着再翻译器的角色,将那种抽象表示转换回所需的任何输出格式。
如果早期层负责读取,后期层负责写入,那么中间层在做什么?
纯粹的抽象推理?在一个与任何人类语言或编码都无关的表示中进行。当然,当时这只是闲来无事的猜测。有趣,但没有明确的方法来测试,甚至无法定义一个有效的假设。
线索二:Goliath 异常
2023 年 11 月,一位名叫 Alpindale 的 HuggingFace 用户发布了 Goliath-120b——一个由两个微调过的 Llama-2 70B 模型缝合而成的弗兰肯合并模型,拥有 1200 亿参数的庞大体量。
它的性能不错,但经过大量“感觉检查”后,我并不觉得这是个突破。但它的构造方式太疯狂了。
Alpindale 并没有简单地将两个模型(Xwin 和 Euryale)首尾相接堆叠起来。他是在它们之间交替使用层。更重要的是,这种架构将后面层的输出反馈到前面层的输入。
使用的层范围如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - range 0, 16 Xwin - range 8, 24 Euryale - range 17, 32 Xwin - range 25, 40 Euryale - range 33, 48 Xwin - range 41, 56 Euryale - range 49, 64 Xwin - range 57, 72 Euryale - range 65, 80 Xwin
你看到这里的疯狂之处了吗?Alpindale 真的把 Xwin 第 16 层的输出,喂给了 Euryale 第 8 层的输入!
为了更清楚地解释这看起来有多离谱,让我们回顾一下万能的 Transformer 架构:
看图的左侧,我们看到内容从底部进入(被“分块”成小段文本的“输入”文本,介于整个单词到单个字母之间),然后向上流过模型的 Transformer 块(图中标记为 [1, …, L]),最后,模型吐出下一个文本“块”(然后它本身被用于下一轮推理)。在这些 Transformer 块中实际发生的事情相当神秘。弄清楚它实际上是 AI 的一个完整领域——“机制可解释性”。
- ——是的,这比那更复杂,还有采样器等等,但本文了解这些就够了。
看图的右半部分右侧,你看到那条从“Transformer Block Input”指向 (⊕) 符号的箭头线了吗?这就是为什么跳过层是有道理的。在训练期间,大语言模型几乎可以决定在任何特定层什么都不做,因为这条“绕行”路线将信息绕过了该块。所以,“后面”的层可以预期看到“前面”层的输入,甚至是几步之前的输入。大约在这个时候,有几个小组正在尝试通过移除层来“精简”模型。这说得通,但很无聊。
机器学习中有一个相当基本的真理:
- 模型必须用与训练时相同类型的东西来使用(我们保持“在分布内”)。
- 对于每个 Transformer 层也是如此。每个 Transformer 层在训练期间通过梯度下降学习,以期望前一层的输出具有特定的统计特性。
现在来看奇怪的地方:从来没有出现过任何 Transformer 层会看到来自未来层输出的情况!
第 10 层是在第 9 层输出的分布上训练的。第 60 层是在第 59 层输出的分布上训练的。如果你重新排列它们——把第 60 层的输出喂给第 10 层——你就创造了一个模型在训练期间从未见过的分布。
Goliath 令人震惊的地方不在于它的性能有了巨大飞跃,而在于这玩意儿居然能正常工作。直到今天,我仍然不明白为什么这没有引起更多人的注意。
实验证明,层的互换性远远超出了任何人有理由预期的程度。内部表示足够同质化,以至于模型能够消化乱序的隐藏状态而不崩溃。架构远比僵化的流水线灵活。
结合 Base64 的观察和 Goliath,我有了一个假设:Transformer 具有真正的功能解剖结构。早期层将输入翻译成抽象表示。晚期层翻译回输出。而中间层,即推理皮层,在一个通用的内部语言中运作,这种语言对架构重排具有鲁棒性。Goliath 120B 的层块大小为 16 层,这让我怀疑输入和输出“处理单元”的大小小于 16 层。我猜测 Alpindale 尝试过更小的重叠,但它们就是不起作用。
如果这是真的,也许我不需要教模型新知识来让它更聪明。我不需要微调。我不需要 RLHF。我只需要给它更多用来思考的层。
接下来的几个月——从2023年底到2024年中——我搭建了一套流水线来验证这个假设。
设备很简单。地下室那台机器学习主机里插了两块RTX 4090,通过ExLlamaV2运行量化模型,硬是把720亿参数的大模型塞进了消费级显卡的显存里。这个方法妙就妙在:你完全不需要训练任何东西,只需要跑推理就行。而量化模型的推理,消费级GPU处理起来意外地给力。只要模型能装进显存,我发现我的4090性能经常能跟H100打个平手。
原理很简单。对于一个有 $N$ 层的模型,我定义一个配置 $(i, j)$。模型先正常处理第 $0$ 层到第 $j{-}1$ 层,然后循环回去,把第 $i$ 层到第 $j{-}1$ 层再跑一遍,接着继续处理剩下的层直到第 $N{-}1$ 层。也就是说,$i$ 到 $j{-}1$ 这几层在执行路径上被重复使用了。权重没变,模型只是把某些层走了两遍。
举个例子,对于一个有9个Transformer块的模型,配置 (2, 7) 的计算路径是这样的:
1 2 3 4 5 6 7 8 Example: (i, j) = (2, 7)
0 → 1 → 2 → 3 → 4 → 5 → 6 ─┐
┌─────────────────────┘
└→ 2 → 3 → 4 → 5 → 6 → 7 → 8
duplicated: [2, 3, 4, 5, 6]
path: [0, 1, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 7, 8]
遍历所有可能的 $(i, j)$ 组合,我们就能生成一张“大脑扫描图”,同时也能看到每个配置对应的重复层数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Number of duplicated layers for configuration (i, j), with N=9
end j →
0 1 2 3 4 5 6 7 8 9
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
start 0 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
i ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
↓ 1 │ . │ . │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
2 │ . │ . │ . │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
3 │ . │ . │ . │ . │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
4 │ . │ . │ . │ . │ . │ 1 │ 2 │ 3 │ 4 │ 5 │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
5 │ . │ . │ . │ . │ . │ . │ 1 │ 2 │ 3 │ 4 │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
6 │ . │ . │ . │ . │ . │ . │ . │ 1 │ 2 │ 3 │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
7 │ . │ . │ . │ . │ . │ . │ . │ . │ 1 │ 2 │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
8 │ . │ . │ . │ . │ . │ . │ . │ . │ . │ 1 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
where (0,0) is the original model
对于Qwen2-72B这种80层的模型,意味着有3240个有效的 $(i, j)$ 组合,再加上原始模型本身需要测试。
[\begin{aligned} \text{Variants}{\text{total}} &= \left(\sum{j=0}^{80} j\right) + 1\[16pt] &= \frac{80 \cdot 81}{2} +1 \[10pt] &= 3241 \end{aligned}]
如果对每个重分层模型都跑一遍排行榜的六个基准测试,那得花上好几天。在我的设备上,完整扫一遍需要超过十年的算力。所以我需要代理任务:那些速度快、目标明确,并且能揭示模型结构特性而非特定任务技巧的探针。
这些代理任务必须满足三个条件:
- 输出Token要少。几千个配置要扫,每个评估都得快。不能写文章,不能搞长篇生成。
- 评分要明确。我负担不起LLM-as-judge(大语言模型作为裁判)的流水线。答案必须能客观打分,不能再套一个模型进来。
- 认知需求要正交。如果一个配置能同时提升两个任务的表现,那说明是结构性的提升,而不是针对某个任务的小聪明。
失败探针的坟场
我没能立刻找到合适的探针,这花了几个月试错,踩了不少坑。
我的第一反应是测创造力。让模型生成诗歌、短篇小说、隐喻,这种丰富、开放式的输出,感觉应该能揭示认知能力的深层差异。我用LLM-as-judge来给输出打分,但结果很糟糕。后来我通过一些工程手段修复了LLM-as-judge,这套评分系统在其他地方派上了用场,所以这里也提一下:
注:这部分有数学,你可以跳过。
简单的LLM裁判很不稳定。同一首诗跑两次,得分不一样(显然,因为采样)。但调低温度也没太大帮助,这只是众多技术问题之一。于是,我基于logits输出的细节,开发了一套完整的评分系统。这里面的门道还挺多。想想一个1-10分的评分:
- 我们期望一个校准良好的模型,其logits是合理的。如果权重最高的是‘7’,我们是不是期望剩下的权重集中在‘6’和‘8’上?但实际情况往往是双峰的,权重在‘6’和‘5’上很低,但在‘4’上的权重却比预期高!
- ‘10’这个分数可以用token表示为‘10’,或者‘1’后面跟‘0’。如果要计算1-100分的概率路径总和,那可一点也不好玩。
与其采样一个离散的分数,我把裁判的输出视为有效评分标签上的一个分布,然后计算其期望值作为最终得分。
为了让这方法可行,我首先为数字0-9(每个数字只有一个token)定义了一个校准过的评分标准,每个数字对应一个清晰的定性描述。在评分步骤,我捕获模型的下一个token的logits,只保留那些对应有效数字token的logits。这样就避免了无关续写(比如解释文字、标点或不同格式)的干扰。在限制的数字集上重新归一化后,我将得到的概率解释为一个分类的分数分布。
形式化地,设有效分数集为
[\mathcal{D} = {0,1,2,\dots,9}.]
令 $(z_k)$ 表示在评分位置模型分配给数字 $(k \in \mathcal{D})$ 的logit。那么限制后的分数分布为
[p(k)= \frac{\exp(z_k)} {\sum\limits_{m \in \mathcal{D}} \exp(z_m)}, \qquad k \in \mathcal{D}.]
最终的标量分数是这个分布的期望值:
[\hat{s}= \sum_{k \in \mathcal{D}} k,p(k).]
这会产生一个平滑的分数,比如5.4,而不是强迫模型给出一个采样得到的整数。实际上,这比简单的分数采样要稳定得多,也更能反映模型的不确定性。它还能处理分布很宽或多峰的情况。例如,两个候选答案的平均分可能都是5.4,但一个的质量主要集中在5和6附近,另一个则把质量分散在更低和更高的评分上。单看平均值是一样的,但背后的判断却截然不同。
一个可选的不确定性估计可以从限制分布的方差得到:
[\mathrm{Var}(s)= \sum_{k=0}^{9} (k-\hat{s})^2,p(k).]
简而言之,这个方法用一个归一化的有效分数数字概率分布,取代了嘈杂的采样裁判分数,然后用这个分布的期望值作为最终评分。
现在看这些东西可能挺明显的,但在‘24年那会儿,可没什么资料指导我开发这个方法。可惜的是,我发现它完全没用……
又快又狠的测试
每个配置都需要生成数百个token的创意输出,然后还得用另一个模型来阅读和评判。对于一个700亿参数的模型,超过3200个配置要测试,在我的双4090上得花好几周。
我需要那种输出极小(最多几个token)、评分客观且确定的探针。不能有裁判模型参与。这让我找到了最后两个探针:
硬核数学题。那种难到离谱的问题,比如:“74,088,893,247的立方根是多少?” 不允许思维链,不能用工具。就纯靠直觉猜,直接输出数字。
情商测试。用EQ-Bench基准:复杂的社交场景,模型必须预测特定情绪状态的强度。“给定这个情境,这个人会感到多愤怒/惊讶/内疚(0-100分)?” 这跟数学完全不同。涉及心理理论、社交推理、共情。输出就是几个数字。
我最终选定了两个认知需求最大程度正交的任务,输出都很小。我的直觉是:LLM是一个token一个token地思考,那就让模型在猜下一个token上变得特别牛。但事情从来不会一帆风顺。就拿LLM做算术来说……
LLM的算术很诡异
即使是数学探针,我也遇到了意想不到的问题。LLM做算术出错的方式很诡异。它们不是答案完全错,而是几乎对了,却忘了写最后一位数字,好像写到一半就烦了。或者把中间两位数字调换了。或者输出了正确的数字,但后面跟了个字符,导致解析失败。
这很可能是因为大数字被token化的方式,大数字可能被任意拆分。拿整数123456789来说,一个BPE分词器(比如GPT风格的)可能会把它分成:‘123’ ‘456’ ‘789’,或者:‘12’ ‘345’ ‘67’ ‘89’。
一个简单的对/错评分系统会丢掉有用的信号。计算百分比正确率会好点:‘123356789’ 而不是 ‘123456789’,这样正确率是99.92%。
但如果一个模型犯了典型的“LLM式错误”,输出 430245 而正确答案是 4302459,明明大部分工作都做对了呢?我写了一个自定义的部分信用评分函数,会对较短的答案进行填充并按比例扣分:
def calculate_score(actual, estimate):
"""Calculate score comparing actual vs estimated answer."""
try:
actual_str = str(int(actual))
estimate_str = str(int(estimate))
except (ValueError, OverflowError):
return 0
max_length = max(len(actual_str), len(estimate_str))
actual_padded = actual_str.ljust(max_length, "0")
estimate_padded = estimate_str.ljust(max_length, "0")
padding_size = max_length - min(len(actual_str), len(estimate_str))
actual_int = int(actual_padded)
estimate_int = int(estimate_padded)
if max(actual_int, estimate_int) == 0:
return 0
relative_diff = abs(actual_int - estimate_int) / max(actual_int, estimate_int)
correction_factor = 1 - (padding_size / max_length)
score = (1 - relative_diff) * correction_factor
return max(0, min(score, 1))
核心思路是:填充较短的答案,然后通过修正因子扣分。一个模型如果答对了90%的数字,只是漏了最后一位,仍然能得到可观的分数——但比答对所有数字的模型要低。事实证明,这对于区分那些在直觉数学能力上相近的配置至关重要。
数学题最初是手工设计的。我尝试了不同的运算和规模,然后用随机数填充数据集。数据集包含16个问题,模型的任务是猜出最接近的整数。这里有几个例子,你可以自己试试,记住不能“思考”,直接猜!
What is 78313086360375 multiplied by 88537453126609?
What is the cube root of 18228885506341?
What is the cube root of 844178022493, multiplied by 43?
测试完几个小模型(Llama 系列和更小的 Qwen2)后,我配置好 Qwen2-72B,让它开始扫描。每个 $(i, j)$ 配置都要花几分钟:加载重分层模型,运行数学探针,运行 EQ 探针,记录分数,继续下一个。在 4090 上连续跑了好几天 GPU 时间。但这比微调需要的算力少多了!实际上,我连在 48GB VRAM 上做 LORA 微调的硬件都没有。
最优配置是 $(45, 52)$:先运行第 0 到 51 层,再运行第 45 到 79 层。第 45 到 51 层执行了两次。在 80 层堆栈的中间位置,多跑了七层,总参数量从 72B 增加到 78B。每层额外层都是现有层的精确副本。没有新权重或训练,只是模型在重复自己。
重复七层。就这么简单,现在我终于可以揭晓模型命名的由来:Repeat Your Self,所以叫 RYS-XLarge ;)
我把这个配置应用到 MaziyarPanahi 的 calme-2.1-qwen2-72b —— 这是 Qwen2-72B 的一个微调版本 —— 然后把结果上传为 dnhkng/RYS-XLarge。我也把它应用到原始基础模型,作为 dnhkng/RYS-XLarge-base。
然后我提交到 Open LLM Leaderboard,开始等待。等了好久。以前 OpenLLM Leaderboard 每天都被几十个微调或合并模型淹没(简直是西部荒野),等待列表很长。但大约一个月后,结果出来了:
| 指标 | RYS-XLarge | 相比基础模型的提升 |
|---|---|---|
| 平均分 | 44.75 | +2.61% |
| IFEval (0-Shot) | 79.96 | -2.05% |
| BBH (3-Shot) | 58.77 | +2.51% |
| MATH Lvl 5 (4-Shot) | 38.97 | +8.16% |
| GPQA (0-shot) | 17.90 | +2.58% |
| MuSR (0-shot) | 23.72 | +17.72% |
| MMLU-PRO (5-shot) | 49.20 | +0.31% |
MuSR 提升 17.72%。MATH 提升 8.16%。六个基准测试中有五个都进步了,只有 IFEval 小幅下降。平均分让它登上了排行榜第一。
再强调一遍:我只针对单次猜测数学难题和 EQ-Bench 做了优化。 开发过程中我根本没看 IFEval、BBH、GPQA、MuSR 或 MMLU-PRO。排行榜完全是样本外验证。
用两个狭窄、正交的探针找到的层配置,竟然能泛化到 排行榜上所有测试 *。
- —— 除了 IFEval,不过那个本来就挺无聊的,对吧?
这已经够让人惊讶了。一种全新的扩展 LLM 的方法,用几块游戏显卡就搞出来了。但画出热力图后,故事变得更精彩了。
大脑扫描仪
生成 RYS-XLarge 的原始热力图,显示组合增量(数学 + EQ)。绿色圆圈标记了最优配置。红色表示改进,蓝色表示退化
这些热力图相当于 Transformer 的功能性 MRI,展示它在思考数学或 EQ 问题时的状态。
x 轴($j$)是重复区域的终点。y 轴($i$)是起点。每个像素代表一次完整评估:加载重分层模型,运行数学探针,运行 EQ 探针,给两者打分,记录增量。如上所述,沿着中央对角线只重复了单层。朝着右上角的下一条对角线,我们重复两层,依此类推。最右上角的那个点,每次推理都要跑完整个 Transformer 堆栈两次。
先看数学热力图。从任何一层开始,在约第 60 层之前停止,似乎都能提高数学猜测分数,这体现在一大片健康的红色区域。只重复最开始的几层(左上角的小三角)会把事情搞砸,重复最后 20 层中的任何一层(右侧的蓝色垂直墙)也一样。这在天际线图(平均行或列)中看得更清楚,我们可以看到对于数学猜测,重复的起始位置影响不大。所以,“起始层”将词元编码到平滑的“思考空间”,最后传递给专门的“重新编码”系统,这个假设似乎得到了部分验证。
直到我们看 EQ 分数:
现在情况看起来完全不同了!重复最后 10 层中的任何一层,对分数几乎没影响,但我们看到了复杂的模式,有些区域显示出显著改进(45i、55j 附近的区域),被表现不佳的区域包围着。
但热力图揭示的东西,比“思考位”的 位置 更有趣。它们揭示了关于其 结构 的某些信息。
LLM 神经解剖学的开端?
在确定块重复之前,我尝试了更简单的方法:取一个中间层,重复 $n$ 次。如果“更多推理深度”的假设正确,这应该管用。从重复中间层能广泛提升数学猜测结果来看,也说得通。给模型某个特定推理层的额外副本,得到更好的推理。所以,我扫描了所有层,寻找提升。
但不行,几乎总是更差。通常差很多,偶尔有小幅改进,但都在噪声范围内。有点烦,但再看一眼 EQ 分数中复杂、斑驳的图案,我有了另一个想法:
如果单层重复没用,那中间层就不是在做独立的迭代优化。它们不是可以简单“再运行一次”的相同操作的互换副本。如果是的话,重复其中任何一层至少应该带来边际收益。相反,这些层是作为一个 电路 工作的。一个多步推理流水线,需要作为一个完整单元执行。
这么想吧。第 46 到 52 层不是七个做同样工作的工人。它们是食谱中的七个步骤。第 46 层获取抽象表示,执行某个认知操作的第一步 —— 可能是将复杂表示分解为子组件。第 47 层获取 那个 输出,执行第二步 —— 可能是识别子组件之间的关系。第 48 层做第三步,依此类推到第 52 层,产生最终结果。
只重复这个“食谱”中的一个步骤,对你没多大帮助。
但重复 整个块,你就得到了完整的食谱两次。模型运行完整的推理电路,产生一个精炼的中间表示,然后在自己的输出上 再次运行相同的电路。这是第二次通过。一个抓住第一次遗漏的东西、精炼其抽象、将推理推进一步的机会。
让我们深入探讨一个更现代的模型(我可以 在我的系统上 实验的):来自 mratsim 的 ExllamaV3 GLM-4.7。
我标出了一个能显著提升数学能力的区域。注意它坐落在哪里?它偏离了对角中心线,这意味着我们看的不是单层重复。从位置 35 开始重复块,直到至少位置 43 才看到任何改进。那是七层几乎没发生什么。实际上,重复这些层我们甚至看到了 性能下降(它们是蓝色的,不好!)。
从终点位置 43 到 46,我们看到了数学分数的稳固提升(红色 = 好,耶)。但包括第 46 层或更远,收益就又崩溃了。假设:位置 47 是 另一个 电路开始的地方。即使包含下一个食谱的一步,也会搞乱当前的食谱。
所以“数学器官”两边都有边界。层太少,你什么也得不到 —— 你切入了电路,它无法完成操作。层太多,你也什么也得不到 —— 你包含了不属于它的相邻电路的组织。预训练从层堆栈中雕刻出这些结构,它们只能整体工作。这也不适用于其他任务,因为 EQ 分数的热力图没有这个斑块。
这比“中间层做推理”的说法具体得多。它说推理皮层被组织成 功能电路:执行完整认知操作的连贯多层单元。每个电路都是一个不可分割的处理单元,而热力图中看到的 $(i, j)$ 扫描本质上是在发现这些电路的边界。
通过“脑损伤”实现机制可解释性?
这也让我重新审视了之前用 oobabooga 的 Text Generation Web UI 做的那些非正式实验。整个开发过程中,我一直在和各种重新分层配置的模型聊天,感受它们在对话中的“感觉”。
好的配置会显得更敏锐,虽然微妙但能察觉到。推理更连贯,长上下文处理得更好,对话流更自然。就是那种你很难具体说出哪里变了,但模型感觉更“在场”的差异。也可能只是我的想象,毕竟“感觉检查”很难定义。
坏的配置就彻底失控了。有些会结巴,陷入退化的循环。另一些则发展出奇怪的人格障碍。有一个模型会莫名其妙地欢快宣布:“我们来扮演牛仔吧!耶哈!”,然后陷入无法恢复的咯咯傻笑,生成好几页夹杂着牛仔梗的“哈哈哈”。“嗑嗨了”是我能想到的最佳描述。我不知道 LLM 是否“部分有意识”,或者说有某种“精神状态”,但如果是的话,这个模型肯定玩得很开心。
这些实验表明,这更像是“真正的脑损伤”,而不是“稍微差一点的模型”。这在电路模型下说得通——复制错误的电路,就像以牺牲邻居为代价放大大脑的特定区域。你不会得到一个全面变笨的人,你会得到一个有特定神经功能缺损的人。那个牛仔模型可能是“社交得体性”电路被失控的双倍“创造力”电路干扰了。结巴的模型可能是解码电路被额外的推理深度推得错位,无法再翻译成连贯的 token。
如果 Transformer 的推理确实组织成离散的电路,这就引发了一系列迷人的问题。这些电路是架构的必然结果,从大规模训练中涌现出来的吗?不同的模型家族会在不同的层位置发展出相同的电路,还是它们会发展出根本不同的架构?
幸运的是,我已经做了一些;看看这些图,你自己判断吧:
后续影响
我的方法与微调正交。层复制改变的是架构,微调改变的是权重。你可以把它们叠加起来。后来有人在排行榜上拿到了更高的分数:
MaziyarPanahi 拿 RYS-XLarge 做基础,在上面做微调,产出了 calme-2.4-rys-78b。然后 dfurman 对那个模型进行了 ORPO 训练,产出了 CalmeRys-78B-Orpo-v0.1。MaziyarPanahi 继续迭代了 calme-3.1 和 calme-3.2。
截至 2026 年初,Open LLM Leaderboard 上的前四名模型是:
- MaziyarPanahi/calme-3.2-instruct-78b — 52.08
- MaziyarPanahi/calme-3.1-instruct-78b — 51.29
- dfurman/CalmeRys-78B-Orpo-v0.1 — 51.23
- MaziyarPanahi/calme-2.4-rys-78b — 50.77
全是 78B 参数,全是 RYS-XLarge 的后代。所有这些都建立在复制的中间层之上,而这些层仅仅是通过一些硬核数学和情感智能探针发现的,用的只是我地下室里的一对 RTX 4090。
我自己从没做过微调。那部分我不太感兴趣。后来我对排行榜也渐渐失去了兴趣。越来越明显的是,有些提交在测试集上训练了,整个排行榜最终被关闭并重启。但我知道这个方法是真的,因为我从未使用排行榜的基准来做优化。排行榜对我来说一直只是验证。
从 2026 年回望
在 2024 年,模型合并社区痴迷于权重插值:SLERP、DARE-TIES、线性合并、直通层。想法总是把不同模型学到的参数结合起来,得到大于各部分之和的东西。mergekit 是首选工具,排行榜上充斥着各种创意组合(害得我等了好几个月才等到我的模型被评测…)。
我做的是不同的事。我不是在改变模型知道什么。我是在改变它如何思考。层复制让模型在其内部推理空间里有更多迭代次数,而不添加任何新信息。这就像给某人一个更大的图书馆,还是给他更多思考时间的区别。当我登上排行榜榜首时,我真的很震惊;但我想这证明了方法很可能有效。
这个方法能成功,更具体地说,只有电路大小的块能成功,这告诉我们 Transformer 在训练过程中是如何组织自己的。我现在相信它们发展出了真正的功能解剖结构。早期层编码。晚期层解码。而在中间,它们构建了电路:连贯的、多层处理单元,执行完整的认知操作。这些电路是不可分割的。你不能通过复印食谱的一个步骤来加速烹饪。但你可以把整个食谱运行两次。
小模型似乎更复杂。编码、推理和解码功能更纠缠,分布在整个堆栈中。我从未找到过一个能在所有任务中通用的单一复制区域,尽管显然可以以牺牲另一种“天赋”为代价来提升某一种“天赋”。但随着模型变大,功能解剖结构变得更分离。更大的模型有更多“空间”来发展通用的“思考”电路,这可能就是为什么我的方法在 72B 模型上效果如此显著。参数存在一个临界质量,低于这个值,“推理皮层”还没有从大脑的其余部分完全分化出来。
随着 HuggingFace LLM 排行榜的关闭,加上没有强大的 GPU 可用,我停止了实验。但随着新的开源模型(Qwen、MiniMax、GLM 等等)大量涌现,以及我终于在家里有了足够的算力,我开始研究当前这批 LLM。热图不断带回相同的大致故事,但每种架构都有自己的神经解剖结构。大脑不同。原理相同。有些模型看起来真的很有意思(特别是 Qwen3.5 27B)。一旦我的 Hopper 系统完成对 MiniMax M2.5 的运算,我将发布代码,同时上传新的 RYS 模型和一篇博客文章。
Nvidia:赞助这个项目,给我寄一台 GB300 Grace Blackwell Ultra Desktop,因为我需要更多的 VRAM!
还有一件事
还记得这个架构吗?
1 2 3 4 5 6 7 8
Example: (i, j) = (2, 7)
0 → 1 → 2 → 3 → 4 → 5 → 6 ─┐
┌─────────────────────┘
└→ 2 → 3 → 4 → 5 → 6 → 7 → 8
duplicated: [2, 3, 4, 5, 6]
path: [0, 1, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 7, 8]
我们有一个糟糕的断裂点,在第 6 层和第 2 层之间。我还有一个假设:我们真正需要的,可能只是对这两层做一点点微调。经过微调的 RYS 模型统治了排行榜。我怀疑这个连接点正是微调修复的地方。而且有一个很好的理由这么做:这个方法不消耗额外的 VRAM! 在所有这些实验中,我通过指针复制层;层被重复了,但没有占用更多 GPU 内存。当然,我们确实需要更多计算和更多 KV 缓存,但为了一个可验证的更好的模型,这是很小的代价。我们可以直接“修复”第 2 层和第 6 层的实际副本,并将第 3-4-5 层作为虚拟副本重复。如果我们微调所有层,我们就把虚拟副本变成了真实副本,会占用更多 VRAM。
二十年前,我是一个解剖老鼠大脑的博士生。我从未想过最终会为人工思维进行脑外科手术。
特别感谢我的妻子,忍受了我在几个月里无数个晚上和周末在地下室盯着热图看。也感谢 appliedAI Institute 提供的 H100 算力,帮助扩展了这些实验。
引用这项工作
@article{ng2026rys,
title = {LLM Neuroanatomy: How I Topped the LLM Leaderboard Without Changing a Single Weight},
author = {Ng, David Noel},
year = {2026},
month = {March},
url = {https://dnhkng.github.io/posts/rys/}
}
觉得有用?分享给更多人













