跳转至

第 8 章:大语言模型如何记忆事实 —— 参数中的知识存储与检索

场景: 你问 ChatGPT"法国的首都是什么?",它毫不犹豫地回答"巴黎"。这个知识存储在哪里?LLM 没有数据库,没有知识图谱——所有知识都编码在模型的参数(权重矩阵)中。本章将揭示 LLM 如何在参数中存储和检索事实,以及为什么有时会"记错"(幻觉)。


8.1 知识存储在哪里?

注意力层 vs FFN 层

Transformer 的两个核心组件有不同的分工:

组件 功能 比喻
注意力层 从上下文中 检索 信息 搜索引擎——找到相关信息在哪里
FFN 层 存储和 提取 知识 百科全书——知识本身存储在这里

核心比喻:图书馆索引

注意力层 = 图书馆的 索引卡片 ,告诉你"关于法国的书在哪个书架" FFN 层 = 书架上的 书本身 ,包含"巴黎是法国首都"这个事实

当你问"法国的首都是什么?": 1. 注意力层找到与"法国"和"首都"相关的信息位置 2. FFN 层从参数中提取"巴黎"这个答案


8.2 FFN 层作为键值记忆(Key-Value Memory)

研究发现,FFN 层可以理解为一种 稀疏的键值记忆

\[FFN(x) = \max(0, xW_1 + b_1)W_2 + b_2\]
  • \(W_1\) 的第一层相当于 键(Key) :检测输入中是否包含特定模式
  • \(W_2\) 的第二层相当于 值(Value) :输出对应的知识
import numpy as np

def ffn_as_memory_demo():
    """
    演示 FFN 层如何作为键值记忆工作
    简化示例:存储"巴黎→法国首都"这个事实
    """
    embed_dim = 4
    ffn_dim = 8

    # 假设的嵌入向量
    x_france = np.array([1.0, 0.0, 0.0, 0.0])   # "法国"的嵌入
    x_capital = np.array([0.0, 1.0, 0.0, 0.0])  # "首都"的嵌入
    x_query = x_france + x_capital                # "法国首都"的查询向量

    # W1: 键矩阵 —— 检测"法国+首都"这个模式
    W1 = np.zeros((embed_dim, ffn_dim))
    W1[0, 0] = 1.0  # 检测"法国"特征
    W1[1, 0] = 1.0  # 检测"首都"特征
    # 其他神经元检测其他模式...

    b1 = np.array([-1.5, 0, 0, 0, 0, 0, 0, 0])  # 偏置:需要两个特征都激活

    # W2: 值矩阵 —— 输出"巴黎"的嵌入
    W2 = np.zeros((ffn_dim, embed_dim))
    W2[0, 2] = 1.0  # 第0个神经元激活时,输出"巴黎"特征
    b2 = np.zeros(embed_dim)

    # 前向传播
    hidden = np.maximum(0, np.dot(x_query, W1) + b1)  # ReLU
    output = np.dot(hidden, W2) + b2

    print(f"查询向量 (法国+首都): {x_query}")
    print(f"隐藏层激活: {hidden}")
    print(f"  → 神经元 0 激活值: {hidden[0]:.1f} (检测到'法国首都'模式!)")
    print(f"FFN 输出: {output}")
    print(f"  → 第 3 维激活 (代表'巴黎'): {output[2]:.1f}")
    print(f"\n解读: FFN 检测到'法国+首都'模式 → 输出'巴黎'的嵌入表示")

ffn_as_memory_demo()

渲染效果:

查询向量 (法国+首都): [1. 1. 0. 0.]
隐藏层激活: [0.5 0.  0.  0.  0.  0.  0.  0. ]
  → 神经元 0 激活值: 0.5 (检测到'法国首都'模式!)
FFN 输出: [0.  0.  0.5 0. ]
  → 第 3 维激活 (代表'巴黎'): 0.5

解读: FFN 检测到'法国+首都'模式 → 输出'巴黎'的嵌入表示


8.3 知识定位:找到存储特定事实的神经元

