查看全课大纲(第 47 / 69 节)
- 1.NLP 的研究领域、应用与学习路径
- 2.自然语言的基本术语
- 3.信息论基础:信息熵与交叉熵
- 4.语言的进化与语义变迁
- 5.主观概率、客观概率与条件概率
- 6.贝叶斯原理与推理
- 7.随机变量:二项式、期望方差与联合概率
- 8.常见概率分布
- 9.辛普森悖论与贝叶斯解题实例
- 10.语言模型:语言概率与词袋模型
- 11.n-gram 语言模型(二元 / 三元 / N-Gram)
- 12.语言模型评价:交叉熵、困惑度与插值
- 13.朴素贝叶斯文本分类:垃圾邮件
- 14.拼写检查
- 15.中文分词:构词法、最大匹配、最优路径与 Jieba
- 16.词表示问题与语义相似度
- 17.TF-IDF 权重处理
- 18.One-Hot 表达与词表示的局限
- 19.Word2Vec 核心思想
- 20.Word2Vec 训练过程
- 21.Skip-gram 模型详解
- 22.词性标注任务与标注方法(规则 + N-Gram)
- 23.EM 算法与混合模型
- 24.高斯混合模型 GMM
- 25.从混合模型到隐马尔可夫模型
- 26.隐马尔可夫模型(HMM)推导与维特比解码
- 27.线性链条件随机场 CRF
- 28.贝叶斯网络与图模型
- 29.隐马尔可夫链与 HMM 推导
- 30.PLSA 主题模型
- 31.LSI 与 SVD 向量表达
- 32.LDA 与狄利克雷分布
- 33.主题模型实验复现(困惑度 / 分类 / 相似度 / 延展)
- 34.上下文无关文法(CFG)与句法分析
- 35.概率上下文无关文法 PCFG
- 36.统计机器翻译:词对齐与翻译模型
- 37.统计机器翻译中的对齐模型与参数估计
- 38.从统计机器翻译到神经机器翻译
- 39.神经元与反向传播速览(指向深度学习课)
- 40.CNN 原理及其在 NLP 中的应用
- 41.循环神经网络的基本原理与 Elman / Jordan 网络
- 42.LSTM:长短期记忆网络的核心思想与分步实现
- 43.Encoder-Decoder 框架
- 44.Seq2Seq 与早期注意力机制
- 45.注意力机制的背景与动机
- 46.注意力模型实现原理与匹配函数
- 47.记忆网络:组成与计算
- 48.注意力机制的应用与历史延展
- 49.Transformer 结构:Encoder-Decoder 栈与 Self-Attention
- 50.Multi-Head Attention、FFNN 与位置编码
- 51.层归一化、损失函数与 Universal Transformer 延展
- 52.预训练范式:从 ELMo 到 BERT
- 53.BERT 与掩码语言模型
- 54.BERT 下游任务微调与 GLUE 口径
- 55.GPT 与自回归语言建模
- 56.GPT-1 到 GPT-4 的演进
- 57.指令微调与 RLHF
- 58.分词器:BPE、WordPiece 与中文词表
- 59.上下文窗口与长文本处理
- 60.能力边界、成本与适用场景
- 61.文本分类实战:从朴素贝叶斯到逻辑回归
- 62.命名实体识别实战
- 63.文本生成与摘要实战
- 64.语义检索与向量库实战
- 65.RAG 知识库问答
- 66.NLP 评估指标:BLEU / ROUGE / BERTScore 与人工评估
- 67.幻觉与事实性问题
- 68.文本与知识结合(知识图谱压缩)
- 69.跨媒体信息检索与未来展望
记忆网络:组成与计算
小象实战讲义 · 自然语言处理
在上一节中,我们学习了注意力机制,它让模型在处理序列时能够动态地聚焦于输入的不同部分。然而,注意力机制通常作用于当前输入序列的“内部记忆”。如果我们希望模型能够访问一个更大、更持久的外部知识库,并像人类一样进行多步推理,就需要更强大的架构。本节将介绍记忆网络(Memory Network),它通过引入一个可读写的“外部记忆”模块,将注意力机制扩展为一个可以进行复杂推理的系统。理解记忆网络是通往现代大模型(如 Transformer)中“键值记忆”思想的重要桥梁。
💡 核心导读
- 记忆网络的动机:模拟人脑的长期记忆与短期推理过程,解决需要多步事实检索的复杂问答任务。
- 四大核心组件:输入映射(I)、泛化更新(G)、输出生成(O)和响应转换(R),构成了记忆网络的基本框架。
- 计算过程:通过“寻址-读取”的迭代循环(Hops),将查询与外部记忆进行注意力匹配,逐步精炼答案。
- 实现方法:将事实和查询向量化,通过点积计算注意力权重,进行加权求和以组合记忆信息。
- 与现代模型的关系:记忆网络是注意力机制的延伸,其“外部记忆”和“多跳推理”思想深刻影响了后续的 Transformer 等模型。
记忆网络的动机与核心思想
在传统的序列模型(如带注意力的 LSTM)中,模型主要关注当前输入序列的信息。记忆网络则提出了一个更宏大的设想:将所有相关的数据存储在一个大的外部记忆表格中,模型可以像访问数据库一样,根据需要从中读取和更新信息。
这个过程模拟了人类的认知:
- 短期记忆:当你被问到“今天吃了什么?”,你能立刻回答“炒饭或油条”,因为这是刚发生的、印象深刻的事件。
- 长期记忆检索:当被问及“正态分布的重要参数是什么?”,你需要从长期存储的数学知识中检索,这个过程可能涉及多步联想。
记忆网络正是为了实现这种对外部记忆的访问和基于记忆的推理而设计的。它本质上是注意力机制的一种延伸和泛化,将注意力对象从一个固定的输入序列,扩展到了一个动态、可读写的大规模记忆库。
记忆网络的四大组件
一个标准的记忆网络(Memory Neural Network, MemNN)主要由四个核心组件构成,通常用 I、G、O、R 来表示。
输入 (Input) -> I (Input Feature Map) -> 内部表示
|
v
G (Generalization) -> 更新记忆 (Memory)
|
v
O (Output) -> 结合输入与记忆生成输出向量
|
v
R (Response) -> 将输出向量转换为最终答案1. 输入映射(I: Input Feature Map)
功能:将原始输入(如自然语言句子)转换为模型内部的向量表示。 实现方式:这与我们之前学习的所有词/句表示方法一脉相承。可以是:
- 词袋模型(Bag-of-Words) 向量。
- 独热编码(One-Hot) 向量。
- 词嵌入(Word2Vec, GloVe) 向量。
- RNN/CNN 编码器 输出的句子向量。 目标:将文本转化为模型可以统一计算的数学对象(向量)。
2. 泛化更新(G: Generalization)
功能:根据新的输入信息,更新外部记忆(Memory)。 实现方式:更新策略可以很灵活:
- 最简单:将新输入作为一个新的事实(向量)直接存入记忆的下一个空位。
- 覆盖更新:找到最不常用或最不相关的旧记忆,用新信息覆盖它(类似于缓存替换策略)。
- 融合更新:将新信息与旧记忆进行加权平均或求和,实现知识的融合与迭代。 类比:学习一个新概念可能让你对旧知识“豁然开朗”(整体更新),而尝到一种新口味的奶茶只是在你“奶茶记忆库”里新增一条记录(局部新增)。
3. 输出生成(O: Output)
功能:结合当前的输入(查询)和更新后的记忆,生成一个输出向量。 输入:当前输入的内部表示向量 + 整个外部记忆库。 过程:计算输入向量与记忆库中每个记忆向量的相关性(如点积),得到一组寻址权重。这里要区分两种实现:原始 MemNN 的 O 组件用 argmax 选出若干个“支持记忆”(离散检索);端到端记忆网络(E2EMN)则做连续软读取,每条记忆有两个表示——由嵌入矩阵 A 得到的输入记忆表示 m_i 和由另一嵌入矩阵 C 得到的输出记忆表示 c_i,权重 p_i = softmax(u^T m_i),输出 o = Σ_i p_i c_i。下面的教学示例为简化起见令 c_i = m_i(寻址与读出用同一组向量),这只是特殊设定,并非端到端模型的一般形式。 核心:o 向量编码了针对当前查询,从外部记忆中检索到的最相关信息。
4. 响应转换(R: Response)
功能:将内部输出向量 o 转换回现实世界可理解的输出形式,如一个词、一句话或一个动作。 实现方式:可以是一个分类器(从词表中选择最可能的词),也可以是一个语言模型解码器(生成一个句子)。 目标:完成从内部计算到最终答案的“最后一公里”。
记忆网络的计算过程:迭代寻址(Hops)
记忆网络强大的推理能力来自于其多跳(Multi-hop) 计算过程。一个“跳(Hop)”代表一次完整的“寻址(Addressing)- 读取(Read)”循环。复杂问题往往需要多跳推理才能解决。
单跳计算示例
我们通过一个简单的问答任务来理解单跳计算。
事实(记忆 m):
Sam moved to garden.Sam went to kitchen.Sam drops apple there.
查询(Query q): Where is Sam?
计算步骤:
- 向量化:使用词袋模型或词向量求和,将每个事实和查询转换为向量
m1, m2, m3和q。 - 计算注意力权重:计算查询向量
q与每个记忆向量mi的点积(相似度),然后通过 softmax 归一化为概率分布(注意力权重)。# 示例:计算点积相似度与softmax权重(伪代码逻辑) import numpy as np # 假设记忆向量和查询向量(维度为3) memory_vectors = np.array([ [0.8, 0.1, 0.1], # m1: Sam moved to garden [0.1, 0.9, 0.0], # m2: Sam went to kitchen [0.2, 0.2, 0.6] # m3: Sam drops apple there ]) query_vector = np.array([0.1, 0.8, 0.1]) # q: Where is Sam? (假设'Sam'和'kitchen'权重高) # 计算点积相似度 similarities = np.dot(memory_vectors, query_vector) # 形状 (3,) # 点积相似度结果为: [0.17, 0.73, 0.24] # 计算softmax注意力权重 exp_s = np.exp(similarities - np.max(similarities)) # 数值稳定性 attention_weights = exp_s / np.sum(exp_s) print("注意力权重:", np.round(attention_weights, 4))
注意力权重: [0.2616 0.4579 0.2805]*注意:此处的权重是示例,实际训练中模型会学习到 `m2`(包含“kitchen”)与查询更相关。*3. 加权求和,生成输出:用注意力权重对记忆表示进行加权求和,得到输出向量 o(本简化示例中读出记忆与寻址记忆取同一组向量;端到端模型分别使用 c_i 与 m_i)。 ```python import numpy as np
# 重新构建同一组记忆向量与查询向量(本块独立可运行)
memory_vectors = np.array([
[0.8, 0.1, 0.1], # m1: Sam moved to garden
[0.1, 0.9, 0.0], # m2: Sam went to kitchen
[0.2, 0.2, 0.6] # m3: Sam drops apple there
])
query_vector = np.array([0.1, 0.8, 0.1]) # q: Where is Sam?
# 重新计算点积相似度与 softmax 注意力权重
similarities = np.dot(memory_vectors, query_vector)
exp_s = np.exp(similarities - np.max(similarities))
attention_weights = exp_s / np.sum(exp_s)
# 加权求和,生成输出向量 o
output_vector = np.dot(attention_weights, memory_vectors)
print("输出向量 o:", np.round(output_vector, 4))
```输出向量 o: [0.3111 0.4944 0.1945]- 生成响应:输出向量
o经过响应组件R(例如一个分类器),映射到词表中最可能的答案词,如“kitchen”。
多跳推理的必要性
有些问题不能通过直接匹配解决,需要链式推理。
任务示例(两个支持事实):
John is in the playground.John picked up the football.查询:Where is the football?
推理链:
- 第一跳(Hop 1):查询
q = "Where is the football?"。记忆中最相关的事实是"John picked up the football.",因为它直接包含“football”。这一跳的输出o1编码了“John”和“football”的关联。 - 第二跳(Hop 2):端到端记忆网络按
u^{k+1} = u^k + o^k更新查询(层共享变体为u^{k+1} = H u^k + o^k),即把第一跳输出o1叠加回当前查询u1,新状态同时保留原查询信息与第一跳检索结果,再用u2对记忆做第二跳注意力。此时,与u2最相关的事实变成了"John is in the playground.",因为它包含了“John”。这一跳的输出o2最终指向了答案“playground”。(原始 MemNN 的第二次匹配则把原输入x与已选支持记忆m_{o1}拼接在一起作为新的匹配条件,而不是只使用o1。)
通过这种迭代的“寻址-读取”过程,记忆网络能够进行多步逻辑推理,从而回答更复杂的问题。
实现细节与扩展
记忆向量构建
- 句子向量:通常对句子中每个词的词向量求和或取平均。
- 时序信息:为了区分多条事实在故事中的写入位置或相对时间顺序,可以引入时间编码(Temporal Encoding)。端到端记忆网络为语句索引
i学习时间向量T_A(i)、T_C(i),分别加到输入记忆表示与输出记忆表示上(语句还可按与问题的相对距离反向编号);时间特殊词也可纳入词袋表示。需要注意:过去式、现在式等时态本身表达的是语法时态,并不承担多条事实写入顺序与相对距离的编码职责。
目标函数与训练
下面这种带逐跳支持事实标签的 margin ranking loss,是原始 MemNN 的强监督训练目标:对于需要 k 个支持事实的问题,训练数据标出了支持句,目标函数鼓励模型:
- 在第一跳,让真实第一个支持事实的匹配分数高于其他事实一个边界值(Margin)。
- 在第二跳,让真实第二个支持事实的匹配分数高于其他事实。
- 最终,让真实答案的匹配分数高于其他候选答案。
前文介绍的端到端连续多跳模型则通常只依据最终的问答对,用预测答案与真实答案之间的交叉熵联合训练各跳,训练时不再要求逐跳提供支持事实标签,监督信号显著减少;不要把逐跳支持事实标签写成所有记忆网络的必备条件。
与现代架构的关联
记忆网络的思想对后续模型产生了深远影响:
- 键值记忆:记忆网络中的“寻址”类似于根据“键”(记忆向量)查询,“读取”的是对应的“值”(读出记忆表示)。这种“用查询匹配键、对值加权读取”的形式,与 Transformer 的键-值(Key-Value)注意力机制在计算形式上可以类比;但原论文并未记载记忆网络对键值注意力存在直接的谱系启发关系。
- 外部知识集成:记忆网络明确了将知识存储在外部模块中的理念,这与当前检索增强生成(RAG)系统的核心思想一脉相承。
- 与 Transformer 的形式类比:记忆网络的多跳推理是顺序读取外部记忆。Transformer 通过自注意力机制在单层内并行访问所有位置,层堆叠捕获复杂依赖;二者都包含查询匹配和对值的加权读取,但 Transformer 的核心是缩放点积与多头自注意力,其层堆叠是序列内部表示层,并不是对外部记忆进行顺序多跳检索,也不能称为记忆网络思想的并行化实现。
📝 动手练一练
- 概念辨析:记忆网络中的“泛化(G)”组件和注意力机制中的“权重计算”有何本质区别?
- 手算推理:假设我们有三个记忆向量(已归一化)和查询向量如下:
m1 = [0.9, 0.1, 0.0](事实A)m2 = [0.0, 0.9, 0.1](事实B)m3 = [0.1, 0.0, 0.9](事实C)q = [0.1, 0.8, 0.1](查询) 请计算查询q与每个记忆向量的点积相似度,并通过 softmax 计算注意力权重。根据权重,模型更关注哪个事实?
👉 点击查看参考答案
区别:
- 注意力机制的权重计算:是在当前前向传播过程中,动态计算输入序列各部分对当前解码状态的重要性,用于信息加权求和。它不持久化改变模型参数或记忆内容。
- 记忆网络的泛化(G)组件:是根据新输入更新记忆的策略,可以采用固定规则,也可以学习;最简单的实现仅将新输入的表示写入下一空槽位,此时更新规则本身不需要学习。它用于根据新输入持久地修改外部记忆库的内容,改变了模型下一次推理时所依赖的知识基础,实现了长期记忆的更新和积累。
手算推理:
- 计算点积相似度:
sim1 = 0.9*0.1 + 0.1*0.8 + 0.0*0.1 = 0.09 + 0.08 + 0.0 = 0.17sim2 = 0.0*0.1 + 0.9*0.8 + 0.1*0.1 = 0.0 + 0.72 + 0.01 = 0.73sim3 = 0.1*0.1 + 0.0*0.8 + 0.9*0.1 = 0.01 + 0.0 + 0.09 = 0.10 - 计算 softmax:先求指数(以 e 为底),
exp(0.17)≈1.185, exp(0.73)≈2.075, exp(0.10)≈1.105。总和S≈4.365。weight1 = 1.185 / 4.365 ≈ 0.271weight2 = 2.075 / 4.365 ≈ 0.475weight3 = 1.105 / 4.365 ≈ 0.253 - 结论:注意力权重最高的是
weight2 ≈ 0.475,因此模型最关注事实B (m2)。
- 计算点积相似度:
本章小结
记忆网络为我们展示了一种将神经网络与符号式记忆、推理相结合的有力范式。它通过引入可读写的外部记忆模块和迭代的多跳推理机制,解决了传统序列模型在复杂、多步推理任务上的局限性。其核心思想——将知识存储于外部,通过注意力机制进行检索和组合——成为了连接经典注意力与现代大模型(特别是 Transformer 和 RAG)的关键桥梁。
📋 行动清单
- 理解四大组件:能够清晰阐述 I、G、O、R 每个组件在记忆网络中的作用。
- 模拟单跳计算:给定简单的记忆向量和查询向量,能手动完成点积、softmax 和加权求和的计算流程。
- 关联现代技术:思考记忆网络的“外部记忆”和“多跳推理”思想,在当今的 Transformer 模型或 RAG 系统中是如何体现和演进的。
—— 小象教研组