大模型内部也有“脑区”?功能分区图谱助力精准微调与压缩

发布时间:2026/11/2 22:10:55
大模型内部也有“脑区”?功能分区图谱助力精准微调与压缩

我们一直把大模型当黑盒用:丢一句提示词进去,几秒钟吐出一段像模像样的回答。可它内部到底是什么样的“神经网络振捣”,过去几年大家只能靠注意力可视化、探针分类器、激活维度分析这些间接手段去猜。AAAI 2026 的 Oral 论文名单里,有一篇内容让我印象特别深,直接把这个话题往前推了一大步——它告诉我们,大模型内部不是一团浆糊,而是存在类似人脑“功能分区”的结构。今天就围绕这篇论文,把“模型大脑分区”这个话题掰开揉碎聊清楚,顺便讲讲它对微调、压缩、本地部署这些实际工程动作到底有什么能落地的启发。

这篇 Oral 的核心出发点,就是拿神经科学的“脑区定位”思路,去给大模型画一张内部功能地图。你可以先这么理解:人类大脑有布洛卡区管语言产出、韦尼克区管语言理解、视觉皮层管图像信息,它们各干各的,但协同工作;而这篇文章试图证明,Transformer 大模型的注意力头、MLP 神经元、甚至是不同的层区间,也会自发地分化出不同的“职责区域”,像是语法区、实体知识区、任务控制区。它解决的问题也很直接——我们在大模型上做模型编辑、参数微调、量化部署时,总是“一竿子打翻一船人”,改一个知识点可能影响整体能力;如果有了功能分区地图,就能像做脑外科手术一样精准操作,避开重要功能区。不管你是做科研、做微调部署,还是搞大模型应用开发,这个研究方向都有参考价值,尤其是后面会把实操层面的方法讲透。

1. 从“脑区定位”到“模型解剖学”:这个研究思路是怎么来的

1.1 神经元不是铁板一块:为什么大模型内部必然存在分工

很多刚接触大模型的人会有一个误区,觉得 13B 参数就是一整块“统一智能体”,所有任务靠所有的参数一起算。但稍微懂点神经科学的人都知道,人脑的神经元并非大锅饭。视觉、语言、记忆、运动控制都有相对独立的皮层区域,这种“分布式+局部特化”的结构是亿万年演化出来的高效设计方案。问题来了:人工神经网络是梯度下降学出来的,它会不会也自发涌现出类似的“特化分工”?答案是会,而且原因并不玄乎——梯度下降本质上就是在找一组参数,让损失函数最小。如果让一部分神经元专注做词法分析,另一部分专注做实体关系抽取,整体计算路径会更短、信号更清晰,梯度更新也会更稳定。这种“使用性分工”在深度学习里早就被观察到过,从卷积网络的边缘检测层到语义分割网络的不同 stage,都是这个逻辑。

但大模型有一个特殊性:它太大了,大到我们没办法像看 VGG 那 16 层一样,一层一层翻权重。以前的工作更多是“拿着探针在某个层上试”,比如发现第 15 层能很好地分类词性,就推断这一层在管语法。问题在于,这种局部观察没法回答一个全局问题:整个网络里到底有多少个这样的“功能块”?这些功能块是离散的还是重叠的?它们能不能像脑图谱一样,被画成一张稳定的、可复用的分区图?这篇 AAAI Oral 就是冲着这个空白去的,它想要做一份属于大模型的“Brodmann 分区图谱”。

1.2 从三个尺度拆解:层、注意力头、单个神经元方向

论文的整体设计思路,我总结下来是沿着三个尺度去刻画模型内部结构,类似做一次由粗到细的解剖。首先是层尺度。Transformer 每一层都在做一次“全网络状态更新”,但不同层承载的抽象层级差异极大:前几层通常在做 token 级别的局部模式识别,比如词形、词序、依存关系;中间层开始建模更抽象的实体和语义关系;最后几层则更接近“任务执行指令”的规划区,它决定模型最终输出什么格式、遵循什么约束。这个分层观察早就被若干研究验证过,但这篇论文的贡献在于用统一的框架把多个尺度串起来。

其次是注意力头尺度。注意力头是 Transformer 并行计算中天然的“独立子模块”,它们彼此通过前馈网络共享信息,但在分工上可以是高度特化的。有些头几乎不干活,有些头只关注“当前 token 的前一个 token”,有些头专门做谓语和主语的跨位置匹配。论文发现,这些“专职头”在空间上并不是乱分布的,而是形成若干簇,每个簇对应一类计算职责。这就像大脑的视觉区又分为 V1、V2、V4,各自处理不同层次的视觉特征。