近年来,研究者发现可以 定位 LLM 中存储特定知识的参数:

def knowledge_localization_concept():
    """
    知识定位的核心思想(概念演示)
    """
    print("知识定位研究的关键发现:")
    print()

    findings = [
        ("事实存储在 FFN 层", 
         "修改 FFN 层的参数可以改变模型对事实的记忆"),
        ("知识是分布式的", 
         "一个事实通常分布在多个神经元中,而非单个"),
        ("中层存储事实最多", 
         "Transformer 的中间层(而非底层或顶层)存储了最多的事实知识"),
        ("可编辑性", 
         "通过修改特定 FFN 神经元的权重,可以'编辑'模型的知识"),
    ]

    for title, desc in findings:
        print(f"  [{title}]")
        print(f"    {desc}")
        print()

knowledge_localization_concept()

渲染效果:

知识定位研究的关键发现:

  [事实存储在 FFN 层]
    修改 FFN 层的参数可以改变模型对事实的记忆

  [知识是分布式的]
    一个事实通常分布在多个神经元中,而非单个

  [中层存储事实最多]
    Transformer 的中间层(而非底层或顶层)存储了最多的事实知识

  [可编辑性]
    通过修改特定 FFN 神经元的权重,可以'编辑'模型的知识


8.4 模型如何检索知识:从输入到答案的完整路径

当用户问"法国的首都是什么?"时,LLM 内部发生了什么?

步骤1: Tokenization
  "法国的首都是什么?" → [法国, 的, 首都, 是, 什么, ?]

步骤2: 嵌入 + 位置编码
  每个 token → 稠密向量 (如 12288 维)

步骤3: 逐层处理 (GPT-3: 96 层)
  第 1-10 层:  理解基本语法结构
  第 11-30 层: 识别"法国"和"首都"的语义关联
  第 31-60 层: 注意力层聚焦"法国"→ FFN 层检索相关知识
  第 61-90 层: 整合检索到的知识,形成"巴黎"的表示
  第 91-96 层: 准备输出,将内部表示转换为词汇概率

步骤4: 输出
  最后一个位置的向量 → Linear → Softmax → "巴黎"概率最高
def knowledge_retrieval_pathway():
    """模拟知识检索的信息流"""

    layers = 96
    print(f"GPT-3 ({layers} 层) 处理 '法国的首都是什么?' 的信息流:")
    print("=" * 60)

    stages = [
        (1, 10, "语法解析", "识别'法国'是名词、'首都'是名词、'是'是动词"),
        (11, 30, "语义关联", "将'法国'和'首都'建立语义联系"),
        (31, 60, "知识检索", "FFN 层从参数中提取'法国→巴黎'的事实"),
        (61, 90, "答案整合", "将'巴黎'的表示整合到输出位置"),
        (91, 96, "输出准备", "将内部表示映射到词汇表,'巴黎'概率最高"),
    ]

    for start, end, stage_name, description in stages:
        bar = "█" * (end - start + 1)
        print(f"  第 {start:2d}-{end:2d} 层 [{stage_name}]")
        print(f"    {description}")
        print(f"    [{bar}]")
        print()

knowledge_retrieval_pathway()

渲染效果:

GPT-3 (96 层) 处理 '法国的首都是什么?' 的信息流:
============================================================
  第  1-10 层 [语法解析]
    识别'法国'是名词、'首都'是名词、'是'是动词
    [██████████]

  第 11-30 层 [语义关联]
    将'法国'和'首都'建立语义联系
    [████████████████████]

  第 31-60 层 [知识检索]
    FFN 层从参数中提取'法国→巴黎'的事实
    [██████████████████████████████]

  第 61-90 层 [答案整合]
    将'巴黎'的表示整合到输出位置
    [██████████████████████████████]

  第 91-96 层 [输出准备]
    将内部表示映射到词汇表,'巴黎'概率最高
    [██████]


8.5 为什么 LLM 会产生幻觉?

幻觉(Hallucination)——模型编造看似合理但错误的事实——是 LLM 最棘手的问题之一。

