为什么我们的 AI 不说人话?
最近尝试用 LLM 进行一些知识的学习,也会在博客记录一些学习的过程,但发现抛开代码后, LLM 的回答的用词有时候非常奇怪,甚至有些不符合人类的表达习惯。最近学习了一些 Transformer 原理后,对这个事情有了进一步认知,也写了个可视化小工具探索词表,并用它找到了词表里的近义词!
原理
我们以 DeepSeek v4 Flash 为例,来看看它的模型结构,其他 Transformer 模型的结构也大同小异:
flowchart TB
IN(["input_ids"]) --> EMB["embed 输入词表<br/>129,280 × 4,096"]
EMB --> BLK["Block × 43<br/>MLA 稀疏注意力 + MoE(256 选 6)"]
BLK --> HCH["hc_head + RMSNorm"]
HCH --> HS["hidden state<br/>4,096 维"]
HS --> HEAD["head 输出词表<br/>129,280 × 4,096"]
HEAD --> LOGIT["logits<br/>129,280 维"]
LOGIT --> SMP(["softmax → 采样"])
classDef focus fill:#f3ece3,stroke:#8a5a2b,stroke-width:2px,color:#1f1d1a
class HS,HEAD,LOGIT,SMP focus
我们可以看到,输入的 Token 经过 embed 层 (也就是输入词表)后,经过 43 个 Block 的推理,得到一个 4096 维的 hidden state 向量,然后这个向量会去和输出词表的每一个向量做点积,得到每个词的相似度,然后通过 softmax 得到概率分布,最后采样输出下一个 token。
因此,我们可知,其实 Token 推理得到的语义信息,是在 hidden state 这个 4096 维的向量中。而这个语义信息其实在这一步还不知道会输出成什么 Token。因此,当这个 hidden state 对应的语义可以是多个近义词时,在计算 head 输出词表的相似度时,可能就有某些近义词的相似度都很高,在采样时就会随机采样到其中一个近义词,导致输出的 Token 可能不是人类习惯的表达。也有可能由于训练没做好,即使是最高概率的词也并没有被准确应用。
可视化
为此,我自己做了个可视化工具 DeepSeek-V4-Flash Token Explorer,可以直观地查看每个 token 在 head 输出词表中的相似度分布。
它的原理是,先根据我们输入的词语去查找词表中含有这个词语的 Token,毕竟对于常见的长句,模型可能会合并成一个 Token。然后,我们可以选择一个 Token,查看该 Token 在 embed (输入词表)和 head (输出词表)中,与其他 Token 的相似度分布。
然后我自己跑下来发现一些很有意思的事情:
我们查询纽约这个词,竟然近邻有洛杉矶、芝加哥、波士顿这些美国城市,也有英国伦敦,甚至还有 NYSE (纽约证券交易所)。
而我们搜北海道也很有意思,竟然会出现哈尔滨和夏威夷。
而我们搜清华大学,也会发现北京大学、浙江大学等学校相似度很高。
由此我们可以看到,LLM 自己的词表,本质上就已经是一本由训练数据驱动的字典了!而这些相近的 Token 在 hidden state 中的语义信息是相近的,因此在采样时就可能随机采样到其中一个近义词,导致输出的 Token 可能不是人类习惯的表达。
解决方案
这个问题其实是可以在训练中通过一些方法缓解的。比如针对近义词,我们可以在训练时对近义词的输出概率进行惩罚,这样他们的距离就会更远,我们如果去对比不同开源模型的相同 Token 的相似度分布,也许也可以看到一些差异。
也可以针对可以调整采样参数的 API / 自己推理,调整 temp=0,也就是 argmax,从而模型会输出最恰当的那个词而不是随机采样,也许也会缓解。
结语
LLM 的内部机制真神奇!通过理解它的工作原理,我们可以更好地利用它,同时也可以为未来的模型改进提供一些思路。