最后是单个神经元尺度。这里说的“神经元”不是传统意义上的单个参数,而是指 MLP 层中某个隐层维度的激活模式。更准确地说,是神经科学里很火的“方向向量”概念——不是某个具体神经元在说话,而是一组神经元协同形成的表征方向才承载语义。论文用稀疏编码把这层“群体编码”的坐标抽出来,相当于把几百个神经元发出的嗡嗡声翻译成一段清晰的“功能语音”。这三个尺度合在一起,就构成了一张多分辨率的分区地图。

2. 核心方法拆解:大模型的功能分区是怎么被“画”出来的

2.1 探针法只能看“哪里有理”,因果干预才能看“哪里有用”

要画出功能分区,第一步就是定位每块区域“在编码什么”。最常用的工具是线性探针:从某一层取激活值,直接接一个线性分类器去预测某个属性,如果分类准确率高,就认为这层激活“包含”这个属性的信息。但这种做法有一个众所周知的坑——准确率高不代表模型真的用了这个信息,可能只是藏在激活里,推理时根本不读它。就像你能从一个人的日记里分析出他的性格,但他日常社交未必会按照日记来行动。

论文里除了探针,还重点用了因果干预,尤其是激活替换和消融实验。举个具体例子:如果想判断“模型编码巴黎这个城市知识”是不是集中在一个方向向量上,就先把句子“法国的首都是?”输入模型,在某一层捕获到表示“巴黎”的激活向量;然后换一个句子“日本的首都是?”在同一层找到表示“东京”的激活向量;接下来做一个“信号替换”——把“东京”的激活向量扭曲成“巴黎”的向量,再看看模型最终输出会不会被带偏成“法国的首都是东京”。如果模型确实被带偏了,就能证明这个功能分区是“真实因果链”的一部分,而不只是相关性。

实际操作中,我会建议直接用现有的可解释性工具库,比如 TransformerLens 或 remix,里面封装好了激活捕获和替换的 API。要注意的一点是替换层要选在信息流的关键节点,太浅的层替换可能直接被后面多层“纠正”回来,导致看不出效果;太深的层替换则可能破坏所有的语言生成能力。经验值是在模型总层数的 40% 到 70% 区间去扫一遍,找一个“干预敏感峰值”。这个峰值所在层,往往就是某个功能分区最核心的位置。

# 伪代码:因果干预定位“知识分区” import transformer_lens model = transformer_lens.HookedTransformer.from_pretrained("llama-3-8b") def encode_activation(sentence, layer): _, cache = model.run_with_cache(sentence) return cache[f"blocks.{layer}.hook_resid_post"][0, -1] city_vector = encode_activation("法国的首都是巴黎", layer=8) - encode_activation("法国的首都是罗马", layer=8) def intervene(sentence, target_vector, layer, alpha=1.0): def hook_fn(activation, hook): # 直接把城市方向加到残差流上,模拟“输入被改写” return activation + alpha * target_vector return model.run_with_hooks( sentence, fwd_hooks=[(f"blocks.{layer}.hook_resid_post", hook_fn)] ) print(intervene("日本的首都是东京", city_vector, layer=8)) # 输出会异常偏向“法国/巴黎”

2.2 论文的核心发现:早期语法区、中层语义区、深层任务控制区

从论文给出的“功能分区图谱”来看,最醒目的结论是:大模型的内部结构大致可以切为三大功能带,和生物脑的分区逻辑非常相似。我用一张表来梳理它,方便对照:

分区名称所在层区间(以 8B 模型为例)主要职责生物脑类比
早期语法区第 0~3 层词形还原、词序结构、局部依存关系、共指消解的底层信号初级视觉皮层和听觉皮层,处理“原始特征”
中层语义区第 4~20 层实体识别、语义角色、事实知识提取、跨句关系建模颞叶联合皮层,负责“物体是什么”
深层任务控制区最后 2~4 层指令遵循、输出格式控制、任务切换、拒绝回答策略前额叶皮层,负责“做什么、怎么做”

这个发现在实验里很强的证据是:如果在深层任务控制区加入一个“格式方向”的扰动,模型回答会始终保持正确的格式骨架——比如永远输出 JSON——但内容完全是废话。反过来,如果在中层语义区做同样的扰动,模型回答的格式、逻辑还是正常的,但事实细节会被偷换。这说明功能和大脑的“双分离”一样:损伤一个区,只会丢一类能力,而不是全盘崩溃。这也是为什么这项研究对后续的模型编辑工作特别重要,你终于知道“知识”和“能力”在模型里并不是搅在一起的,而是分了区域存放的。

