理解这个叫做“世界”的操作系统
灵光一现 → 精巧实现 → 无人知晓 → 自己遗忘,几乎是每个认真思考的工程师都会经历的隐性知识流失
用 PyTorch 从头实现语言模型
《Speech and Language Processing》(2025版草稿)中文版
理解这个叫做“世界”的操作系统
灵光一现 → 精巧实现 → 无人知晓 → 自己遗忘,几乎是每个认真思考的工程师都会经历的隐性知识流失
用 PyTorch 从头实现语言模型
《Speech and Language Processing》(2025版草稿)中文版
本章介绍了用于语言建模任务的 Transformer 及其各个组成部分。 我们将在下一章继续探讨语言建模的相关问题,包括训练和采样等。 以下是本章涵盖的主要内容总结: Transformer 是一种基于多头注意力(multi-head attention)的非循环神经网络,而多头注意力是一种自注意力(self-attention)机制。多头注意力计算通过将先前词元的向量(根据它们与当前词处理的相关性进行加权)累加进来,将输入向量 $\mathbf{x}_i$ 映射为输出向量 $\mathbf{a}_i$。 一个Transformer 模块(transformer block)包含一个残差流(residual stream),其中来自前一层的输入会直接传递到下一层,并与不同组件的输出相加。这些组件包括一个多头注意力层,后接一个前馈层,每个组件之前都带有层归一化(layer normalization)。通过堆叠多个 Transformer 模块,可以构建出更深、更强大的网络。 Transformer 的输入是通过将一个嵌入(由嵌入矩阵计算得出)与一个表示词元在上下文窗口中序列位置的位置编码(positional encoding)相加得到的。 语言模型可以通过堆叠 Transformer 模块来构建,在顶部配有一个语言模型头(language model head)。该头部将一个解嵌入(unembedding)矩阵应用于顶层的输出 $H$,以生成逻辑值(logits),然后通过 softmax 函数生成词的概率分布。 基于 Transformer 的语言模型拥有非常宽的上下文窗口(对于大型模型,可宽达 32768 个词元),这使得它们能够利用海量的上下文信息来预测下一个词。 文献与历史注记 Transformer (Vaswani et al., 2017) 的发展借鉴了两条先前的研究路线:自注意力(self-attention)和记忆网络(memory networks)。 编码器-解码器注意力(encoder-decoder attention)的思想——即使用对输入词编码的软权重来指导生成式解码器(见第13章)——最初由 Graves (2013) 在手写生成的背景下提出,并由 Bahdanau 等人 (2015) 应用于机器翻译(MT)。 这一思想后来被扩展到自注意力机制:不再需要区分独立的编码和解码序列,而是将注意力视为一种对词元进行加权的方式,用以汇集从较低层传递到较高层的信息(Ling et al., 2015; Cheng et al., 2016; Liu et al., 2016)。 Transformer 的其他一些方面,包括键(key)、查询(query)和值(value)的术语,则来源于记忆网络(memory networks)。 记忆网络是一种为神经网络添加外部读写存储器的机制,其核心是使用查询的嵌入去匹配关联记忆中代表内容的键(Sukhbaatar et al., 2015; Weston et al., 2015; Graves et al., 2014)。 ...
“真正的记忆艺术在于专注。” 塞缪尔·约翰逊,《闲者》第74篇,1759年9月 本章将介绍 Transformer,这是构建大语言模型的标准架构。 正如上一章所言,基于 Transformer 的大语言模型彻底改变了语音与语言处理领域。 事实上,本书后续每一章都将用到这一技术。 和上一章一样,本章我们主要关注从左到右(有时也称为因果式或自回归)的语言建模方式,即给定一个输入词元(token)序列,模型根据先前的上下文逐个预测下一个输出词元。 Transformer 是一种具有特定结构的神经网络,其核心机制被称为自注意力(self-attention)或多头注意力(multi-head attention)1。 注意力机制可以理解为一种方法,通过“关注”并整合周围词元的信息,来构建某个词元在上下文中的语义表示,从而帮助模型学习长距离内词元之间的关联。 图 8.1 展示了一个(从左到右的)Transformer 架构,说明了每个输入词元如何被编码,经过一系列堆叠的 Transformer 模块(block),最终由语言模型头部预测下一个词元。 图8.1 概述了 Transformer 的基本结构。 一个完整的 Transformer 模型包含三个主要组成部分。 居于核心的是若干列堆叠的 Transformer 模块(blocks)。 每个模块是一个多层网络,包含一个多头注意力层、前馈网络以及层归一化(layer normalization)等操作,它将第 $i$ 列的输入向量 $\mathbf{x}_i$(对应第 $i$ 个输入词元)映射为输出向量 $\mathbf{h}_i$。 整组 $n$ 个模块共同将一个长度为 $n$ 的上下文窗口内的输入向量序列($\mathbf{x}_1,...,\mathbf{x}_n$)映射为一个等长的输出向量序列($\mathbf{h}_1,...,\mathbf{h}_n$)。 每个“列”通常包含 12 到 96 个甚至更多堆叠的模块。 在模块列之前是输入编码(input encoding)组件,它负责将一个输入词元(例如单词 “thanks”)处理成一个具有上下文意义的向量表示,这通常通过一个嵌入矩阵 $\mathbf{E}$(embedding matrix $\mathbf{E}$)以及一种对词元位置进行编码的机制来实现。 在模块列之后是语言模型头(language modeling head),它接收最后一个 Transformer 模块输出的嵌入表示,将其通过一个解嵌入矩阵 $\mathbf{U}$(unembedding matrix $\mathbf{U}$),再经过一个针对整个词汇表的 softmax 函数,最终为该位置生成一个预测词元。 基于 Transformer 的语言模型结构复杂,其细节将在接下来的几章中逐步展开。 第 7 章已经介绍了如何预训练模型,如何通过采样(sampling)生成词元。 在本章接下来的几节中,我们将介绍多头注意力机制、Transformer 模块的其余部分,以及输入编码和语言模型头部等组件。 第 10 章将介绍掩码语言建模(masked language modeling)以及基于双向 Transformer 编码器的 BERT 系列模型。 第 9 章将展示如何通过提供指令和示例来提示(prompt)大语言模型,使其执行各类自然语言处理任务,以及如何通过对齐(align)技术使模型的输出符合人类偏好。 第 12 章将介绍使用编码器-解码器(encoder-decoder)架构进行机器翻译的方法。 ...
“我能很好地感知很多维度,只要这些维度大约是二维的。” 已故经济学家 马丁·舒比克 可视化嵌入向量对于帮助我们理解、应用和改进这些词义模型至关重要。 但如何可视化一个(例如)100维的向量呢? 图8:针对三类名词的多维尺度分析(Multidimensional scaling)。 图9:基于向量相关性距离的三类名词层次聚类。 要可视化一个嵌入在空间中的词 w 的词义,最简单方法是列出与 w 最相似的词,即按词汇表中所有词向量与 w 的向量之间的余弦相似度进行排序。 例如,使用GloVe算法计算出的某个嵌入向量,与 frog (青蛙)最接近的7个词是:frogs(青蛙,复数)、toad(蟾蜍)、litoria(雨滨蛙属)、leptodactylidae(细趾蟾科)、rana(蛙属)、lizard(蜥蜴)和 eleutherodactylus(细趾蟾属)(Pennington 等, 2014)。 另一种可视化方法是使用聚类算法,展示嵌入空间中哪些词彼此相似的层次结构。 左侧未加标题的图例使用了对部分名词嵌入向量进行层次聚类的方法作为可视化手段(Rohde 等, 2006)。 然而,目前最常见的可视化方法可能是将词的 100 维空间投影到二维空间中。 图 6.1 和图 6.16 展示了这样一种可视化效果,它们使用了一种称为 t-SNE 的投影方法(van der Maaten 和 Hinton, 2008)。 6.8 Word2vec 目录 6.10 嵌入向量的语义特性
在前面的章节中,我们了解了如何将一个词表示为稀疏的长向量,其维度对应于词汇表中的词或文档集合中的文档。 现在,我们介绍一种更强大的词表示方法:嵌入(embeddings),即短而稠密的向量。 与迄今为止所见的向量不同,嵌入向量是短的,其维度 $d$ 通常在50到1000之间,远小于之前遇到的庞大词汇量 $|V|$ 或文档数量 $D$。 这些维度 $d$ 并没有明确的解释意义。 并且这些向量是稠密的:向量元素不再是稀疏的、大部分为零的计数或计数函数,而是可以为负的实数值。 事实证明,在每一项自然语言处理任务中,稠密向量的表现都优于稀疏向量。 虽然我们尚未完全理解所有原因,但有一些合理的解释。 将词表示为300维的稠密向量,比起表示为50,000维的向量,能让分类器学习的权重少得多,更小的参数空间可能有助于提升泛化能力并避免过拟合。 稠密向量也可能更有效地捕捉同义关系。 例如,在稀疏向量表示中,像 car 和 automobile 这样的同义词对应的维度是彼此独立且无关的;因此,稀疏向量可能无法捕捉到一个以 car 为邻近词的词与另一个以 automobile 为邻近词的词之间的相似性。 本节中介绍一种计算嵌入的方法:负采样跳字模型(skip-gram with negative sampling),有时简称为 SGNS。 跳字算法是名为 word2vec 的软件包中的两种算法之一,因此该算法有时被笼统地称为 word2vec(Mikolov 等,2013a;Mikolov 等,2013b)。 word2vec 方法速度快、训练高效,且代码和预训练嵌入模型在线上易于获取。 Word2vec 嵌入是静态的嵌入,意味着该方法为词汇表中的每个词学习一个固定的嵌入表示。 在第11章中,我们将介绍学习动态上下文嵌入的方法,如流行的 BERT 表示系列,其中每个词的向量会因其所处的不同上下文而变化。 word2vec 的核心理念是:不再统计每个词 $w$ 在某个词(比如 apricot)附近出现的频率,而是训练一个分类器来执行一个二元预测任务:“词 $w$ 是否可能出现在 apricot 附近?” 我们实际上并不关心这个预测任务本身;而是将分类器学习到的权重作为词的嵌入表示。 这里的革命性思想在于,我们可以直接使用连续文本作为此类分类器的隐式监督训练数据:一个在目标词 apricot 附近出现的词 $c$,就充当了“词 $c$ 是否可能出现在 apricot 附近?”这一问题的黄金标准“正确答案”。 这种方法通常被称为自监督,它避免了任何人工标注监督信号的需求。 这一思想最初在神经语言建模任务中被提出,Bengio 等人(2003)和 Collobert 等人(2011)表明,一个神经语言模型(一种学习根据前文预测下一个词的神经网络)可以直接使用连续文本中的下一个词作为其监督信号,并可在执行此预测任务的同时学习每个词的嵌入表示。 我们将在下一章介绍神经网络的实现方法,但 word2vec 是一个比神经网络语言模型简单得多的模型,主要体现在两方面。 首先,word2vec 简化了任务(将其变为二元分类而非词预测)。 其次,word2vec 简化了架构(训练一个逻辑回归分类器,而不是一个多层、包含隐藏层且需要更复杂训练算法的神经网络)。 跳字模型的设计原理如下: ...
总之,到目前为止我们所描述的向量语义模型将目标词表示为一个向量,其维度对应于一个大型文集中的文档(词-文档矩阵)或某个邻近窗口中词语的计数(词-词矩阵)。每个维度的值是经过加权的计数,词-文档矩阵使用 tf-idf 加权,词-词矩阵使用 PPMI 加权,且这些向量是稀疏的(因为大多数值为零)。 该模型通过计算两个词 $x$ 和 $y$ 的 tf-idf 或 PPMI 向量的余弦值来衡量它们之间的相似性;余弦值越高,相似度越高。整个模型有时根据其加权函数被称为 tf-idf 模型或 PPMI 模型。 基于 tf-idf 的意义模型常用于文档相关任务,例如判断两篇文档是否相似。取文档中所有词的向量,并计算这些向量的质心(centroid)来表示一篇文档。质心是均值在多维空间中的推广;一组向量的质心是一个单一向量,它到该组中每个向量的平方距离之和最小。给定 $k$ 个词向量 $w_1, w_2, ..., w_k$,其质心文档向量 $d$ 定义为: $$ d = \frac{w_1 + w_2 + ... + w_k}{k} \tag{6.23} $$给定两篇文档后,我们可以计算它们的文档向量 $d_1$ 和 $d_2$,并通过 $cos(d_1, d_2)$ 来估计两篇文档的相似度。文档相似度在各种应用中都非常有用,例如信息检索、抄袭检测、新闻推荐系统,甚至可用于数字人文领域的任务,如比较文本的不同版本以判断哪些版本彼此相似。 PPMI 模型和 tf-idf 模型都可用于计算词语相似度,适用于诸如寻找词语同义词、追踪词语意义变化,或自动发现不同语料库中词语含义等任务。例如,可以通过计算目标词 $w$ 与其余 $V-1$ 个词之间的余弦相似度,对结果进行排序,然后查看前 10 个结果,从而找到与 $w$ 最相似的 10 个词。 6.6 点互信息(PMI) 目录 6.8 Word2vec
为了度量两个目标词 $v$ 和 $w$ 之间的相似性,我们需要一种度量方法,它能接受两个向量(维度相同,要么都以词语为维度,因此长度为 $|V|$,要么都以文档为维度,长度为 $|D|$),给出它们相似程度的度量值。 迄今为止最常用的相似性度量是向量之间夹角的余弦(cosine)。 余弦——像NLP中使用的大多数向量相似性度量一样——基于线性代数中的点积(dot product)运算符,也称为内积(inner product): $$ \begin{align*} \text{点积}(\mathbf{v},\mathbf{w}) &= \mathbf{v} \cdot \mathbf{w} \\ &= \sum_{i=1}^N v_i w_i \\ &= v_1w_1 + v_2w_2 + ... + v_N w_N \tag{5.7} \end{align*} $$点积可以作为一种相似性度量,因为当两个向量在相同维度上具有较大的值时,点积的值往往会很高。 相反,如果两个向量在不同维度上为零(即正交向量),它们的点积为 0,这表示它们的差异性很强。 然而,这种原始的点积作为相似性度量存在一个问题:它偏向于长度更长的向量。 向量的长度定义为: $$ |\mathbf{v}| = \sqrt{\sum_{i=1}^N v_i^2} \tag{5.8} $$如果一个向量更长,每个维度的值更高,其点积也会更高。 更频繁出现的词具有更长的向量,因为它们倾向于与更多的词共现,并且与每个共现词的共现值也更高。 因此,原始点积对高频词的值会更高。 但这是一个问题;我们希望相似性度量能告诉我们两个词有多相似,而不受它们频率的影响。 我们通过将点积除以两个向量的长度来对点积进行归一化,从而修正这一问题。 这种归一化的点积实际上等于两个向量之间夹角的余弦,这源于两个向量 $\mathbf{a}$ 和 $\mathbf{b}$ 之间点积的定义: $$ \begin{align*} \mathbf{a} \cdot \mathbf{b} &= |\mathbf{a}||\mathbf{b}| \cos\theta \\ \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}||\mathbf{b}|} &= \cos\theta \tag{5.9} \end{align*} $$因此,两个向量 $\mathbf{v}$ 和 $\mathbf{w}$ 之间的余弦相似性度量可计算为: ...
本章介绍了逻辑回归模型在分类中的应用。 逻辑回归是一种监督式机器学习分类器,它从输入中提取实值特征,每个特征乘以一个权重后求和,并将结果通过sigmoid函数传递以生成概率。使用一个阈值来做出决策。 逻辑回归可以用于两类(例如,正面和负面情感)或多类(多项逻辑回归,例如用于n元文本分类、词性标注等)的情况。 多项逻辑回归使用softmax函数来计算概率。 权重(向量 $\mathbf{w}$ 和偏置 $b$)通过损失函数(如交叉熵损失)从标记的训练集中学习,该损失函数需要被最小化。 最小化这个损失函数是一个凸优化问题,迭代算法如梯度下降被用来找到最优权重。 正则化被用来避免过拟合。 由于其能够透明地研究单个特征的重要性,逻辑回归也是最有用的分析工具之一。 文献与历史注记 逻辑回归是在统计学领域发展起来的,在20世纪60年代已被用于二进制数据的分析,尤其在医学中广泛应用(Cox, 1969)。从20世纪70年代末开始,它成为语言学中研究语言变异的形式基础之一(Sankoff and Labov, 1979)。 然而,直到20世纪90年代,逻辑回归才在自然语言处理中变得普遍,当时它似乎同时从两个方向出现。第一个来源是信息检索和语音处理这两个相邻领域,它们都曾使用回归方法,并且都为NLP贡献了许多其他统计技术。实际上,早期将逻辑回归用于文档路由的例子之一是最早使用(LSI)嵌入作为词表示的NLP应用之一(Schütze et al., 1995)。 与此同时,在20世纪90年代初,IBM Research在名为最大熵建模或maxent(Berger et al., 1996)的名称下开发并应用于NLP,这似乎是独立于统计文献的发展。在这个名称下,它被应用于语言模型(Rosenfeld, 1996)、词性标注(Ratnaparkhi, 1996)、解析(Ratnaparkhi, 1997)、共指消解(Kehler, 1997b)和文本分类(Nigam et al., 1999)。 关于分类的更多信息可以在机器学习教材中找到(Hastie et al., 2001; Witten and Frank, 2005; Bishop, 2006; Murphy, 2012)。 5.10 进阶:梯度公式的推导 目录 第6章 向量语义与词嵌入
在本节中,我们将推导逻辑回归的交叉熵损失函数 $L_{CE}$ 的梯度。首先,回顾一些基本的微积分知识。 第一,$\ln(x)$ 的导数: $$ \frac{d}{dx} \ln(x) = \frac{1}{x} \tag{5.49} $$第二,sigmoid 函数(非常优美的)导数: $$ \frac{d\sigma(z)}{dz} = \sigma(z)(1 - \sigma(z)) \tag{5.50} $$第三,导数的链式法则(chain rule)。假设要计算复合函数 $f(x) = u(v(x))$ 的导数。$f(x)$ 的导数等于 $u(x)$ 对 $v(x)$ 的导数乘以 $v(x)$ 对 $x$ 的导数: $$ \frac{df}{dx} = \frac{du}{dv} \cdot \frac{dv}{dx} \tag{5.51} $$首先,求损失函数对单个权重 $w_j$ 的偏导数(需要对每个权重以及偏置 $b$ 都进行计算): $$ \begin{aligned} \frac{\partial L_{CE}}{\partial w_j} &= \frac{\partial}{\partial w_j} \left( -[y \log \sigma(\mathbf{w} \cdot \mathbf{x} + b) + (1 - y)\log(1 - \sigma(\mathbf{w} \cdot \mathbf{x} + b))] \right) \\ &= -\left[ \frac{\partial}{\partial w_j} y \log \sigma(\mathbf{w} \cdot \mathbf{x} + b) + \frac{\partial}{\partial w_j} (1 - y)\log(1 - \sigma(\mathbf{w} \cdot \mathbf{x} + b)) \right] \end{aligned} \tag{5.52} $$接下来,使用链式法则,并利用对数函数的导数: ...
在本节中,我们将推导逻辑回归的交叉熵损失函数 $L_{CE}$ 的梯度。 首先,回顾一些基本的微积分知识。 第一点是$\ln(x)$ 的导数: $$ \frac{d}{dx} \ln(x) = \frac{1}{x} \tag{4.56} $$第二点sigmoid 函数(非常优美的)导数: $$ \frac{d\sigma(z)}{dz} = \sigma(z)(1 - \sigma(z)) \tag{4.57} $$最后是导数的链式法则(chain rule)。 假设要计算复合函数 $f(x) = u(v(x))$ 的导数。 $f(x)$ 的导数等于 $u(x)$ 对 $v(x)$ 的导数乘以 $v(x)$ 对 $x$ 的导数: $$ \frac{df}{dx} = \frac{du}{dv} \cdot \frac{dv}{dx} \tag{4.58} $$首先,求损失函数对单个权重 $w_j$ 的偏导数(需要对每个权重以及偏置 $b$ 都进行计算): $$ \begin{align*} \frac{\partial L_{CE}}{\partial w_j} &= \frac{\partial}{\partial w_j} \left( -[y \log \sigma(\mathbf{w} \cdot \mathbf{x} + b) + (1 - y)\log(1 - \sigma(\mathbf{w} \cdot \mathbf{x} + b))] \right) \\ &= -\left[ \frac{\partial}{\partial w_j} y \log \sigma(\mathbf{w} \cdot \mathbf{x} + b) + \frac{\partial}{\partial w_j} (1 - y)\log(1 - \sigma(\mathbf{w} \cdot \mathbf{x} + b)) \right] \tag{4.59} \end{align*} $$接下来,使用链式法则,并利用对数函数的导数: ...
我们常常希望了解的不仅仅是对某个观测样本的正确分类结果。 还想知道分类器为何做出这样的决策。 也就是说,我们希望决策是可解释的(interpretable)。 可解释性很难严格定义,但其核心思想是:作为人类,我该能够理解算法为何得出某个结论。 由于逻辑回归所使用的特征通常是人为设计的,因此理解分类器决策的一种方式就是弄清楚每个特征在决策中所起的作用。 逻辑回归可以结合统计检验方法(如似然比检验或沃尔德检验)使用;通过这些检验来判断某个特定特征是否显著,或者检查其权重大小(该特征对应的权重 $w$ 有多大?),都有助于解释分类器做出某一决策的原因。 这对于构建透明的模型至关重要。 此外,除了作为分类器使用之外,逻辑回归在自然语言处理(NLP)以及许多其他领域还被广泛用作分析工具,用于检验关于各种解释性变量(即特征)影响的假设。 在文本分类中,我们可能想知道逻辑上的否定词(如 no、not、never)是否更可能与负面情感相关联,或者负面影评是否更倾向于讨论电影的摄影技术。 然而,在进行此类分析时,必须控制潜在的混杂因素(confounds):即其他可能影响情感的因素(如电影类型、上映年份,或影评的字数)。 或者,我们可能在研究由 NLP 提取的语言学特征与非语言学结果(如医院再入院率、政治结果或产品销量)之间的关系,但需要控制混杂因素(如患者年龄、投票所在县、产品品牌)。 在这种情况下,逻辑回归使我们能够检验某个特征是否在排除了其他特征影响的前提下,仍与某一结果存在关联。 4.12 分类中的危害防范 目录 4.14 进阶:正则化