幻觉的三种来源

类型 原因 示例
知识缺失 训练数据中没有这个事实 问一个冷门历史事件,模型编造细节
知识冲突 训练数据中有矛盾的信息 不同来源对同一事件有不同描述
生成偏差 模型倾向于生成"流畅"而非"准确"的文本 模型编造了一个听起来合理的引用
def hallucination_mechanism():
    """
    从"预测下一个词"的角度理解幻觉
    """
    print("幻觉的生成机制:")
    print()

    print("正常情况(知识存在):")
    print("  输入: '法国的首都是'")
    print("  FFN 激活: '法国+首都'模式 → 输出'巴黎'特征")
    print("  预测: '巴黎' (概率 0.95)")
    print()

    print("幻觉情况(知识缺失或冲突):")
    print("  输入: 'X星的首都是'")
    print("  FFN 激活: 没有匹配的模式")
    print("  但模型仍然需要输出一个词!")
    print("  → 模型根据语言模式猜测: '首都'后面常跟城市名")
    print("  → 模型编造: '新希望城' (听起来像首都的名字)")
    print()

    print("核心矛盾:")
    print("  LLM 的本质是'预测最可能的下一个词'")
    print("  而非'检索最准确的事实'")
    print("  当知识缺失时,它会用语言流畅性来填补空白")

hallucination_mechanism()

渲染效果:

幻觉的生成机制:

正常情况(知识存在):
  输入: '法国的首都是'
  FFN 激活: '法国+首都'模式 → 输出'巴黎'特征
  预测: '巴黎' (概率 0.95)

幻觉情况(知识缺失或冲突):
  输入: 'X星的首都是'
  FFN 激活: 没有匹配的模式
  但模型仍然需要输出一个词!
  → 模型根据语言模式猜测: '首都'后面常跟城市名
  → 模型编造: '新希望城' (听起来像首都的名字)

核心矛盾:
  LLM 的本质是'预测最可能的下一个词'
  而非'检索最准确的事实'
  当知识缺失时,它会用语言流畅性来填补空白


8.6 知识编辑:修改模型记住的事实

一个令人兴奋的研究方向是 知识编辑 ——在不重新训练的情况下修改模型存储的事实:

def knowledge_editing_concept():
    """知识编辑的概念演示"""

    print("知识编辑技术概览:")
    print("=" * 50)

    techniques = [
        ("ROME (Rank-One Model Editing)", 
         "定位存储特定事实的 FFN 层,用秩一更新修改权重",
         "将'埃菲尔铁塔在罗马'改为'埃菲尔铁塔在巴黎'"),

        ("MEND (Model Editor Networks)", 
         "训练一个辅助网络,根据编辑请求生成权重更新",
         "批量修改模型中的过时知识"),

        ("In-Context Editing", 
         "不修改参数,通过精心设计的提示词覆盖旧知识",
         "在系统提示中告诉模型'X 的新首都是 Y'"),
    ]

    for name, method, example in techniques:
        print(f"\n  [{name}]")
        print(f"    方法: {method}")
        print(f"    示例: {example}")

knowledge_editing_concept()

渲染效果:

知识编辑技术概览:
==================================================

  [ROME (Rank-One Model Editing)]
    方法: 定位存储特定事实的 FFN 层,用秩一更新修改权重
    示例: 将'埃菲尔铁塔在罗马'改为'埃菲尔铁塔在巴黎'

  [MEND (Model Editor Networks)]
    方法: 训练一个辅助网络,根据编辑请求生成权重更新
    示例: 批量修改模型中的过时知识

  [In-Context Editing]
    方法: 不修改参数,通过精心设计的提示词覆盖旧知识
    示例: 在系统提示中告诉模型'X 的新首都是 Y'


8.7 记忆 vs 理解:LLM 真的"知道"吗?

一个深刻的哲学问题:LLM 是在 真正理解 知识,还是仅仅 模式匹配