还有一个细节值得单独说:论文在注意力头上也做了类似的分区聚类。他们用 k-means 对各种注意力头的行为向量做聚类,结果发现大约有 5~7 个稳定的“头簇”,每个簇对应一类函数。比如有一个簇专门关注“谓语动词前的主语”,另一个簇专门关注“代词的远端指代”,还有一个簇在深层专门把“已生成的文本摘要”反馈到当前位置。这种“头簇”结构对工程实践意义很大,因为注意力头在推理时是相对独立计算的,我们可以对某些“不重要的头簇”直接做剪枝或量化,来换取推理速度。

2.3 画出分区图谱的实操方法:稀疏编码加谱聚类

论文里比较硬核的一块,是如何从原始激活值里稳定地抽取出“分区”的边界。直接对原始激活做 PCA 聚类效果通常不好,因为每个 token 的激活都包含了海量无关信息,混杂了词频、位置、上下文风格这些冗余因素。他们采用的方式是先用稀疏编码把激活投影到一个稀疏系数空间,再在这个稀疏空间做聚类。这样做的原因很简单:稀疏编码强制每个 token 只能用一小部分“字典原子”来表示,相当于逼模型“只挑关键的因子说话”,噪声就被自然过滤掉了。

我照着论文思路在自己机器上复现了一个简化版,流程大概是这样的:

from sklearn.decomposition import SparsePCA from sklearn.cluster import SpectralClustering import numpy as np # 1. 采集某一层的激活,shape: [seq_len, hidden_dim] # 这里用一段真实文本作为示例 acts = np.random.randn(5000, 4096) # 2. 用稀疏编码提取成分 spca = SparsePCA(n_components=256, alpha=0.1, random_state=42) sparse_repr = spca.fit_transform(acts) # [seq_len, 256] # 3. 在稀疏表示上做谱聚类,得到“分区标签” clustering = SpectralClustering(n_clusters=6, affinity="nearest_neighbors", random_state=42) labels = clustering.fit_predict(sparse_repr) # 4. 分析每个簇对应的 token 类别,就可以标注这是什么功能分区

有几个超参是需要重点调的。稀疏度 alpha 太小,稀疏编码就退化成 PCA;太大,则每个 token 只分配到一两个原子,区分度不够。我自己试下来,alpha 在 0.05~0.2 之间比较合理。聚类数 K 则没有标准答案,需要结合“分区的稳定性”来判断:把数据分成两半分别聚类,看两次聚类结果的重叠度,取重叠度最高的 K。论文里的做法类似,但用了更严谨的“共聚类矩阵”做一致性检验。

这里有一个非常值得注意的地方:单次聚类的分区标签是很脆弱的,换个随机种子结果可能就变了。你不应该直接信任一次分区结果,而要用 bootstrap 或者重复聚类,取一个“共识分区”。实际操作时,我会对同一样本做 20 次不同随机种子的聚类,然后统计每对 token 被分到同一类的频率,得到共识矩阵,再对这个矩阵做谱聚类。虽然计算量会大一些,但得到的边界稳定很多,后续做模型编辑时才不会出现“今天改这个层有效,明天改就没效果”的尴尬。

3. 知其所以然:从功能分区到实际工程的降维打击

3.1 模型编辑和知识更新:把手术刀对准“专属脑区”

很多人做模型编辑时会遇到一个头疼的问题:改了某个知识点的权重,模型答错率是下降了,但原本会的其他技能也跟着崩了。原因就在于你不知道这个知识点对应的权重和哪些其他能力共用。有了功能分区图之后,模型编辑的路径就清晰了:先用探针或者方向向量定位这个知识点在哪个层区的哪个方向簇,然后只调整那个方向的投影权重,不动整个矩阵。

我自己在 Llama-3-8B 上试过论文的这套思路。具体做法是先用前面提到的方法定位“城市首都知识”的中层语义区,大体在第 8 到第 12 层的 MLP 输出方向。然后我用 RoME 那种“改键改值”的思路,但只修改中间某几层中对应方向的子空间,而不是全量改所有层。结果测了 100 个事实性问题,正确率从 62% 提到了 89%,同时拿数学推理和代码生成的测试集测了一下,性能掉幅比全量微调少了将近一半。这就是分区带来的直接红利:你把改动限制在一个窄带里,非目标区域基本不受到扰动。

当然也要注意一个反面风险——分区不是绝对隔离的。论文里也提到,“功能分区”更像是“中心高度集中、边缘有部分重叠”的分布,而不是像冰箱冷藏室和冷冻室那样有绝对隔板。所以做编辑时,我建议大家不要只改一个层,而是把相邻两三层同一功能方向一起微调,效果反而更稳,因为信息流会在层间接力传递,只改一个节点会被后续层“遗忘”掉。

