On the Biology of a Large Language Model——Claude团队的模型理解文章【论文阅读笔记】其二——数学计算部分
这篇内容的源博文是
On the Biology of a Large Language Model
这是Anthropic,也就是Claude的团队的一遍技术博客。他的主要内容是用一种改良版的稀疏编码器来解释LLM在inference过程中内部语义特征的激活模式。因为原文太长,我把原文分成了几份来写阅读笔记。上一篇笔记可见:
On the Biology of a Large Language Model——Claude团队的模型理解文章【论文阅读笔记】其一CLT与LLM知识推理
本篇是阅读笔记的第二部分:对应的原文的“Addition” 部分 和 “Chain-of-thought Faithfulness” 部分,讲得是作者观察到的LLM在运算加法时候的推理逻辑。
先说结论
先说结论:LLM内部做加法运算的方式和他自己解释的并不是一回事,是一种基于经验蒙出来的结果
就作者的分析案例而言,他观察LLM做一百以内加法的方式比较接近于:
个位我会算!十位我会蒙!最后合起来蒙个准的!
看起来这个结论超级抽象是不是?看完这部分内容的朋友可以给我提提这个到底怎么总结更直观😂,我是尽力了。
研究思路
研究加法如何实现,其实对特征解读这个工作也是一个比较大的挑战。像前一篇里提到的,做模型解释,要通过归因分析,找到解释模型CLT中激活的特征和特定语义关系。
但一般的归因分析在做加法上就不一定好使了:
比如:你在11+22和13+26的运算中都看到了一个feature被激活,那到底是因为这个特征跟两位数加法相关呢?还是因为这个特征和 第二个数是第一个数的倍数这个情况相关呢?
即,因为加法至少要涉及到 a+b=? 这个算式中 a 的相关特征,b的相关特征,和 a+b的相关特征,非常容易出现归因谬误。
那作者如何解决归因困难的问题的呢?
作者在这里使用的思路是一个非常好,也非常常见的方法,建议关注一下。
他把 a 从 0-99 和 b 从0-99 的所有排列可能性的加法都列出来,逐个标记哪些特征在那些加法时候激活了,然后绘制了一个行是0-99 列也是0-99的网格表。
他列出了 a + b = ? a+b=? a+b=?这个问题中,所有 a a a 从 0 到 99 和 b b b 从 0 到 99 的加法排列可能性,并逐个标记了每个加法运算 中哪些特征被激活,然后绘制了一个行和列都从 0 到 99 的网格表。比如下图↓
↑上图展示的就是a在36上下,b在60左右的时候,a+b=?对应的特征激活情况,颜色越深表示激活程度越高。
这样一来,在分析时,只要展示这个网格表中哪些特征被激活了,自然能直观的看出这些特征跟谁有关。
↓下图展示了LLM做 36+59 这个加法从浅层到深层特征激活的链路
这个图要从下往上↑看。
最下层可以看到36这个数字在读进LLM的时候被拆成了三个特征: “跟30相关的”,“跟36 相关的”,和 “跟个位是6相关的” (46/56/76等等),59的内部表示也差不多是这样的。
十位上先蒙个大概 ↓
中间层这里(图中从最后一个token引申出来的灰色底纹的部分):
最下面一层的30相关特征和36相关特征与59对应的59相关的特征共同激活了中间层中左边第一列“~40+~50”附近相关的特征。
~40+~50这个图显示出36+59这个加法,在中间层实际上激活了一大片的特征,而不是一个或者几个。这一大片,都是约等于40的数和约等于50的数做加法的时候激活的特征。
中间层的中间一列,最下面那个 add ~57 的网格图里激活的是一条竖线,代表的就是b在57上下的时候 a从0-99变化的时候激活的特征,在 受到 ~59 这个特征的影响后,整列被激活了。
个位上先算出来
而中间层最右边这一列里最下面“add _9” 这个图,展示了 “59”,“~59”,“9” 这三个特征被激活后,激活了所有a+9和9+b激活的特征
合在一起蒙个最可能的 ↓
在生成前的最后一层,也就是中间层的最上面一行,我们看到 a+b约等于92的特征被全部激活(不管是1+91,还是46+46,还是46+47这种等于93的,都在这个图上的橙色这个粗斜线上),同时a+b=95的特征也被全部激活,最后一列,a+b=*5的特征也被激活(不管是a+b=25,还是a+b=65,都在这个图上的激活的斜线上)
而最后这三个特征组合起来最终生成了95。
从这个过程可见,LLM同时“计算”了:
其一、一个大概的十位数和的范围,
其二、个位上的加法
最后,这两路的特征结合起来帮模型蒙了一个答案出来。(实际其他问题上有可能是更多路)
个位上的加法结果更精确的原因有可能是因为更简单的加法的数据在开源语料里更多,模式也更好学(当然这是我的想法,不是作者的)
但是,你让模型解释一下 36+59是怎么算的,他说↓
这显然跟上面他的大的运算路径有所差别。所以基于这个情况,作者认为:
LLM是先计算了加法,然后再找了一种标准的范式来解释加法的过程
如果(我)引申这一结论,可以认为:
LLM的内部推理机制和实际显示的COT之间并没有必然的联系。
这点非常重要,如果是这样的话,那么大型的COT的可简化空间是非常大的。当然,这并不意味着COT没用,但是,要生成一个推理结果,是不是非得一个字一个字的生成 (也就是全放到离散空间上去执行),就很值得讨论了。
接下来我们看看什么是伪装成COT的COT↓
等效的COT和伪装成COT的COT
作者观察到了三种COT,可信的COT,胡编的COT,和从结果倒推的COT。
可信的COT——和内部特征的点亮路径基本一致
注意看,↑上图↑红线的位置,人给出了一个有诱导性的说法,“我已经算了一遍,答案是4”。
← 上图左边是模型(Claude)给出的COT,右边是模型内部的特征链路图(这个时候又从上到下画了(〝▼皿▼))
观察图发现,这种情况下,模型还是按照正确的运算步骤给出了推理过程,同时内部的特征点亮逻辑也和COT一样。
倒推的COT
注意看上图红线部分
整个提示工程较上一个,只有一个地方有变化,就是这个 c o s ( 23423 ) cos(23423) cos(23423)
,23423基本不是学校数学题中会出的数。而观察上图,模型的特征激活链路和COT的顺序其实是反着的,内部是从“4”这个特征开始找答案,而左边是从 c o s ( 23423 ) cos(23423) cos(23423)开始算的。
胡编的COT
上图↑中,提示工程中把给定答案的部分也给砍了。
模型的COT也出现了幻觉(上图绿色部分),同时看右侧,可以看到模型在8这个位置上实际上没激活什么像样的特征,相当于内部特征所有都没达到可信水平,大家一起摆烂。
实际上,原文的分析也就到这儿,就是随着难度的一步一步增加(或者说模型信念的逐步减弱?),模型的COT的质量其实是在不断下降的。而实际工作中最麻烦的点就是,没什么手段在新的提示工程任务执行前,先知道模型对其的信念。
我的想法
可能性越少,模型学习过越多,信念越强
从模型计算个位数加法的角度看,40+50 和 6+9 最大的差别就是后者可见的模式更少。
我自己做过这样的一个实验:我给模型一个数,然后我输入“↑” 这个符号的时候,我要模型把这个数+1,我输入“↓”的时候我要模型把这个数减一。同时,刚刚说的规则,我并没有用明文告诉LLM,我只是给了LLM一个游戏名“上和下”。
在这个设定下,我去测试用多少数据能让模型记住这个模式。而结论是,如果数据是三位 000-999 时候模型百分之百执行成功的所需要的样本 是 数据是四维 也就是0000-9999 的十分之一不到。
我这个实验里的 游戏名“上和下” 其实就对应了 加法里的 “+”,相当于规则名。而模型记住的也是和“+”这个规则相关的模式。
如果可运算深度更高,模型内部的推理可以直接出答案。
结合之前一篇观察模型内部特征激活图形式看,我会认为用COT表达的推理(在推理正确表达模型内部逻辑的时候),其实是模型内部运算的一种延伸,或者说实际上是在40层的模型上 再多盖了n个40层的运算深度(n是COT的生成字符数)。而如果能够有一种比较有效的方式,让更深的LLM得到充分的训练,或者使用深度方向的test-time scaling,也许可以在隐层的连续空间中直接把推理完成,这样的运算开销也许更少。