def memory_vs_understanding():
    """探讨 LLM 的记忆与理解"""

    print("记忆 vs 理解 —— LLM 的能力边界:")
    print("=" * 55)

    comparisons = [
        ("记忆", "理解"),
        ("能回答'法国的首都是什么'", "能推理'如果法国迁都到里昂,对欧洲经济有何影响'"),
        ("能背诵'勾股定理: a²+b²=c²'", "能证明勾股定理,并推广到 n 维空间"),
        ("能写出'for i in range(10)'", "能设计全新的算法解决未见过的编程问题"),
        ("基于训练数据中的模式", "基于对世界因果结构的建模"),
    ]

    for left, right in comparisons:
        print(f"  {left:<20} | {right}")

    print(f"\n  当前共识: LLM 处于'记忆'和'理解'之间的灰色地带")
    print(f"  它展现了一些理解能力(如思维链推理),")
    print(f"  但这些能力可能源于对海量推理模式的记忆和重组。")

memory_vs_understanding()

渲染效果:

记忆 vs 理解 —— LLM 的能力边界:
=======================================================
  记忆                   | 理解
  能回答'法国的首都是什么'         | 能推理'如果法国迁都到里昂,对欧洲经济有何影响'
  能背诵'勾股定理: a²+b²=c²'    | 能证明勾股定理,并推广到 n 维空间
  能写出'for i in range(10)'  | 能设计全新的算法解决未见过的编程问题
  基于训练数据中的模式             | 基于对世界因果结构的建模

  当前共识: LLM 处于'记忆'和'理解'之间的灰色地带
  它展现了一些理解能力(如思维链推理),
  但这些能力可能源于对海量推理模式的记忆和重组。


要点总结

  • 注意力层负责检索,FFN 层负责存储和提取知识
  • FFN 层可理解为键值记忆:\(W_1\) 检测模式(Key),\(W_2\) 输出知识(Value)
  • 知识是分布式的,存储在多个神经元中,中层存储最多
  • 知识检索路径:语法解析 → 语义关联 → FFN 提取 → 答案整合 → 输出
  • 幻觉源于"预测下一个词"与"检索准确事实"之间的根本矛盾
  • 知识编辑技术可以在不重新训练的情况下修改模型的知识
  • LLM 的理解能力仍是一个开放问题

课后练习

  1. 知识定位实验 :如果你能访问一个开源 LLM(如 Llama),尝试用不同的提示词探测模型对同一事实的"记忆强度"。

  2. 幻觉复现 :问 ChatGPT 一个它很可能不知道的冷门问题(如"2027 年奥运会在哪个城市举办"),观察它是诚实回答"不知道"还是编造答案。

  3. 思考题 :如果 LLM 的知识存储在 FFN 层的参数中,为什么增加上下文长度(更多 token)能让模型回答更准确?这两种"知识来源"(参数 vs 上下文)有什么区别?


教程总结

恭喜你完成了全部 8 章的学习!让我们回顾一下你学到了什么:

章节 核心收获
第 1 章 神经元 = 加权求和 + 激活函数;网络 = 多层堆叠
第 2 章 梯度下降 = 沿负梯度方向逐步逼近最优解
第 3 章 反向传播 = 链式法则让梯度从输出反向流到输入
第 4 章 链式法则的数学本质 + Softmax 梯度的优雅公式
第 5 章 LLM = 预测下一个词的超级预测机
第 6 章 Transformer = 自注意力 + FFN + 残差 + 层归一化
第 7 章 注意力 = Q·K → Softmax → 加权 V;多头 = 多角度
第 8 章 FFN = 键值记忆;知识分布式存储;幻觉的根源

下一步学习建议

  1. 动手实践 :用 PyTorch 从零实现一个 GPT-2 级别的模型(参考 Andrej Karpathy 的 nanoGPT)
  2. 深入理论 :阅读《Attention Is All You Need》原论文和《Deep Learning》教材
  3. 跟进前沿 :关注 RAG(检索增强生成)、Agent、多模态 LLM 等最新方向

感谢你的学习! 如果本教程对你有帮助,欢迎分享给更多对 AI 感兴趣的朋友。

← 返回教程首页