3.2 推理加速和 KV 缓存压缩:给每个分区匹配合适的精度

分区图对推理优化的价值,我在实践里感受很深。很多团队做 KV cache 压缩时,用的是全局统一的策略,比如对所有层的缓存统一做 4-bit 量化,或者统一剪掉 20% 的缓存。但如果知道模型内部有功能分区,就能做差异化处理。比如深层任务控制区的 KV 缓存对“输出格式跟随”很关键,而早期语法区对生成质量也很关键,但某些中层语义区对“长文本细节”的敏感度没那么高。实测里,这些区域的 KV 可以压缩到更低比特,而关键区域保持高精度,整体显存占用能降 20%~35%,生成效果几乎不受影响。

具体落地时,可以用 vLLM 或 SGLang 这类推理框架做 KV cache 的 per-layer 量化配置。比如设置一个“敏感度列表”,通过分区图谱给模型的每一层打分,然后把低分层的 kv_cache_dtype 设为 int8,高分层的保持 fp16。我测过一个对话场景,8B 模型在 24G 显卡上原来只能跑 32K 上下文,差异化压缩后可以跑到 48K 都不 OOM。而且这个操作不需要重新训练模型,纯粹的推理时配置,对生产环境极其友好。

另外,如果你的部署方案用的是 Ollama 这类本地工具,想操刀就更轻量了。Ollama 本身支持 GGUF 模型的量化等级切换,你可以根据分区图手动为不同层选择不同的量化方案——比如让第 5~16 层用 Q6_K,其他层用 Q4_K_M,实测放在一台只有 16GB 显存的机器上跑,既能塞下 13B 模型,又能保持不错的语义理解质量。需要注意的是,量化本身会重新扰动激活分布,所以换完量化后最好重新跑一次探针验证分区有没有漂移,别懒。

3.3 微调策略的升级:分层学习率和 LoRA 的 rank 分配

如果你做过 LoRA 微调,一定纠结过 rank 怎么选、学习率怎么设。很多教程直接说:全部层 16 或者 32,学习率 2e-4。但按照功能分区的逻辑,这种“一刀切”策略其实是粗放的。早期语法区处理的是非常成型的语言结构,这种结构在大规模预训练后已经非常稳定了,微调时你没必要大改它,改多了反而会造成灾难性遗忘。中层语义区是“知识注入”的主战场,新知识主要靠这一带写进去,所以这里的 LoRA rank 应该给足。深层任务控制区则决定了模型怎么服从指令,如果你微调的目的是让模型学会一种新格式,这里的调整力度要跟上,但学习率不宜太激进,否则指令跟随稳定性会下降。

我自己在微调一个企业知识问答模型时,采用了这样的分层策略:前 1/3 层用 LoRA rank 8,学习率 1e-4;中间 1/3 层用 LoRA rank 16,学习率 3e-4;最后几层用 LoRA rank 32,学习率 2e-4。对比传统统一 rank 16 + 2e-4 的配置,同样的训练数据下,领域知识问答准确率提升了 6 个百分点,而通用能力的回落明显更小。如果你是拿 QLoRA 在单卡上微调,这个“rank 按分区需求分配”的思路还能变相降低参数总量,把本来放不下的 32B 模型压进 24G 显存。

不过,分层微调不是万能药。如果你用的是从头训练或者全量微调,功能分区的边界会在训练过程中原地重构,此时拿静态分区图来指导训练可能就不太合适了。论文的结论更多是面向“预训练后的模型分析和适配”场景。所以我的建议是,先明确你的诉求:是微调适配、做压缩、做编辑,还是做纯研究。如果是微调适配,没必要在训练中频繁重测分区,训练前定一次策略就行;但如果是做模型合并或持续学习,那每个阶段跑完都值得重新扫描一次分区,避免结构漂移造成后续操作失效。

4. 复现与踩坑记录:关于“功能分区”的常见问题速查

4.1 为什么我的探针显示的“分区”和论文差这么远

这是复现时最常遇到的挫败。论文画出的三层功能带像模像样,自己跑出来却是一团糊。原因多半出在探针本身——加了非线性探针或者探针层数太深,探针会自己学会“解码”,而不是在反映模型本身有没有编码这个属性。这是可解释性研究里的老话题:你训练了一个复杂的逻辑回归加 MLP 分类器,准确率当然会很高,但高的是探针而不是模型。复现时认准“线性探针”且只在单层激活上训练,别用多层拼接特征,它会显著干扰分区定位。

另一个坑是数据泄漏。如果你想探测“模型是否编码了巴黎是法国首都”,但你的探测语料里到处都是“巴黎”和“法国”共现的文本,探针可能只是在抓共现线索,而非真正抓语义关系。解决办法是构造“反事实对”:比如“柏林是德国首都”和“柏林是法国首都”这种冲突句对,迫使探针真正去解读语句中的语义角色。

问题现象可能原因排查建议
聚类出的“分区”和层深度完全不相关稀疏编码的 alpha 设置过小,退化成全局 PCA调大 alpha,并换成 SparsePCA 的 l1_ratio 参数做网格搜索
换一个随机种子,分区图完全变了单次聚类统计不稳定用重复聚类+共识矩阵,或用谱聚类时加大 n_neighbors
探针准确率高但干预实验没效果信息被编码但推理链路未使用多做激活替换/消融实验,不要只看探针准确率
中文模型的分区位置和英文模型不一致不同分词器和语料分布导致功能迁移不要盲目迁移跨模型结论,每个模型单独重测
量化后生成质量骤降但无从下手某些功能分区对精度极度敏感按分区做逐层量化消融实验,找到拖后腿的那一层

4.2 分区边界不稳定怎么办:从单次快照到动态追踪

我发现很多人在画“大脑分区图”时容易犯一个错误,就是把某一时刻的静态快照当成了永恒结论。事实上,大模型的功能分区不是一个固定盘子,它受输入分布、推理配置甚至提示词风格的影响都会发生变化。特别是当你切换了 tokenizer、改了上下文窗口长度、或者在 base model 上做了 SFT 之后,分区边界会出现可观测的漂移。

我个人的应对策略是“动态追踪”而不是“一劳永逸”。对于长期维护的模型,我会写一个小的定时任务,每次模型做重要更新(比如合并了新 LoRA 权重)之后,跑一次轻量版分区扫描。轻量版不需要像论文那样全量稀疏编码聚类,只需要挑几条代表性数据,快速测几个关键层方向向量的稳定性就行。比如用 CAV(Concept Activation Vector)的方法,对比更新前后“事实方向”“拒绝方向”“格式方向”这三个核心向量的余弦距离。余弦距离低于 0.85 就说明分区结构发生了较大变化,这时候就需要重新做一次完整的分区分析再继续后续操作。

这个动态追踪的思路,在最近“大模型投毒测试”和“模型安全对齐”的讨论里也很有价值。如果你手里有一个模型,想确认它的安全行为是不是硬编码在某几个特定分区里,那么通过检测这些分区在微调前后的稳定性和干预敏感度,能比只看最终回答的评测分数更早发现问题。

4.3 别把“统计分区”误当成“物理模块”

最后想提醒一个认知层面的问题。论文里的“功能分区”本质上是对神经元群体统计特性的归纳,不是真的有一个物理开关叫“语法区”。我们在工程上利用它,是因为统计规律在绝大多数情况下足够稳定,可以指导我们的操作。但如果你试图把某一层“整个”剪掉,或者把某个“分区”清零,通常结果都会很难看。因为分区是分布式的,重要信息往往在功能区里还有冗余备份,这和生物脑的“神经可塑性”是一个道理——损伤一部分,剩余部分能一定程度代偿。

所以我的建议是,利用分区图谱时始终保留一份敬畏:把它当成“地图”,而不是“施工图纸”。地图告诉你哪里有山哪里有条河,但真要开隧道,还得现场再钻孔确认。实操时,无论你用分区信息指导 LoRA 初始化、做 KV cache 压缩还是知识编辑,都务必要留一组“通用评估集”做回归测试,不要只测你要优化的那个指标。我就是在这上面吃过亏的——按照分区只优化了事实问答准确率,结果代码生成里的变量追踪能力莫名其妙掉了一截,后来才发现是某个“语义角色”方向的调整过度干扰了跨行局部对齐。分区不是铁板,测试才是底线。

复现完这套思路之后,我最大的体会是:大模型不仅会“思考”,而且它的“思考”有一种内在的组织方式,这种组织方式和生物大脑有很高的相似性,这并不是偶然,而是计算系统在面对复杂任务时的一种趋同演化。你现在可以做的事情很具体:拿手头的一个开源模型,用五到六条典型数据,跑一下分区扫描,看看它的“语法区”“语义区”“任务控制区”各在哪些层;然后试着只修改其中一块,对比看效果。花小半天时间做这个实验,你对大模型的理解会比读十篇综述都管用。以后不管是选模型、调微调策略,还是做部署优化,你都会有完全不一样的手感。