2026年斯坦福-CS221-人工智能导论-2025-笔记-全-

斯坦福-CS221-人工智能导论-2025-笔记-全-在本节课中 我们将学习人工智能的基本定义 其核心组成部分 发展历史 并开始接触现代人工智能的基础工具 张量 人工智能 AI 代表 人工 和 智能 人工 部分指代在计算机或机器人上构建的系统 智能 部分则更为微妙 涉及一个智能体应具备的能力 一个智能体需要具备四种核心能力 感知世界 基于信息进行推理 在世界中行动以及从经验中学习 感知 处理来自世界的原始输入

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



在本节课中,我们将学习人工智能的基本定义、其核心组成部分、发展历史,并开始接触现代人工智能的基础工具——张量。

人工智能(AI)代表“人工”和“智能”。“人工”部分指代在计算机或机器人上构建的系统。“智能”部分则更为微妙,涉及一个智能体应具备的能力。

一个智能体需要具备四种核心能力:感知世界、基于信息进行推理、在世界中行动以及从经验中学习。

  • 感知:处理来自世界的原始输入,并将其转化为某种表示或理解。例如:计算机视觉理解图像和视频;语音识别理解声音;自然语言理解处理文本。
  • 推理:利用已有的知识和感知概念,对世界进行推断。本课程将涵盖多种技术,例如:在确定性世界中寻找最短路径的统一代价搜索;在不确定性世界中建模并做出最优决策的马尔可夫决策过程;在对抗性环境中(如国际象棋)进行最优博弈的极小化极大算法;以及使用贝叶斯网络进行概率推理。
  • 行动:输出实际影响世界的动作。例如:聊天机器人生成文本回复;生成图像或语音;控制机器人进行物理移动。
  • 学习:智能体在运行过程中从经验中学习,更新其信念或状态。例如:梯度下降Q学习期望最大化算法

所有这些能力都必须在资源约束下实现。资源约束主要包括两类:计算资源(如时间、内存)和信息(智能体总是拥有有限的信息和经验)。

上一节我们介绍了智能体的能力,本节中我们来看看智能体的目标。

我们需要从两个层面思考人工智能的目标。

首先,从开发者的角度,智能体(无论是显式还是隐式地)编码了某种价值观、目标或效用函数。开发者希望智能体实现特定目标,例如让聊天机器人提供信息、避免幻觉、拒绝有害查询等。确保智能体的价值观与开发者意图一致的过程被称为“对齐”。

其次,从更广泛的社会角度,我们需要考虑人工智能对社会的影响。这包括保护隐私、思考版权与知识产权、对就业和不平等的影响,乃至地缘政治考量。这些是社会技术层面的深刻问题,涉及不同价值观之间的权衡和潜在的意外后果。

本节课我们一起探讨了人工智能的定义,接下来我们简要了解本课程以及人工智能的发展历史。

本课程名为“人工智能原理与技术”,重点在于这些永恒的基础。课程哲学是“在实践中学习”,许多作业将涉及构建和编写代码。

今年课程的主要变化是采用“张量原生”方法,主要使用NumPy和PyTorch。我们削减了约束满足问题,并增加了对人工智能社会影响的深入探讨。

人工智能的历史可以从三条线索来理解:符号人工智能、神经人工智能和统计人工智能。

  • 符号人工智能:起源于20世纪50年代,试图用逻辑和规则系统来构建智能。经历了早期的乐观和随后的“AI寒冬”。其贡献包括Lisp编程语言等基础计算思想。
  • 神经人工智能:起源于20世纪40年代对人工神经网络的理论探索。经历了感知机的局限、反向传播的复兴,并在21世纪10年代随着深度学习在语音、视觉、语言等领域的突破而蓬勃发展。Transformer架构(2017年)为当前的大模型奠定了基础。
  • 统计人工智能:提供了严谨的数学工具和框架,如线性回归、随机梯度下降、支持向量机、贝叶斯网络等。这些思想源于更广泛的数学和工程领域,为人工智能提供了描述优化、泛化等的语言。

当前,我们处于基础模型大语言模型的时代,人工智能已经工业化,并对商业和政策产生巨大影响。然而,关于智能的许多开放研究问题仍然存在。本课程将融合这三种传统的元素。

上一节我们回顾了人工智能的思想史,本节中我们将卷起袖子,通过代码来学习现代人工智能的基础——张量。

张量是现代机器学习的基本单元,用于表示数据、模型参数、梯度以及深度神经网络的激活值等。本质上,我们将接触的所有内容都可以视为某种张量。

张量本质上是多维数组,是向量和矩阵的推广。

  • 标量是0阶张量:x = np.array(42)
  • 向量是1阶张量:v = np.array([1, 2, 3])
  • 矩阵是2阶张量:M = np.array([[1,2,3], [4,5,6]])
  • 张量可以是任意阶数。

可以使用np.zeros(shape), np.ones(shape), np.random.randn(shape)等函数创建张量。可以提取切片(如x[0, 1, 2])或进行转置等操作(注意这些操作通常创建视图而非副本)。

可以对张量进行逐元素运算(如x2, np.sqrt(x), x + y)。矩阵乘法是深度学习的核心运算。

为了提高效率,我们通常将多个数据点批量处理。例如,一个形状为(n, d_in)的矩阵乘以形状为(d_in, d_out)的权重矩阵,可以一次性完成所有n个数据点的变换。NumPy会自动将权重矩阵广播到批次的每个样本上。

使用张量操作(而非Python循环)通常更高效,因为底层库(如NumPy、PyTorch)针对性能进行了高度优化,并能利用GPU加速。

当张量运算变得复杂时(例如涉及多个维度的乘加),使用传统的-1, -2等索引会令人困惑。Einops库通过为张量维度命名,使运算意图更加清晰。

核心函数是einsum,它实现了广义的矩阵乘法并具有良好的簿记功能。

例如,矩阵乘法 C = A @ B(其中A形状为(a, b),B形状为(b, c))可以写为:
C = einsum(A, B, 'a b, b c -> a c')



对于更复杂的例子,比如对两个共享批次维度的张量进行特定乘法,使用einsum会清晰得多:
result = einsum(x, y, 'batch seq1 hidden, batch seq2 hidden -> batch seq1 seq2')



Einops还提供了reduce(用于降维,如求和、取最大)和rearrange(用于重组维度,例如将扁平化的维度拆分或合并)等实用函数,这在实现如Transformer等多头注意力机制时非常有用。

本节课中我们一起学习了人工智能的基本定义,将其分解为感知、推理、行动和学习四个核心组成部分,并认识到这些活动必须在计算和信息的资源约束下进行。我们探讨了开发者目标与社会影响之间的区别。随后,我们回顾了人工智能从符号主义、连接主义到统计学习的发展历史,看到它是一个融合了多种思想的领域。最后,我们开始学习现代人工智能的基石——张量,了解了如何创建、操作张量,以及如何利用Einops库写出更清晰、高效的张量运算代码,为后续更深入的学习打下基础。

在本节课中,我们将要学习反向传播和线性回归。我们将首先回顾张量和Einops库的基本概念,然后深入探讨计算图、梯度以及反向传播算法。最后,我们将把这些概念应用到线性回归这一具体的机器学习任务中,理解其假设空间、损失函数和优化过程。

上一节我们介绍了张量作为现代机器学习中的基本构建块。本节中,我们来看看如何通过Einops库更清晰地操作张量。

张量具有阶数,有时也称为秩。标量是0阶张量,向量是1阶张量,矩阵是2阶张量,但张量可以有任意阶数。张量的每个轴都可以被命名,命名应反映该轴所代表的意义,例如“样本”或“特征”。

Einops库中的einsum函数是一个核心操作,它可以看作是矩阵乘法的泛化,并能执行多种张量运算。其工作原理是:根据输入和输出轴的命名规则,对输入张量的所有可能索引组合进行乘法和求和,并将结果累加到输出张量的对应位置。

以下是使用einsum的一些基本示例:

  • 恒等运算einsum('i->i', x)。这表示对于输入向量x的每个索引i,输出y[i]等于x[i]
  • 向量求和einsum('i->', x)。输入轴i出现在左侧,但不出现在右侧输出中,这意味着对所有i索引的值进行求和,结果是一个标量。
  • 逐元素乘积einsum('i,i->i', x, x)。对于两个输入向量(此处为同一个),对应索引i的元素相乘,结果放入输出向量的相同索引位置。
  • 点积einsum('i,i->', x, x)。对应元素相乘后,对索引i进行求和,结果是一个标量。
  • 外积einsum('i,j->ij', x, x)。对于输入向量x的所有索引ij,计算x[i] * x[j],结果放入一个矩阵的(i, j)位置。
  • 矩阵转置einsum('ij->ji', M)。将输入矩阵M的行索引i和列索引j交换,得到转置矩阵。
  • 矩阵向量乘法einsum('ij,j->i', M, x)。对矩阵M的每一行i,与向量x按列索引j进行点积求和,结果是一个向量。
  • 矩阵乘法einsum('ik,kj->ij', A, B)。这是标准的矩阵乘法。注意索引k没有出现在输出中,这意味着对k进行了求和。

einsum的通用原则是:输入张量带有命名的轴,输出张量的命名轴是输入轴的一个子集。对于输入轴的所有可能赋值组合,将对应位置的输入张量元素相乘,然后累加到输出张量由剩余输出轴指定的位置。

上一节我们回顾了张量操作,本节中我们来看看如何计算复杂函数的梯度,这是优化模型参数的关键。

我们通常定义目标函数,它将张量(通常是参数)映射为一个标量(例如损失值)。为了改进模型,我们需要计算这个目标函数关于其输入的梯度,梯度指明了函数值下降最快的方向。

对于多元函数,梯度是一个由所有偏导数组成的张量,其形状与输入张量相同。每个偏导数衡量了当对应输入元素发生微小变化时,函数值的变化量。

手动计算复杂函数的梯度是繁琐且容易出错的。幸运的是,我们可以利用计算图和反向传播算法来自动化这个过程。

计算图将函数分解为一系列基本操作(节点)。每个节点要么是输入值(叶节点),要么是由其他节点通过基本运算(如加法、乘法)派生出的值。通过前向传播,我们可以计算图中所有节点的值。

反向传播算法则利用链式法则,高效地计算图中所有节点关于最终输出(根节点)的梯度。算法步骤如下:

  1. 前向传播:按拓扑顺序遍历节点,计算每个节点的值。
  2. 初始化梯度:将根节点的梯度设为1(因为改变根节点的值对其自身的影响是1:1),其他节点的梯度初始化为0。
  3. 反向传播:按拓扑逆序遍历节点。对于每个非叶节点,根据其对应的运算规则,利用其自身的梯度值,计算并累加到其依赖节点(输入)的梯度上。

例如,对于函数 y = (x1 + x2)^2,其计算图包含节点 x1, x2, sum (加法), y (平方)。反向传播时,首先 y.grad = 1y(平方操作)的backward方法计算 sum.grad += 2 * sum.value * y.grad。接着,sum(加法操作)的backward方法计算 x1.grad += sum.gradx2.grad += sum.grad。最终,我们得到了 x1x2 的梯度。

反向传播的核心数学原理是链式法则。现代深度学习框架(如PyTorch)的核心正是构建计算图并执行前向和反向传播。

前面我们介绍了计算梯度的通用工具,现在我们将聚焦于机器学习的具体任务:监督学习,并以线性回归为例。

监督学习的任务是学习一个预测函数(预测器),将输入映射到输出。例如,根据学习时间预测考试成绩。我们通过训练数据(输入-输出对示例)来学习这个预测器。

一个机器学习问题需要回答三个核心部分:

  1. 假设空间:我们考虑哪些可能的预测器?
  2. 损失函数:如何评价一个预测器的好坏?
  3. 优化算法:如何找到最好的预测器?

对于线性回归:

  • 假设空间:我们考虑所有线性函数 f(x) = w * x + b 构成的集合,其中 w(权重)和 b(偏置)是参数。不同的参数值对应不同的线性预测器。
  • 损失函数:我们使用平方损失。对于一个训练样本 (x, y),预测值为 f(x),残差为 f(x) - y,该样本的损失是残差的平方 (f(x) - y)^2。在所有训练样本上的训练损失是这些单个损失的平均值。损失越小,说明预测器对训练数据的拟合越好。
  • 优化算法:我们的目标是找到使训练损失最小的参数 (w, b)。我们使用梯度下降法。首先随机初始化参数,然后迭代地进行以下步骤:计算当前参数下的损失和梯度,然后沿梯度反方向更新参数(因为梯度方向是函数值上升最快的方向)。更新公式为:参数 = 参数 - 学习率 * 梯度。学习率控制着每次更新的步长。

通过多次迭代,梯度下降能够逐步降低损失,找到一组相对较好的参数。虽然对于像线性回归这样的凸问题,梯度下降可以收敛到全局最优解,但对于深度学习中的非凸问题,它通常能找到不错的局部最优解或鞍点。还存在随机梯度下降(SGD)、Adam等更高级的优化器。

本节课中我们一起学习了机器学习的核心基础。我们首先回顾了使用Einops进行张量操作,它提供了一种统一且清晰的方式来描述各种线性代数运算。接着,我们深入探讨了梯度的概念,并引入了计算图和反向传播算法,这是现代深度学习框架自动求导的基石。最后,我们将这些工具应用于监督学习的一个经典示例——线性回归,明确了构建机器学习解决方案的三个关键组成部分:假设空间(线性模型)、损失函数(平方损失)和优化算法(梯度下降)。这个“假设-损失-优化”的框架是理解和构建更复杂机器学习模型的基础模板。

在本节课中,我们将继续机器学习之旅,重点学习线性分类。我们将从线性回归的回顾开始,探讨如何将预测任务从回归(预测实数)扩展到分类(预测离散标签)。我们将定义线性分类器的假设空间,讨论损失函数的选择,并学习如何通过优化算法找到**分类器。

上一节我们介绍了线性回归的基本框架,本节中我们来看看如何将其应用于分类问题。

分类任务的目标是接收一个输入,并输出一个离散的类别标签。例如:

  • 图像分类:输入一张图片,输出其内容类别(如“猫”)。
  • 情感分类:输入一段文本,输出其情感倾向(如“正面”或“负面”)。

输入通常被表示为向量或张量。对于图像,可以将其像素值转换为张量;对于文本,则需要通过后续介绍的方法将其转换为数值表示。

输出是K个离散选择中的一个。当K=2时,称为二分类,通常用 -1(负类)和 +1(正类)表示。当K>2时,称为多分类

一个预测器是一个函数 f(x),它将输入 x 映射到预测的标签 y。对于一个简单的二分类器,其决策过程可以表示为:

def predict(x, w, b): logit = dot_product(w, x) + b # 计算原始分数 if logit > 0: return +1 else: return -1 

其中 w 是权重向量,b 是偏置项。所有满足 dot_product(w, x) + b = 0 的点构成了决策边界,它将输入空间划分为正类和负类区域。

在机器学习中,我们不手动编写预测器,而是从数据中学习。训练数据是一组输入-输出对 (x, y),其中 y 是目标标签。学习算法的目标是利用训练数据,找到一个能很好拟合数据并能在新数据上做出准确预测的预测器。

这引出了三个核心问题:

  1. 假设空间:我们考虑哪些可能的预测器?
  2. 损失函数:如何衡量一个预测器的好坏?
  3. 优化算法:如何计算最优的预测器?

上一节我们定义了学习问题的框架,本节我们将深入探讨假设空间。

对于线性分类,我们考虑的预测器由权重向量 w 和偏置 b 参数化。其形式为:
公式f(x) = sign( w·x + b )
其中 sign(z) 是符号函数,当 z > 0 时输出 +1,否则输出 -1w·x + b 被称为逻辑值










假设空间是所有可能的 (w, b) 所对应的预测器的集合。在二维空间中,这对应于所有可能的直线决策边界。虽然线性分类器表达能力有限,但在高维空间中(例如特征数很多时),它们可以非常强大且不易过拟合。

定义了假设空间后,我们需要一个标准来评估其中的哪个预测器最好,这就是损失函数的作用。

损失函数 L(w, b) 衡量参数为 (w, b) 的预测器在训练数据上的表现。我们首先为单个数据点定义损失。

最直观的损失是0-1损失,它只关心预测是否正确:
公式L_{0-1}(x, y, w, b) = 1 if sign(w·x + b) != y else 0
训练损失是所有训练样本0-1损失的平均值,即错误率










为了便于分析,我们引入间隔的概念。间隔定义为逻辑值与目标标签的乘积:
公式margin = (w·x + b) * y
间隔的符号表示预测是否正确(正为正确,负为错误),其大小表示正确的“确信度”。0-1损失可以重写为:
公式L_{0-1} = 1 if margin <= 0 else 0

















然而,0-1损失有一个致命缺点:其梯度几乎处处为零。这意味着基于梯度的优化算法(如梯度下降)无法使用,因为微调参数不会引起损失的连续变化。

为了解决0-1损失不可优化的问题,我们转向概率视角。我们不直接输出标签,而是让分类器输出一个概率分布

对于二分类,我们使用逻辑函数将逻辑值 z 映射到 [0, 1] 区间,解释为正类的概率:
公式σ(z) = 1 / (1 + exp(-z))
逻辑函数是平滑、可微的。给定逻辑值 z,正类概率为 σ(z),负类概率为 1 - σ(z) = σ(-z)










根据最大似然原理,我们希望找到使训练数据出现概率最大的参数。对于单个样本 (x, y),其似然为 P(y | x, w, b)。我们通常最大化对数似然(或等价地最小化负对数似然),这就得到了逻辑损失
公式L_{logistic}(x, y, w, b) = -log( P(y | x, w, b) ) = -log( σ( margin ) )
其中 margin = (w·x + b) * y










逻辑损失是连续可微的,其梯度不为零,因此适合用梯度下降优化。训练逻辑损失是各样本逻辑损失的平均值。

我们解决了损失函数的选择问题,接下来看看如何优化这个损失函数。

对于逻辑损失,我们可以计算其关于参数 wb 的梯度。通过链式法则,单个样本的梯度为:
公式∇_w L = (σ(margin) - 1) * y * x (当 y=+1 时的一种简化形式,实际计算需考虑 y 的符号)
公式∇_b L = (σ(margin) - 1) * y
整个训练集的梯度是每个样本梯度的平均值。

















有了梯度,我们就可以运行梯度下降算法:

  1. 初始化参数 w, b(例如,全零)。
  2. 重复以下步骤直到收敛:
    • 计算当前参数下的训练损失和梯度。
    • 沿梯度反方向更新参数:w := w - η * ∇_w L, b := b - η * ∇_b L,其中 η 是学习率。

优化过程会找到一组参数,其决策边界不仅尽可能正确分类样本,还会倾向于让正确分类的样本具有更大的间隔(更高的分类置信度)。

掌握了二分类后,我们将其推广到更一般的多分类场景。

在多分类中,输出 y{0, 1, ..., K-1} 中的一个。我们需要为每个类别 j 配备一个权重向量 w_j 和偏置 b_j。对于输入 x,我们为每个类别计算一个逻辑值:
公式z_j = w_j·x + b_j, 对于 j = 0, ..., K-1



为了得到所有类别的概率分布,我们使用 Softmax函数
公式P(y = j | x) = exp(z_j) / (∑_{k=0}^{K-1} exp(z_k))
Softmax将逻辑值向量转换为一个概率分布,满足所有概率之和为1,且较大的逻辑值对应较高的概率。










损失函数采用交叉熵损失,它是负对数似然在多分类情况下的推广。当真实标签 y 是单个类别时,交叉熵损失简化为:
公式L_{cross-entropy}(x, y, W, b) = -log( P(y | x, W, b) )
其中 W 是所有 w_j 组成的矩阵,b 是所有 b_j 组成的向量。这个损失同样可以使用梯度下降进行优化。










最后,我们需要解决一个实际问题:如何将非数值输入(如文本)转换为模型可以处理的张量。

机器学习模型处理的是数值张量,因此需要将文本字符串转换为这种形式。这个过程通常分为两步:

  1. 分词:将字符串分割成更小的单元(如单词、子词)。为每个唯一的单元分配一个整数ID,从而将文本转换为整数序列。
  2. 向量化:将每个整数ID转换为一个向量。最简单的方法是独热编码,即创建一个长度等于词汇表大小的向量,仅在对应ID的位置为1,其余为0。这样,一个长度为 L 的文本就被表示为一个 L x V 的矩阵(V 是词汇表大小)。

在实践中,我们通常直接使用整数ID索引一个可学习的嵌入矩阵来获取密集向量表示,这比独热编码更高效。

一种简单但常用的文本表示是词袋模型:将文本中所有词的向量表示(或独热向量)平均,得到一个固定长度的向量,作为整个文档的表示。它的优点是简单、长度固定,但缺点是完全忽略了词序信息。

本节课中我们一起学习了线性分类的核心内容。我们从分类任务的定义出发,探讨了线性分类器的假设空间。为了解决优化难题,我们从0-1损失转向了可微的逻辑损失(及其多分类推广——交叉熵损失),并介绍了如何使用梯度下降进行优化。最后,我们了解了如何将文本数据转换为张量表示,为实际应用扫清了障碍。线性分类是许多复杂模型的基础,理解其原理至关重要。

在本节课中,我们将学习深度学习。我们将从线性模型过渡到非线性模型,介绍多层神经网络的基本概念,并探讨训练深度网络时需要注意的各种技巧。

上一节我们介绍了线性分类和回归。本节中,我们将探讨如何实现更强大的非线性回归和分类方法。

我们将开始使用PyTorch。首先,回顾一下计算图的基本概念。在PyTorch中,张量(torch.Tensor)可以看作是计算图中的节点,它们存储值和梯度。

GPT plus 代充 只需 145import torch x = torch.tensor([1.], requires_grad=True) y = torch.tensor([2.], requires_grad=True) z = x * y z.backward() print(x.grad) # 输出:tensor([2.]) print(y.grad) # 输出:tensor([1.]) 

PyTorch的requires_grad标志指示需要计算梯度的节点。调用.backward()方法会反向传播梯度。

以下是使用PyTorch构建和训练一个简单线性分类器的步骤。

首先,定义模型、损失函数和优化器。

import torch.nn as nn import torch.optim as optim # 数据 x = torch.tensor([[1., 2., 3., 4.]]) y = torch.tensor([[0, 1, 0, 0]]) # 独热编码,标签为1 # 模型:线性层 model = nn.Linear(4, 3) # 输入维度4,输出维度3(3个类别) criterion = nn.CrossEntropyLoss() # 交叉熵损失 optimizer = optim.SGD(model.parameters(), lr=0.01) # 前向传播 logits = model(x) loss = criterion(logits, y) # 反向传播与优化 optimizer.zero_grad() # 清零梯度 loss.backward() # 计算梯度 optimizer.step() # 更新参数 

训练循环通常包含以下步骤:前向传播计算损失,反向传播计算梯度,优化器更新参数。

线性模型的决策边界是直线或超平面,但许多数据需要非线性边界。

一个技巧是使用特征映射。例如,一个在二维空间分类圆内外的“二次分类器”,可以通过一个非线性特征映射转换为高维空间中的线性分类问题。

然后,在高维特征空间φ(x)上应用一个线性分类器w·φ(x) + b,即可实现原始的非线性分类。

我们可以不手动设计特征映射,而是让模型自己学习。这就是神经网络的核心思想。

一个两层的神经网络(多层感知机,MLP)可以看作:第一层学习特征映射,第二层是线性分类器。

GPT plus 代充 只需 145class TwoLayerMLP(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super().__init__() self.layer1 = nn.Linear(input_dim, hidden_dim) self.layer2 = nn.Linear(hidden_dim, output_dim) def forward(self, x): h = self.layer1(x) # 注意:如果没有非线性激活函数,这仍然是线性的! # h = torch.relu(h) # 加上非线性激活函数 logits = self.layer2(h) return logits 

关键点:如果没有非线性激活函数,多层线性层的组合仍然等价于一个单层线性层。因为矩阵乘法是结合的:W2 * (W1 * x) = (W2 * W1) * x

为了使网络具有非线性表达能力,必须在层之间引入非线性激活函数。

常用的激活函数包括Sigmoid、Tanh、ReLU等。我们主要关注ReLU。

# ReLU 激活函数 def relu(x): return torch.maximum(x, torch.tensor(0.0)) 

它在x>0时梯度为1,在x<=0时梯度为0。梯度为零可能导致“神经元死亡”问题。Leaky ReLU、GELU、Swish等激活函数试图缓解这个问题。

在MLP中加入ReLU:

GPT plus 代充 只需 145class MLPWithReLU(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super().__init__() self.layer1 = nn.Linear(input_dim, hidden_dim) self.layer2 = nn.Linear(hidden_dim, output_dim) def forward(self, x): h = self.layer1(x) h = torch.relu(h) # 加入非线性激活函数 logits = self.layer2(h) return logits 

现在,这个模型是真正的非线性模型,表达能力更强。

我们可以堆叠更多的层来构建深度神经网络,每一层可能学习到更抽象的特征。

然而,训练深度网络面临梯度消失梯度爆炸的问题。在反向传播时,梯度需要跨越多层连续相乘。如果每层的缩放因子持续小于1,梯度会指数级衰减至接近零;如果持续大于1,梯度则会爆炸。

残差连接(或称跳跃连接)通过将层的输入直接加到其输出上来缓解梯度消失。

class ResidualBlock(nn.Module): def __init__(self, dim): super().__init__() self.linear = nn.Linear(dim, dim) def forward(self, x): # F(x) + x return self.linear(x) + x 

即使self.linear(x)的梯度很小,来自x的梯度也能直接回传。

层归一化(Layer Normalization)对单层内所有神经元的激活进行标准化,使其均值为0,方差为1,有助于稳定训练。

GPT plus 代充 只需 145# PyTorch 中的层归一化 layer_norm = nn.LayerNorm(feature_dim) normalized_output = layer_norm(activations) 

不恰当的初始化会导致激活值过大或过小。Xavier初始化(或Glorot初始化)根据输入和输出的维度来缩放初始权重。

# 手动实现 Xavier 初始化 def xavier_init(layer): if isinstance(layer, nn.Linear): nn.init.xavier_uniform_(layer.weight) layer.bias.data.fill_(0) 

在PyTorch中,许多层默认使用合理的初始化。

我们之前使用的是(批量)梯度下降。在实际中,更常用的是随机梯度下降或其变种。

  • 梯度下降:使用整个训练集计算梯度,更新一次。
  • 随机梯度下降:每次随机选取一个小批量数据计算梯度,更新一次。这更高效,且梯度的噪声有时有助于跳出局部最优。
GPT plus 代充 只需 145# 使用SGD优化器,它既可用于全批量梯度下降,也可用于小批量随机梯度下降 optimizer = optim.SGD(model.parameters(), lr=0.01) # 在训练循环中 for epoch in range(num_epochs): # 随机打乱数据并分成小批量 for batch_x, batch_y in data_loader: optimizer.zero_grad() loss = criterion(model(batch_x), batch_y) loss.backward() optimizer.step() # 用当前小批量的梯度更新 

更高级的优化器如Adam,通常能提供更快的收敛和更稳定的训练。

本节课我们一起学习了深度学习的基础。

  1. 我们使用PyTorch进行自动微分和模型构建。
  2. 我们理解了线性模型的局限性,并通过特征映射和非线性激活函数引入非线性表达能力。
  3. 我们构建了多层感知机,并认识到激活函数的关键作用。
  4. 我们探讨了训练深度神经网络的主要挑战:梯度消失/爆炸。
  5. 我们介绍了几种稳定深度网络训练的核心技巧:
    • 使用残差连接确保梯度流动。
    • 使用层归一化稳定激活分布。
    • 使用合理的参数初始化(如Xavier初始化)。
    • 使用小批量随机梯度下降及更高级的优化器。

深度学习需要理论理解与实践经验的结合。希望本教程为你提供了坚实的起点。

在本节课中,我们将学习搜索这一核心概念。搜索是解决确定性世界中规划、推理和问题求解问题的一种形式。我们将学习如何将现实问题形式化为搜索问题,并探索几种解决它们的算法,从精确方法到启发式方法。


上一节我们介绍了机器学习,它直接学习从感知到行动的映射。然而,许多现实问题(如解魔方或寻找最短路径)需要推理规划。本节中,我们来看看如何将这类问题形式化为搜索问题

搜索问题包含以下核心组件:

  • 起始状态:搜索开始时的状态。
  • 后继函数:给定一个状态,返回所有可能的行动、其成本以及执行该行动后到达的新状态
  • 终止判断函数:判断一个状态是否为最终目标状态。

假设一条街道有编号为1到n的街区。从街区i走到i+1耗时1分钟。此外,有一辆魔法电车可以从i直达2*i,耗时2分钟。问题:如何从1号街区到达n号街区,且总时间最短?

我们可以这样定义搜索问题:

  • 状态:当前所在的街区编号(整数)。
  • 起始状态1
  • 后继函数
    • 行动“走”:成本为1,新状态为state + 1(如果不超出n)。
    • 行动“乘车”:成本为2,新状态为2 * state(如果不超出n)。
  • 终止判断:当state == n时返回True

以下是该问题的Python代码描述:

def successors(state, n): steps = [] if state + 1 <= n: steps.append(('walk', 1, state + 1)) if 2 * state <= n: steps.append(('tram', 2, 2 * state)) return steps def is_end(state, n): return state == n 

状态需要包含评估未来行动、成本和后继状态所需的所有信息。例如,如果乘车需要车票且数量有限,状态就必须包含当前位置剩余车票数。如果规定不能连续两次乘车,状态可能还需要包含上一次的行动信息。

设计状态时,需要在信息完备性和状态空间大小之间取得平衡。状态空间过大会导致算法效率低下。


上一节我们学习了如何建模搜索问题。本节中,我们来看看如何精确地求解这些问题,即找到成本最小的解决方案。

最直接的方法是尝试所有可能的行动序列,并选择总成本最小的一个。这可以通过递归计算未来成本来实现。

未来成本 future_cost(s) 定义为从状态 s 出发到达任一终止状态的最小总成本。它满足以下贝尔曼最优方程:

GPT plus 代充 只需 145future_cost(s) = 0, 如果 is_end(s) 为真 future_cost(s) = min_{ (a, cost, s') in successors(s) } [ cost + future_cost(s') ], 否则 

以下是穷举搜索的递归实现框架:

def exhaustive_search(problem, state): if problem.is_end(state): return Solution(cost=0, steps=[]) best_solution = None for action, immediate_cost, next_state in problem.successors(state): future_solution = exhaustive_search(problem, next_state) total_cost = immediate_cost + future_solution.cost candidate_solution = Solution(cost=total_cost, steps=[action] + future_solution.steps) if best_solution is None or total_cost < best_solution.cost: best_solution = candidate_solution return best_solution 

缺点:时间复杂性在最坏情况下是指数级的,因为它可能多次探索同一个状态。对于有环(循环)的状态空间,简单的递归实现可能无法终止。可以通过在状态中加入步数计数来打破循环。

穷举搜索的低效之处在于它会重复计算同一状态的未来成本。动态规划通过缓存(记忆化)已计算的结果来避免重复工作。

动态规划的核心思想是:一旦计算了 future_cost(s),就将其存储起来。下次再需要 future_cost(s) 时,直接返回缓存的结果。

以下是动态规划与穷举搜索的主要区别(新增代码已标出):

GPT plus 代充 只需 145cache = {} # 新增:缓存字典 def dp_search(problem, state): if state in cache: # 新增:检查缓存 return cache[state] if problem.is_end(state): solution = Solution(cost=0, steps=[]) else: best_solution = None for action, immediate_cost, next_state in problem.successors(state): future_solution = dp_search(problem, next_state) total_cost = immediate_cost + future_solution.cost candidate_solution = Solution(cost=total_cost, steps=[action] + future_solution.steps) if best_solution is None or total_cost < best_solution.cost: best_solution = candidate_solution solution = best_solution cache[state] = solution # 新增:存入缓存 return solution 

优点:时间复杂性降至与状态数量成正比(每个状态只计算一次)。
适用条件



  1. 状态空间必须能放入内存。
  2. 当存在多条路径到达同一状态时(即状态图有汇合),动态规划优势最大。

上一节我们介绍了两种精确搜索算法。然而,当状态空间非常庞大(例如包含所有可能单词序列)时,精确搜索将变得不可行。本节中,我们转向启发式搜索算法,它们通过探索解空间的一个子集来高效地寻找近似最优解,但可能错过真正的最优解。

**N采样 是最简单的启发式方法之一。

  1. 定义一个策略:一个从状态映射到行动的函数(可以是随机策略)。
  2. 从起始状态开始,使用该策略重复进行模拟,直到到达终止状态。每次模拟产生一个候选解。
  3. 进行 N 次独立的模拟。
  4. 从这 N 个候选解中选出成本最低的一个作为最终解。

以下是其工作原理:

def best_of_n(problem, policy, n): best_solution = None for _ in range(n): # 一次模拟 solution = rollout(problem, policy) if best_solution is None or solution.cost < best_solution.cost: best_solution = solution return best_solution def rollout(problem, policy): state = problem.start_state steps = [] total_cost = 0 while not problem.is_end(state): action, cost, next_state = policy(state) # 根据策略选择行动 steps.append(action) total_cost += cost state = next_state return Solution(cost=total_cost, steps=steps) 

特点

  • 简单且高度可并行:所有 N 次模拟可以独立进行。
  • 渐进保证:如果策略对所有行动赋予非零概率,且 N 趋近于无穷大,则算法能以概率1找到最优解(尽管可能需要指数时间)。
  • 策略的质量至关重要。一个聪明的策略(如训练好的神经网络)可以极大地提高找到好解的效率。

束搜索 在搜索过程中维护一个固定大小的候选解集合(称为“束宽” k)。

  1. 初始化:束中仅包含从起始状态出发的部分解(空解)。
  2. 扩展:对于当前束中的每个部分解,考虑从其最后状态出发的所有可能行动,生成新的部分解。
  3. 选择:将所有新生成的部分解合并,根据其当前总成本排序,仅保留成本最低的 k 个。
  4. 重复步骤2和3,直到束中的所有部分解都到达终止状态,或达到最大步数。
  5. 从最终的束中选择成本最低的完整解。

特点

  • 确定性:给定相同输入,总是产生相同输出。
  • 束宽的影响
    • k=1 时,退化为贪心搜索(每步只选当前最优)。
    • k→∞ 时,退化为穷举搜索(不切实际)。
  • 除了**解,还能提供排名前 k 的近似解。
  • 与**N采样相比,束搜索在每一步进行全局比较,但并行化不如前者直接。

前面介绍的搜索框架非常通用。本节中,我们来看一个现代人工智能中的关键应用:增强语言模型的推理能力

一个常见的场景是:给定一个提示(如数学问题),我们不仅希望语言模型生成一个答案,更希望它生成一个正确概率高的答案。我们可以利用搜索,在生成时投入更多计算资源(测试时计算)来寻找更好的响应。

我们可以将语言模型生成过程定义为一个搜索问题:

  • 状态:提示字符串 + 已生成的部分响应字符串。
  • 行动:预测下一个词元(token)。
  • 成本-log P(token | state),即负对数概率。最小化成本等价于最大化序列概率
  • 额外奖励:如果生成的完整响应通过验证器(如数学答案正确),可以给予一个大的负成本(即奖励)。

然后,我们可以应用**N采样

  • 策略:语言模型本身。在给定状态下,模型输出下一个词元的概率分布,我们可以依此概率进行采样。
  • 进行多次独立生成(模拟),然后选择其中成本最低(即概率最高且可能正确)的序列。

这种方法被称为自洽性采样**N采样,研究表明,即使使用较小的模型,通过大量采样也能获得与更大模型相媲美的性能。


本节课中,我们一起学习了搜索这一核心人工智能范式。

  1. 搜索问题建模:我们将需要规划的问题形式化为包含状态行动成本终止条件的搜索问题。设计一个信息充足且紧凑的状态表示是关键。
  2. 精确搜索算法
    • 穷举搜索:递归尝试所有路径,简单但可能是指数级时间复杂度。
    • 动态规划:通过缓存子问题结果(记忆化)避免重复计算,将时间复杂性降至与状态数成正比,但要求状态空间可放入内存。
  3. 启发式搜索算法:当状态空间过大时使用,寻找近似解。
    • **N采样:使用一个策略进行多次独立随机模拟,取最优。简单、可并行,其效果依赖于策略质量。
    • 束搜索:在搜索过程中始终维护一个固定大小的**候选解集合,进行确定性的启发式搜索。
  4. 搜索与学习的协同:现代人工智能系统常将两者结合。学习(如训练语言模型)用于预测成本或提供智能策略;搜索则利用这些学到的信息来寻找最优或近似最优的解决方案。这种结合是解决复杂推理问题的强大范式。

搜索是解决确定性规划问题的基石。下次课,我们将探讨如何处理带有循环的状态空间,并介绍一致代价搜索算法。

在本节课中,我们将继续学习精确搜索算法,重点探讨如何处理包含循环的搜索问题。我们将介绍两种算法:统一代价搜索A*搜索。我们会看到,A*算法实际上是统一代价搜索的一种巧妙变体。


上一讲我们介绍了搜索。我们之所以需要搜索,而不仅仅是学习,是因为我们希望解决那些需要思考和推理的复杂问题。

我们定义了什么是搜索问题。以一个简单的电车问题为例:有六个地点,你需要通过步行或乘坐电车从地点1到达地点6。

我们可以形式化地定义一个搜索问题:

  • 起始状态start
  • 后继函数successors(state) -> [(action, cost, next_state), ...]
  • 目标测试isEnd(state) -> True/False

搜索问题的目标是找到一个总成本最小的解决方案,即所有行动成本之和最小。

上次我们学习了四种算法:

  1. 穷举搜索:尝试所有可能的路径。
  2. 动态规划:本质上是带有缓存的穷举搜索,通过计算未来成本(从每个状态到目标状态的最小成本)来解决问题。
  3. N次最优采样:根据某个策略独立采样多个解决方案,并选择其中最好的一个。
  4. 束搜索:在每一步保留一个“束”的**候选解,并进行剪枝。

上一节我们回顾了搜索的基础概念和算法。本节中,我们将继续探讨精确算法,但会聚焦于如何处理包含循环的搜索问题。


为了引入统一代价搜索,我们先回顾搜索中的两个理想化数学概念:

  • 未来成本:从给定状态到达目标状态的**成本。
  • 过去成本:从起始状态到达给定状态的**成本。

在动态规划中,我们通过递归关系计算每个状态的未来成本。但这种方法要求先计算所有后继状态的未来成本,然后才能计算当前状态的未来成本。这类似于反向传播算法,从目标开始反向计算。

然而,动态规划无法处理循环。如果搜索图中存在循环,未来成本的递归定义将变得不明确,代码也会陷入无限循环。

那么,当搜索问题存在循环时,我们该怎么办?答案是统一代价搜索,它也被称为迪杰斯特拉算法

UCS与动态规划有两个主要区别:

  1. UCS计算的是过去成本,而非未来成本。
  2. UCS按照过去成本递增的顺序处理状态,而不是依赖图的结构顺序。

UCS的高层策略是将所有状态划分为三个集合:

  • 已探索:我们已经找到了到达这些状态的最小成本路径。
  • 边界:我们已经发现了这些状态,但仍在寻找到达它们的**路径。
  • 未探索:尚未发现的状态。

算法从起始状态开始,逐步扩展边界。一旦探索到目标状态,算法就结束了。

考虑一个简单的图搜索问题,状态为A、B、C、D,边及其成本如下:

  • A -> B (成本 1)
  • A -> C (成本 100)
  • B -> C (成本 1)
  • B -> D (成本 100)
  • C -> D (成本 1)

以下是UCS的运行步骤:

  1. 初始化:边界 = [(A, 成本 0)], 已探索 = {}
  2. 从边界取出成本最低的状态A(成本0)。将其移入已探索集。检查其后继:
    • 到达B:新成本 = 0 + 1 = 1。将(B, 成本 1)加入边界。
    • 到达C:新成本 = 0 + 100 = 100。将(C, 成本 100)加入边界。
  3. 从边界取出成本最低的状态B(成本1)。将其移入已探索集。检查其后继:
    • 到达A:A已在已探索集,忽略。
    • 到达C:新成本 = 1 + 1 = 2。这比边界中C的当前成本(100)更优。更新边界中C的成本为2,并记录回溯指针(来自B)。
    • 到达D:新成本 = 1 + 100 = 101。将(D, 成本 101)加入边界。
  4. 从边界取出成本最低的状态C(成本2)。将其移入已探索集。检查其后继:
    • 到达A和B:它们已在已探索集,忽略。
    • 到达D:新成本 = 2 + 1 = 3。这比边界中D的当前成本(101)更优。更新边界中D的成本为3,并记录回溯指针(来自C)。
  5. 从边界取出成本最低的状态D(成本3)。D是目标状态。算法结束。

通过回溯指针,我们可以重建最优路径:A -> B -> C -> D,总成本为3。

UCS算法能保证找到最小成本路径,前提是所有边的成本都是非负的。其核心定理是:当UCS将一个状态S从边界移入已探索集时,S在边界中的优先级(计算出的成本)就等于其真正的过去成本(最小成本)

证明思路(归纳法):

  • 基础情况:起始状态的优先级和过去成本都是0,成立。
  • 归纳假设:假设对于所有已探索的状态,该性质成立。
  • 归纳步骤:考虑从边界移出的状态S。存在一条从起点到S的路径(蓝色路径),其成本等于S的优先级。我们需要证明任何其他到达S的路径(红色路径)的成本都不会更低。通过一系列不等式推导(利用非负成本、归纳假设以及UCS总是选择边界中优先级最低的状态这一事实),可以证明红色路径的成本至少等于蓝色路径的成本。因此,S的优先级就是其过去成本。

UCS虽然能保证找到最优解,但其探索是“均匀”的,即从起点开始向所有方向等速扩展,而不考虑目标的位置。这意味着它可能会探索许多明显偏离目标方向的状态,效率上存在优化空间。


为了克服UCS的局限性,我们引入A*搜索。A*的核心思想是:在决定探索哪个状态时,不仅考虑从起点到达该状态的过去成本,还估计从该状态到达目标的未来成本。

理想情况下,如果我们能知道每个状态的精确未来成本,那么按照 过去成本 + 未来成本 的顺序探索状态将是最优的,因为它总是优先探索位于某条最优路径上的状态。但精确未来成本通常难以计算。

A*的做法是使用一个启发式函数 h(s)近似未来成本。然后,A*算法按照 过去成本 + h(s) 的顺序探索状态。

具体实现上,A*可以看作是在修改后的搜索问题上运行UCS。我们定义一个新的成本函数:
modified_cost(s, a, s') = original_cost(s, a, s') + h(s') - h(s)



然后,在这个修改后的问题上运行标准的UCS算法。最后,再将找到的路径成本转换回原始问题的成本。

并非任何启发式函数都能保证A*找到最优解。为了保证正确性,启发式函数需要满足一致性条件:

  1. 对于所有状态s,h(s) >= 0
  2. 对于所有状态s和行动a,到达后继状态s‘,修改后的成本必须非负:original_cost(s, a, s') + h(s') - h(s) >= 0
  3. 对于所有目标状态s,h(s) = 0

一致性条件的一个直观理解是:启发式函数h(s)对到达目标成本的估计是“协调的”,不会出现因为绕远路而使得估计值反而降低的矛盾情况。

如果启发式函数是一致的,那么A*算法就能保证找到最小成本路径。其证明思路是:在修改后的问题上,任何从起点到目标的路径总成本,等于原始路径总成本减去一个常数h(start)。因此,在修改后问题上最小化成本,等价于在原始问题上最小化成本。

设计一个既有效(能加速搜索)又一致(保证正确性)的启发式函数是关键。一个强大而系统的方法是松弛法

核心思想:将原始搜索问题放松,移除一些约束,使其更容易求解。然后,将这个更简单问题的精确未来成本作为原始问题的启发式函数。

因为松弛后的问题未来成本是精确计算的,所以它自动满足一致性条件(根据三角不等式)。

以下是几种常见的松弛策略示例:

  1. 移除障碍(获得闭式解)
    • 原始问题:网格世界,有墙壁阻挡。
    • 松弛问题:忽略所有墙壁。
    • 启发式h(s) = 曼哈顿距离(s, goal)。这是一个闭式解,计算极快。
  2. 减少状态维度(降低搜索复杂度)
    • 原始问题:有限次电车问题,状态包含(位置, 剩余车票数)
    • 松弛问题:电车可以无限次免费乘坐。状态仅包含位置
    • 启发式h(s) = 在松弛问题上,从s的位置到目标的最小成本。这可以通过在状态数更少的松弛问题上运行DP或UCS来预计算。
  3. 分解为独立子问题
    • 原始问题:八数码拼图,瓷砖移动会相互影响。
    • 松弛问题:允许瓷砖重叠移动(即每个瓷砖可以独立移动到目标位置,无视其他瓷砖)。
    • 启发式h(s) = 所有瓷砖的曼哈顿距离之和。每个子问题(单个瓷砖的移动)都有闭式解。

统一原则:松弛在数学上可以看作是降低行动的成本(例如,将不可通行墙壁的成本从无穷大降低到有限值,或将有限成本降低到更小的值)。

如果你有多个启发式函数h1(s)h2(s),并且它们都是一致的,那么你可以通过取最大值来组合它们:h(s) = max(h1(s), h2(s))。这个新的启发式函数仍然是一致的,并且通常比任何一个单独的启发式函数效果更好(因为它提供了更紧的、即更大的未来成本估计)。


本节课我们一起学习了两种能够处理循环的精确搜索算法:

  • 统一代价搜索:按照过去成本递增的顺序探索状态,使用优先队列高效实现。它能保证在边权非负的图中找到最优解,但探索方式较为盲目。
  • A*搜索:UCS的改进版本,通过引入启发式函数h(s)来估计未来成本,从而引导搜索朝向目标方向。只要启发式函数满足一致性条件,A*就能在保证找到最优解的同时,大幅提升搜索效率。
    • 设计启发式函数的关键方法是松弛法:通过放松原始问题的约束,构造一个更容易求解的松弛问题,并将其精确解作为启发值。

通过结合领域知识(体现在启发式设计中),A*算法让我们能在复杂问题中更智能、更高效地进行搜索。下一讲,我们将探讨当行动结果具有不确定性(例如掷骰子)时,如何制定最优策略,这将引入马尔可夫决策过程的概念。

在本节课中,我们将学习马尔可夫决策过程。这是一种比上周学习的搜索问题更强大的框架,因为它能处理现实世界中的不确定性。我们将了解MDP的基本组成部分、如何评估一个策略,以及如何找到最优策略。

搜索问题假设动作是确定性的,即从一个状态执行一个动作,必然会到达一个特定的下一个状态。然而,现实世界充满了不确定性。马尔可夫决策过程通过允许一个动作导致多个可能的下一个状态(每个状态都有一定的发生概率)来对此进行建模。本节课我们将定义MDP,学习如何评估一个给定的策略,并最终学习如何计算最优策略。

上一节我们介绍了确定性搜索问题。本节中我们来看看如何将其扩展以处理不确定性。

马尔可夫决策过程是一个用于在不确定环境中进行顺序决策的框架。它包含以下组成部分:

  • 状态:表示系统在特定时刻的完整描述。
  • 动作:代理在给定状态下可以执行的操作。
  • 转移函数:定义了在状态 s 执行动作 a 后,转移到状态 s' 的概率,记为 T(s, a, s')
  • 奖励函数:定义了在状态 s 执行动作 a 并转移到状态 s' 后获得的即时奖励,记为 R(s, a, s')。奖励的负值可以理解为成本。
  • 折扣因子:一个介于0和1之间的数 γ,用于衡量未来奖励相对于即时奖励的重要性。γ=1 表示同等重要,γ=0 表示只关心即时奖励。
  • 起始状态终止状态

MDP的关键特性是马尔可夫性:未来的状态只依赖于当前状态和采取的动作,而与过去的历史无关。

我们用一个例子来具体说明。考虑一个从位置1到位置10的旅行问题。

  • 行走:从位置 i 走到 i+1,花费1分钟(奖励为-1),且是确定性的。
  • 乘坐电车:从位置 i 直接到位置 2i,通常花费2分钟(奖励为-2)。但电车有0.4的概率发生故障。如果故障,你将停留在原地 i,但仍需花费2分钟。

在状态 s,可用的动作是 walktram(如果 2*s <= 10)。转移函数和奖励函数定义如下:

  • 对于动作 walkT(s, walk, s+1) = 1.0R(s, walk, s+1) = -1
  • 对于动作 tramT(s, tram, 2*s) = 0.6R(s, tram, 2*s) = -2T(s, tram, s) = 0.4R(s, tram, s) = -2

我们的目标是找到一种行动方案,使得从状态1到状态10的期望总奖励最大(或期望总成本最小)。

在确定性搜索中,解决方案是一个动作序列。但在MDP中,由于存在不确定性,我们需要一个能应对任何可能情况的方案。

MDP的解决方案称为策略。策略 π 是一个函数,它为每个状态 s 指定一个要执行的动作 a = π(s)。无论随机性将我们带到哪个状态,策略都能告诉我们下一步该做什么。

给定一个MDP和一个策略,我们可以进行模拟来观察会发生什么。一次模拟称为一个 rollout。它从起始状态开始,反复使用策略选择动作,然后根据MDP的转移概率随机选择下一个状态,并收集奖励,直到到达终止状态。

一次rollout产生的效用是所获得奖励的折扣总和:
效用 = R_0 + γ * R_1 + γ^2 * R_2 + ...
其中 γ 是折扣因子,R_t 是第 t 步获得的奖励。










由于随机性,同一策略的不同rollout会产生不同的效用。为了评估策略的好坏,我们看它的,即所有可能rollout的期望效用,记为 V^π(s),表示从状态 s 开始并遵循策略 π 所能获得的期望总折扣奖励。

上一节我们了解了如何通过模拟来估计策略的值。本节中我们来看看如何更精确、更高效地计算它。

策略评估的目标是精确计算给定策略 π 的值函数 V^π。核心思想是利用动态规划和贝尔曼期望方程

我们首先定义一个辅助函数:Q值Q^π(s, a) 表示在状态 s 采取动作 a,然后 thereafter 遵循策略 π 所能获得的期望总奖励。其计算公式为:
Q^π(s, a) = Σ_{s'} T(s, a, s') * [ R(s, a, s') + γ * V^π(s') ]
这个公式求和了所有可能的下一个状态 s‘,用转移概率加权,计算即时奖励加上后续状态值的折扣值。










策略 π 的值函数与Q值的关系由贝尔曼期望方程给出:
V^π(s) = Q^π(s, π(s))
也就是说,在状态 s 的值,就等于执行策略指定的动作 π(s) 所对应的Q值。










策略评估算法通过迭代来求解 V^π

  1. 初始化所有状态的值 V(s)(例如,终止状态为0,其他状态为一个任意值)。
  2. 重复以下步骤直到值函数收敛(变化很小):
    • 对每个状态 s,计算 V_new(s) = Q(s, π(s)),其中Q值使用当前的 V 计算。
    • V_new 更新 V
      这个算法被称为迭代策略评估。它通过“引导”来逐步改进对值的估计。



策略评估告诉我们一个给定策略有多好。但我们的最终目标是找到最优策略 π*,即能获得最大可能期望总奖励的策略。

价值迭代算法可以直接计算出最优值函数 V*,其中 V*(s) 表示从状态 s 开始,遵循最优策略所能获得的最大期望总奖励。其核心是贝尔曼最优方程
V*(s) = max_{a ∈ A(s)} [ Σ_{s'} T(s, a, s') * ( R(s, a, s') + γ * V*(s') ) ]
= max_{a ∈ A(s)} Q*(s, a)
与策略评估的贝尔曼期望方程不同,这里我们取的是所有可能动作中Q值的最大值,而不是固定策略的动作。

















价值迭代算法与策略评估非常相似,只是将“使用策略动作”这一步替换为“取所有动作中的最大值”:

  1. 初始化所有状态的值 V(s)
  2. 重复以下步骤直到值函数收敛:
    • 对每个状态 s,计算 V_new(s) = max_{a} Q(s, a),其中Q值使用当前的 V 计算。
    • V_new 更新 V
      一旦我们得到了最优值函数 V*,最优策略 π* 可以通过对每个状态选择能最大化Q值的动作来恢复:
      π*(s) = argmax_{a ∈ A(s)} Q*(s, a)










对于不可靠的电车问题,价值迭代计算出的最优策略是:在位置1到4选择行走,从位置5开始尝试乘坐电车。这个策略的期望成本(-7.3)优于“总是行走”(-9)或“总是乘电车(如果可能)”(-12)的策略。

本节课我们一起学习了马尔可夫决策过程。MDP通过引入转移概率和奖励函数,扩展了搜索问题以处理不确定性。MDP的解决方案是一个策略,而不是一个简单的动作序列。我们学习了如何通过模拟和迭代策略评估来计算一个给定策略的值。最后,我们掌握了价值迭代算法,它通过求解贝尔曼最优方程,能够找到最优值函数和最优策略。这两个算法的核心都是基于动态规划和Q值的递归计算,区别仅在于价值迭代在每一步选择了最大化未来收益的动作。

在本节课中,我们将学习强化学习。强化学习是智能体通过与环境的交互来学习最优策略的一种方法。与之前学习的马尔可夫决策过程不同,在强化学习中,我们事先并不知道环境的完整模型。

上一节我们介绍了马尔可夫决策过程。本节中,我们来看看如何定义和解决一个MDP。

一个MDP由以下要素定义:

  • 起始状态
  • 后继函数:指定了在给定状态下采取某个动作后,转移到下一个状态的概率和获得的即时奖励。
  • 终止状态判断
  • 折扣因子

我们可以用一个图来可视化MDP,其中包含两种节点:状态节点(智能体在此做决策)和机会节点(环境在此根据概率决定转移结果)。

MDP的解是一个策略,它是一个从状态到动作的映射。给定一个策略,我们可以进行模拟,生成一个状态、动作和奖励的序列。一个模拟的效用是折扣奖励的总和。一个策略的价值是遵循该策略时,从某个状态开始所能获得的期望效用。

我们学习了两种算法:

  • 策略评估:计算给定策略的价值。
  • 价值迭代:通过动态规划计算最优策略的价值,并能从中提取出最优策略。

现在,我们进入新的内容。如果我们不知道MDP的模型,还能找到最优策略吗?这就是强化学习要解决的问题。

在强化学习中,我们有一个智能体和一个环境。智能体采取动作,环境返回奖励观察(通常是下一个状态)。这个过程不断重复。智能体的目标是通过试错来学习,找到能获得高奖励的动作序列。

与MDP的关键区别在于,在强化学习中,智能体一开始对环境的转移概率和奖励一无所知,必须通过交互来学习。

我们将介绍四种强化学习算法,它们可以分为两类:

  1. 基于模型的方法:先学习环境模型(MDP),再利用模型计算最优策略。
  2. 无模型的方法:直接学习策略或价值函数,无需显式构建环境模型。

以下是四种算法的简要介绍:

  • 基于模型的价值迭代:通过探索估计MDP,然后在其上运行价值迭代。
  • 无模型蒙特卡洛:通过模拟直接估计当前策略的Q值。
  • SARSA:一种时序差分学习算法,在每一步更新时使用当前策略选择的动作来估计Q值。
  • Q学习:另一种时序差分学习算法,直接估计最优策略的Q值。

接下来,我们将逐一深入探讨这些算法。

基于模型的价值迭代是一种直观的方法。既然不知道MDP,我们就先通过探索来估计它。

这个算法分为三个阶段:

  1. 探索阶段:使用一个探索策略(例如随机选择动作)与环境交互,收集数据。
  2. 模型学习与规划阶段:利用收集到的数据估计MDP的转移概率和奖励函数。然后,在这个估计的MDP上运行价值迭代,计算出最优策略。
  3. 利用阶段:执行上一步得到的最优策略。

在代码实现中,智能体内部维护一个对MDP的估计。get_action 函数在探索阶段使用探索策略,在利用阶段使用计算出的最优策略。incorporate_feedback 函数则用收到的 (状态, 动作, 奖励, 新状态) 数据来更新内部MDP的统计信息(如转移计数和平均奖励)。

总结:基于模型的RL先估计环境模型,再规划最优策略。探索阶段的性能可能较差,但这是为了学习必须付出的代价。

基于模型的方法需要学习整个MDP,但我们的最终目标只是得到一个好的策略。无模型方法试图更直接地达到这个目标。

无模型蒙特卡洛方法直接估计当前策略的 Q值。Q值 Q(s, a) 表示在状态 s 下采取动作 a,然后遵循当前策略所能获得的期望效用。

该方法通过运行完整的模拟来估计Q值。在一个模拟结束后,我们从后向前计算每个 (状态, 动作) 对的效用(即从该点开始的折扣奖励和),然后用这个观察到的效用来更新该 (状态, 动作) 对的平均Q值。

为了平衡探索和利用,智能体采用 ε-贪心 策略:

  • 以概率 ε 随机选择一个动作(探索)。
  • 以概率 1-ε 选择当前估计Q值最高的动作(利用)。

总结:无模型蒙特卡洛通过完整的模拟轨迹直接估计当前策略的Q值,无需构建环境模型。但它需要等到一个回合结束才能更新,效率较低。

蒙特卡洛方法需要等到一个回合结束才能更新Q值,这在很多现实场景中不实用。SARSA算法通过自举解决了这个问题。

自举的核心思想是:用当前的Q值估计来替代对未来回报的完整模拟。SARSA的更新公式基于收到的 (状态, 动作, 奖励, 新状态, 新动作) 元组(这也是其名称的由来)。

  • α 是学习率。
  • γ 是折扣因子。
  • s‘, a‘ 是采取动作 a 后到达的下一个状态及在该状态下根据当前策略选择的动作。

这个公式将当前的Q值向一个更接近实际观察到的“目标值”(即时奖励加上对未来价值的折扣估计)的方向调整。

重要提示:SARSA是一种同策略算法,因为它评估和优化的是它当前正在执行的那个策略(即ε-贪心策略)的Q值。

我们最终目标是学习最优策略的Q值,而不是当前探索策略的Q值。Q学习是一种异策略算法,它允许我们做到这一点。

注意,在估计未来价值时,Q学习使用的是在下一个状态 s‘ 上所有可能动作中最大的Q值,而不是像SARSA那样使用根据当前策略实际选择的动作 a‘ 的Q值。这意味着Q学习直接估计的是最优Q值 Q*,而不受当前探索行为的影响。

在代码中,这通常体现为在 incorporate_feedback 时,用 max 操作代替根据策略选择动作。

总结:Q学习通过异策略更新,直接估计最优策略的Q值,是强化学习中非常核心和强大的算法。

本节课我们一起学习了强化学习的基础。我们首先回顾了已知MDP时的解决方案(策略评估与价值迭代)。然后,我们进入了真正的强化学习设定:智能体在与未知环境的交互中学习。

我们探讨了四种经典的RL算法:

  1. 基于模型的价值迭代:先学习模型,再规划。
  2. 无模型蒙特卡洛:通过完整回合直接估计策略价值。
  3. SARSA:使用时序差分自举进行同策略学习。
  4. Q学习:使用时序差分自举进行异策略学习,直接逼近最优值。

这些算法为智能体在未知世界中通过试错学习如何行动提供了基本框架。下一讲,我们将面对状态空间巨大的挑战,并学习如何用函数近似等方法来应对。

在本节课中,我们将学习强化学习的核心算法之一:策略梯度方法。我们将从回顾强化学习的基本概念开始,然后探讨如何直接优化策略以最大化期望效用,而不是通过估计值函数。我们将学习策略梯度定理,并了解如何通过采样轨迹来近似计算梯度,从而更新策略参数。最后,我们将讨论一些用于减少梯度估计方差的技术,如基线函数。


上一节我们介绍了基本的强化学习算法。本节是强化学习的第二讲,我们将推广到更大的基于状态的模型,并探索允许你直接学习策略的基于策略的算法。这将使我们更接近人们在强化学习中实际使用的最新技术。

我们首先从马尔可夫决策过程开始,理解了Q学习、SARSA等算法。现在,我们希望通过本讲的学习,你能掌握理解几乎所有前沿强化学习算法的关键要素。

强化学习更像是一种设定,而非特定的算法。这种设定非常优雅,可以说是思考人工智能最通用的方式。

  • 你有一个智能体,它在环境中采取行动。
  • 环境给予智能体奖励和观察结果。
  • 在这个过程中,智能体需要理解奖励和观察结果,并为后续迭代选择更好的行动。

在我们研究的设定中,环境由一个马尔可夫决策过程定义。智能体将是一个强化学习算法。我们上次讲座中研究了多种强化学习算法,特别是Q学习,其中你定义某种探索策略,然后我们研究了ε-贪心策略,其中获取行动的函数会根据当前策略进行探索,或者在学习过程中探索正在学习的策略。学习率控制着强化学习算法估计其Q值的速度。

这是从智能体视角看的一个交互示例。最初,你从状态1开始。环境要求给出状态1下的行动。然后,行动进入环境,环境返回结果:你从状态1走到状态2,获得-1奖励,并且尚未结束。现在,环境调用智能体获取状态2下的行动。智能体可能返回“行走”。环境会说:智能体,你从状态2行走,进入状态3,奖励-1,尚未结束。然后它会再次调用智能体询问状态3下的行动,智能体可能说“乘坐电车”,环境更新并说:智能体,在状态3,你乘坐电车,最终到达状态6,获得-2奖励,现在你完成了。

这是一个特定的“轨迹”,每个轨迹都会产生一个“效用”,它是一个代表折扣奖励总和的数字。如果你生成大量轨迹,比如20个,并平均所有这些轨迹的效用,就定义了这个强化学习算法相对于这个MDP的“价值”。

为了定义算法,定义不同类型的“价值”很有用。价值是期望效用的同义词。

  • V^π(s):这个数字代表从状态s开始遵循策略π的价值。它表示如果你被放入状态s并遵循策略π,进行无数次轨迹,期望效用是多少。
  • Q^π(s, a):在状态s中首先采取行动a,然后遵循策略π的价值。
  • V^*(s):从状态s开始遵循最优策略的价值。
  • Q^*(s, a):首先采取行动a,然后遵循最优策略的价值。

你的强化学习算法可以基于模型,也可以不基于模型。

  • 基于模型:意味着你首先估计MDP,然后使用价值迭代计算最优策略。
  • 无模型:我们看到了第一种无模型方法,即基于价值的方法,我们不直接估计转移和奖励,而是直接估计Q值。一旦你有了Q值,你基本上选择能给你最高Q值的行动,这就是你的策略。从Q到策略相对直接,但从奖励或MDP到Q值则不那么直接。

基于价值的方法的一般形式是:我们正在估计Q(s, a)。当我们获得反馈时,我们对Q(s, a)应该是什么有了一些新的观点。我们称这个为“目标”,目标是对效用的估计。当我们进行更新时,我们基本上取旧的Q(s, a),并根据学习率将其向目标方向移动。如果目标已经是Q(s, a),那么这不会做任何事情,但如果目标高于Q(s, a),那么我们将把它推向目标方向。

在我们的算法中,你遵循某个策略来生成轨迹,我们称之为“探索策略”。使用该反馈,算法将估计一个策略的Q值,我们称之为“估计策略”。

  • 同策略:意味着探索策略和估计策略是相同的。你获得的数据来自你试图估计的策略。
  • 异策略:意味着你生成的数据来自一个不是估计策略的策略。

SARSA是一个同策略算法,因为它试图估计你正在遵循的策略的Q值。Q学习是异策略的,因为你试图估计最优策略的Q值。异策略算法非常有用,因为你可以获取来自某个源的数据,然后用它来估计你想要的策略,这通常是最优策略。

我们研究了两种选择目标的方法:

  • 完整轨迹:意味着从状态s开始,你实际上一直轨迹到结束状态,然后取折扣奖励总和作为效用,你使用这个数字。但问题是,你必须等到结束才能得到一个可以更早估计的数字。
  • 自举法:意味着我们不等结束,我只获取初始奖励,然后不使用轨迹到结束,而是使用我当前的估计来估计我将获得什么样的未来效用。我正在从模型估计中“自举”我的效用。

考虑到所有这些概念,我们现在可以思考上次研究的四种算法:

  1. 基于模型的价值迭代:我们首先估计MDP,然后使用价值迭代计算最优策略。
  2. 无模型蒙特卡洛:你遵循某个策略π,只看从特定状态和采取特定行动的完整轨迹,并将目标设置为该效用。没有自举,我只是使用效用的蒙特卡洛估计。
  3. SARSA:我仍然试图估计Q^π,所以我是同策略的,但我使用自举法,其中我不使用效用,而是取初始奖励,然后在这里代入后继状态的Q值。我不费心去轨迹并弄清楚最后发生了什么,我只是使用Q值。
  4. Q学习:几乎相同,但有一个小变化:现在我正在估计最优策略的价值。这是一个异策略算法,仍然使用自举法,这就是为什么它看起来像SARSA,唯一的区别是我在这里对a'取最大值,而不是让a'等于π(s')。

到目前为止,我们为每个状态-行动对估计一个Q值。这被称为强化学习中的“表格设定”,之所以称为表格设定,是因为你本质上有一个查找表。

但在现实世界的设定中,你无法做到这一点。例如,如果你试图学习机器人策略,你的状态可能是机器人看到的图像,你的行动将是如何移动机器人手臂。或者,如果你在处理语言模型,你的状态可能是一个完整的句子或段落,你的行动是生成下一个标记。在这些情况下,状态空间是巨大的,你当然不能有一个按图像索引的查找表。

那么我们应该如何处理这个问题呢?答案是使用“函数近似”。在强化学习的背景下,函数近似用于与表格学习进行对比。如今,有了深度强化学习,函数近似已经是一个既定事实,因为每当你有一个大的状态空间时,别无选择。

表格设定是你为每个(s, a)对有一个查找表,你存储一个数字Q(s, a)。函数近似说:等等,我们从机器学习中学到了什么?我们学到的是,你实际上可以学习非常高维输入的非常复杂的函数。所以s和a,假设它们是图像或句子,是非常大的东西。我们知道如何将其映射到一个数字。那么,我们为什么不直接用一些参数θ来参数化这个函数,然后尝试直接估计参数θ,而不是尝试直接估计Q呢?这就是函数近似背后的思想。

现在回想一下机器学习讲座。我们必须弄清楚什么?我们必须弄清楚可能的函数是什么,这就是假设空间或假设类。在强化学习的背景下,我们如何知道一个特定的Q_θ是好是坏?以及你使用什么算法来减少损失?这一切都应该看起来很熟悉,本质上我们现在能够将机器学习的许多思想融入到强化学习环境中。

如果你能推断,取我们从强化学习中学到的一切和从机器学习中学到的一切,我们现在就把它们结合起来。

那么这里可以选择什么可能的函数呢?s和a可以是句子或图像,所以通常我们要做的是将其映射到一个特征向量,因为机器学习喜欢处理向量、矩阵和张量。

  • 线性函数:简单地是某个参数向量θ和特征向量φ(s, a)的点积。
  • 多层感知机:我们简单地取这个向量,乘以一个矩阵,然后应用一些非线性,然后再乘以另一个向量或矩阵,依此类推。

我不打算过多讨论这里的选择,但请将其视为一个可以放入你最喜欢的模型架构的地方。

让我们尝试一个例子。定义与之前相同的环境(MDP)。现在我们将定义相同的探索策略,现在我们将进行参数化Q学习。为了简单起见,我们将假设状态-行动对仅映射到指示器特征,因此我们为每个状态-行动对有一个特征。这将允许我们使用机器学习来模拟表格设定,以便我们可以检查一切是否正常工作,但希望你能发挥想象力,放入其他更强大的机器学习模型。

在类中,我将有我的线性模型,它将特征数量映射到代表Q值的单个标量,我将有我的优化器,它只是随机梯度下降。

让我们弄清楚这个特征向量应该是什么样子。从概念上讲,我只是将状态-行动对映射到一个介于0和状态数乘以行动数减1之间的数字。状态编号为1到6,所以我将其设为0到5乘以行动数加上该行动的整数表示。在这种情况下,这是0。我创建了一个长度为特征数量的独热向量。这将是“状态1,行走”的特征表示,这将是“状态1,电车”的特征表示,“状态2,行走”,“状态2,电车”,依此类推,直到“状态6,电车”。每个状态-行动对只是一个不同的特征向量。这一切都是手动编码的,这里没有学习。

现在,我可以计算状态和行动对的Q值。为此,我首先将其映射到特征向量空间,然后我只是将其传递给模型,然后得到一个数字。这就是我计算特定状态-行动对的Q值的方式。

现在,既然我知道如何计算Q值,我就可以计算策略。在状态1获得的策略将是计算所有行动的Q值,然后选择具有最高Q值的行动,这将为我提供策略返回的行动。

现在我有了构建块,我可以实现get_actionincorporate_feedback,这是每个强化学习算法需要做的事情。

get_action中,这与之前相同,我以概率ε进行探索,以概率1-ε不探索。

现在让我们看看incorporate_feedback。环境说我走到状态2,我应该用它做什么?现在,我要计算目标。为了计算目标,我将查看self.pi(next_state)。记住,π将取Q值的argmax,这将给我最优行动,给定我当前的Q估计。然后我将计算目标为即时奖励加上折扣乘以Q(next_state, next_action)。我正在使用自举法,所以我只是插入了下一个状态和下一个行动的Q值。

现在我有了目标。我也有预测值,如果我在状态s并采取行动a,我期望的价值是多少?我希望这个值接近目标。回想一下回归,当我们希望两个东西彼此接近时,我们做什么?我们将损失定义为标准平方损失,它惩罚预测值和目标之间的偏差。

现在我已经定义了一个损失,我可以计算相对于该损失的梯度。这只是标准的PyTorch操作,然后我更新参数。

希望你现在能看到机器学习如何进入强化学习。基本上,get_actionincorporate_feedback以及如何进行Q学习的骨架基本上就是现在指定目标。给定目标后,所有的损失计算和模型架构就只是在机器学习的领域内了。

现在我为Q学习做了这个,你可以想象为SARSA或无模型蒙特卡洛做同样的事情,它只是插入其中。

现在也许你回去说get_action,现在以1-ε的概率,我只是选择我目前拥有的最优行动,然后我incorporate_feedback,计算目标,计算预测奖励,形成损失,计算梯度,优化,更新参数。然后get_action这次我也在探索,然后incorporate_feedback我得到我处于结束状态,所以没有下一个状态,没有下一个行动,所以那只是奖励,但尽管如此,它仍然是可以更新的目标,计算损失,计算损失的梯度并更新参数。

如果你模拟这个MDP 100次,那么你会得到一些权重和一些价值。让我们看看计算出的最优策略。我在这里做的是对于每个状态,我将调用强化学习算法的pi函数来获取它为我存储的策略。这次它没有,也许我在这里运气不好。这是随机的,所以它实际上最终没有得到正确的策略,因为它应该走了,走了,走了,然后乘坐了电车,但它没有这样做。但如果我运行更长时间,它应该做一些合理的事情。

我在这里用这个策略做的是,我也在查看最优值的最优估计,即取Q(state, pi(state))。然后我得到这些值。让我们通过与求解MDP得到的真实值进行比较。记住我有原始的MDP,我只是对其调用价值迭代,原始的MDP对我们的算法不可用,所以我实际上不能在算法中这样做,所以我在外部做。我得到结果。如果你看实际值,这些是MDP的真实最优值。这是强化学习算法得出的结果。它有点合理,但有点偏差。这是我们的实际最优策略。

我们讨论的是函数近似。你拥有大的状态或行动空间,你不能使用表格设定,你不能只是查找所有可能的图像或句子。所以我们要做的是参数化Q值,通过一些线性或非线性映射从状态-行动到某个价值数字。

我们首先将状态-行动对映射到特征向量。然后我们将定义一个线性函数或MLP将该特征向量映射到单个数字。当我们incorporate_feedback时,我们将定义预测Q值和目标之间的平方损失,目标是由进行Q学习提供给我们的。然后我们将取损失函数相对于θ的梯度,并朝那个方向迈出一步。

现在我们将转向一种不同的强化学习方法。这是策略梯度或基于策略的方法的空间。

如果你记得我们从哪里开始,我们从基于模型的强化学习开始,这意味着我们首先估计MDP,然后使用该MDP通过评估来计算最优策略。然后我们说,等等,我们甚至不需要MDP,为什么我们不直接计算Q值呢?然后使用Q值,我们可以通过给定状态下给我们最大Q值的行动来获得策略。这些被称为基于价值的方法。

但现在如果你注意,你说,等等,实际上我们甚至不需要Q值。我们可以直接估计策略。我们为什么不直接这样做呢?简短的回答是否定的,但希望稍后更长的答案会变得清晰。

思考策略的方式就是将其视为一个分类器。分类器将输入映射到输出。所以从某种意义上说,一切都是分类器。这里的输入是状态,输出是行动。

如果你记得机器学习线性分类讲座,我们说这些分类器实际上很难优化,因为你最终会得到像0-1损失这样的东西,梯度处处为零,你无法做到。所以我们做了概率分类器,所以我们有一个概率分类器,它接受一个状态s,然后定义可能行动上的分布。分布是连续的,因此我们可以优化它们。

现在让我们稍微谈谈模仿学习。如果我们有该策略的演示,这实际上会很容易。演示基本上是由一个专家给你一个轨迹。专家来了说,好的,这是你要做的:你走到状态2,你走到状态3,你乘坐电车到6。如果你有这些数据,你可以说,好的,我将把它变成我的训练算法的一堆例子。如果输入是1,我想行走。如果输入是2,我想行走。如果输入是3,我乘坐电车。3个例子。然后你可以说,我将定义一个目标函数J(θ),它对所有示例求和,并查看给定相应状态下行动的对数概率。

这被称为模仿学习,因为你有一个专家向你展示该做什么,现在你只是训练分类器/策略去做专家所说的事情。

例如,这实际上是在原本是强化学习问题的背景下完成的。在机器人技术中,有人告诉或操作机器人说,好的,这是你如何拿起杯子并将其放在柜台上而不打破它。在数学中,公司会雇佣懂数学的人去解决一堆数学问题并写出好的解决方案,这些就是在给定状态下专家会做什么的演示。

所以你不需要强化学习算法来进行模仿学习,这只是监督学习。但问题是,如果你没有演示怎么办?记住强化学习框架,环境不够友好,不会给你“这是你应该做的”。环境是残酷的。它只会给你奖励或不给奖励。所以我们只有这个奖励函数,那么我们应该做什么?是的,你可以探索。

所以你能做的本质上就是轨迹你的策略,获取一些数据。但你不想只是轨迹然后克隆那些数据,你不想做那些数据告诉你的任何事情。但伴随着那些数据,它告诉了你那个结果有多好。所以你可能会想,好吧,我将进行轨迹,有些轨迹会很好,有些会很糟糕,我只取好的那些,然后进行模仿学习,你不会离实际发生的事情太远。

如果你记得,如果你只想记住零阶的事情,在策略梯度中,你基本上只是轨迹你的策略,收集一堆轨迹,你取那些有高奖励的,然后对它们进行模仿学习。在本讲的其余部分,我将给你一些比这更细致的东西,带有更多的数学,但希望直觉是清晰的。

好的,让我们开始吧。这部分将比前几部分有更多的数学。请戴上你的数学思考帽。

我们有一个轨迹。我将使用τ来表示轨迹。我使用术语“轨迹”,我认为轨迹、情节可以互换思考。所以我们的轨迹基本上是状态、行动、奖励、状态、行动、奖励、状态、行动、奖励、状态。一个具体的轨迹看起来像我们之前一直在看的东西,你有行走、行走、电车。记住,每个轨迹产生一个效用。这是标准的。

现在,轨迹的概率是多少?我的意思是这样事情发生的概率是多少?根据链式法则,我们可以将其写为一组条件概率。

它是从我们的设定中开始状态s0的概率。在我们的设定中,这是确定性的,所以如果假设τ的第一个元素是s0,那么这只是1。然后第一件事是有一个策略π_θ,给定状态s采取第一个行动的概率是多少?然后乘以从s0和a1转移到状态s1的转移概率。现在是智能体的回合,给定s1采取行动a2的概率,环境的回合,给定s1和a2转移到状态s2的概率。然后是智能体的回合和环境的回合,依此类推。

所以轨迹的概率是这个交错的序列:智能体策略的概率,环境转移的概率,智能体,转移,智能体转移。再说一遍,组成部分是:有一个策略项,然后有一个转移分布项。

现在,如果你想想我们在强化学习中试图做什么。我们所做的只是试图找到一个最大化轨迹期望效用的策略。我可以直接写下来。所以θ的价值,记住θ是策略的参数,等于τ的效用的期望。如果我写下来,基本上是思考,嗯,期望是关于什么的?它是关于所有可能轨迹τ的期望,以及该轨迹的概率乘以该轨迹的效用。

这可能是对强化学习应该做什么的最直接的陈述。你实际上是在说期望效用。我们只是想优化这个。没有MDP,没有Q值,从某种意义上说,这是你能做的最直接的事情。

现在,我们如何优化这个?我们只学会了一种优化函数的方法:梯度下降。所以让我们取梯度。这里的期望可能有点烦人,但我们还是做吧。

梯度V,我只是写出V的定义。到目前为止,一切都好。我将期望的定义扩展为这个对τ的显式求和。让我把这个写大一点。这是对所有轨迹的期望。所以这是对所有轨迹的求和,该轨迹的概率乘以该轨迹的效用。这些只是定义。我将梯度移到期望或求和内部,因为梯度是线性操作。

现在我要做点什么。那么梯度是什么?你可能会想,嗯,这取决于P_θ是什么。它只是P_θ的梯度。但我要做的事情一开始可能看起来有点奇怪。我要把它重写为P_θ乘以log P_θ的梯度。你可能会想,好的,这是从哪里来的?它来自……让我看看。好吧,让我这样写。log的梯度是什么?记住,log的梯度是1除以那个量乘以内部任何东西的梯度。然后我所做的就是把这个移到这里,这就是我如何用P_θ乘以这个来写这个。我这样做的原因是因为现在我有了一个对轨迹求和乘以该轨迹的P_θ的东西,我可以整齐地将其包装回期望中。所以每当你看到这个期望,你应该把它看作是对轨迹求和乘以该轨迹的概率。

现在我有上面这个东西的梯度,这可能不太明显如何微分,现在我已经把它写成了这个期望,其中我有这个量的梯度。这个恒等式被称为策略梯度定理,但我的意思是,它基本上是初等的,所以我只是称它为那个恒等式。它不值得被称为定理。

所以这实际上是好的,因为一般来说,每当你看到一个期望并且你想计算它,但你不能,因为它需要对所有可能的轨迹求和,你可以想:也许我可以只从那个中取一个随机样本。这就是我们要在这里做的。我们将用只是一个样本来替换这个期望。

所以不是对所有可能的轨迹求和并按该轨迹的概率加权,我只是采样一个轨迹。然后我将定义一个目标函数J,它只是内部的东西:log P_θ(τ) 乘以效用τ。然后我可以通过朝这个梯度的方向迈出一步来更新θ。

让我在这里暂停一下,总结一下。我们从这个无可争议的期望效用最大化目标开始。我做了一些……说,好的,我们现在只知道通过取梯度来优化东西。所以让我们取梯度。梯度实际上是期望的东西。它说,你可以只取一个样本来近似完整的期望。现在,我们将定义这个目标函数,其梯度正是内部的东西。

所以也许只是预示一些东西。这基本上是在说:去吧,探索,进行你的轨迹,一旦你得到一个轨迹,我基本上在看这个项并按该轨迹的效用加权。然后只是更新它。所以如果我没有这个效用,我只会进行模仿学习,只是最大化我看到的轨迹的概率,但现在有了效用,它对本质上这个轨迹有多好很敏感。

如果你想想展开这个梯度项。这将是效用乘以对所有时间步的求和,即给定前一个状态采取行动的概率,对所有行动,对所有时间步的求和。这被称为强化学习中的REINFORCE算法,它来自Williams 92,是这种一般类别的策略梯度算法的一个实例,但REINFORCE可能是最早和最简单的。

就像我之前说的,这里的直觉是,我们本质上是在对我们知道和理解的演示进行模仿学习。演示来自我们自己的策略,但它们按效用加权。如果效用只是0或1,基本上是成功或失败,那么这只是对成功演示的模仿学习。

所以我之前提到的直觉,即对你的策略进行一堆轨迹,然后只取好的那些并进行模仿学习,正是REINFORCE在这种所有效用都是0和1的特殊情况下会做的事情。

现在,如果它们不是0和1,那么你就有更多一点。如果效用是0.5,那么它说,嗯,我在那个示例轨迹上的权重是0.5,如果效用是-10,那么我就像在远离它,说不要那样做,不要那样做。

那么这个效用是在哪里定义的呢?轨迹的效用,如果你记得,是折扣奖励的总和,所以当你有一个轨迹时,它只是-1乘以折扣乘以-1加上折扣平方乘以-2。

希望这应该非常直观:策略梯度。现在,总结一下:直接优化策略以最大化期望效用。由于策略梯度定理或恒等式,我们可以通过采样单个轨迹来计算梯度的无偏估计,然后只是更新它。

算法是:你采样一个轨迹,这意味着你是同策略的,然后按效用加权更新轨迹中的每个状态-行动对。

现在我们已经完成了数学,让我尝试实现它。我们从相同的MDP开始,现在我有REINFORCE。注意我们不需要……好的,所以REINFORCE,我现在有一个模型,它将本质上从状态映射到行动进行分类。所以它是一个在多个行动上的概率分类器,这就是为什么它现在是一个矩阵,因为我是多类的。然后我和以前一样有优化器。

就像在无模型蒙特卡洛中一样,我们将在incorporate_feedback时跟踪当前的轨迹,因为在我定义的当前算法中,你必须等到获得效用。注意我们不需要显式的探索策略,因为我们现在正在定义这些概率策略,这应该给我们一些探索。当然,你也可以根据需要添加额外的探索,但这里我们绝对不需要。

让我们看看get_actionincorporate_feedback做什么。get_action,我要计算状态的特征表示。这将是一个代表状态的独热向量。我将把这个特征向量传递给我的线性矩阵。这将给我一些逻辑值。然后我将取softmax,这将给我这些行动上的概率分布,然后我将根据这些概率进行采样,然后我将获取行动并返回它。所以get_action所做的只是你在分类中会做的事情:你计算逻辑值,得到分布,现在我从那个分布中采样。

那么incorporate_feedback做什么?就像在无模型蒙特卡洛中一样,我们只是要记住轨迹,所以记住起始状态,跟踪效用,如果我不在结束状态,我不做任何更新。我将get_actionincorporate_feedbackget_action,现在最后一次当我incorporate_feedback时,我处于结束状态。所以这是我的轨迹。现在我想更新参数。所以我要跟踪损失。我将遍历轨迹的每一步。轨迹的每一步都从某个状态到特定行动。第一次将是状态1采取行走。记住,这是分类器的输入和输出。所以,我现在要计算模型对给定状态的行动的预测,所以计算特征向量,计算逻辑值。现在记住在多类分类中,我计算逻辑值和目标之间的交叉熵,目标在这种情况下只是行动的独热编码(行走)。然后我加上那个损失。所以我希望这些逻辑值与这里的目标匹配。算法的形式是相同的。所以你进入第二步,你为第二步添加你的交叉熵项,然后你进入第三步,然后你为第三步添加交叉熵项。我应该将损失乘以效用。现在你更新你的参数,计算这个损失的梯度,然后迈出一步,现在这些是更新的参数。

让我们看看如果我运行它会发生什么。我得到一些权重,得到一些价值。看起来它起作用了,即使我搞乱了算法。有趣。所以我学到了一个分布,在状态1,我应该行走,状态2,我应该行走,状态3,我应该乘坐电车,状态4行走,状态5行走,状态6行走,或者我猜状态6是结束状态。所以这些值只是有点随意。

总结一下:get_action只是从策略中采样。incorporate_feedback更新参数,轨迹中的状态-行动对,并按效用加权,我没有做,但你应该做。

这是在线的。所有强化学习算法通常都是在线的,除非是离线强化学习算法,因为每当你这样做时,你是在线的:你获取行动,你合并反馈,你获取行动,合并反馈,依此类推。这里,这只是一个轨迹,我已经在更新参数了。有时你可能想要批处理,比如有一堆轨迹,你把它们批处理起来,所以它看起来更像离线,但精神是在线的。

现在让我谈谈这里的一些附加功能。回想一下目标:最大化期望效用。所以我们可以直接写下来。策略梯度定理说,这是梯度。我们不能精确计算梯度,因为那将涉及对所有可能轨迹求和。

但我们所做的是使用REINFORCE来说,我将通过只取一个样本并计算该样本的梯度来获得该梯度的估计。但你能得到更好的估计吗?为了谈论“更好”意味着什么,我将通过这个快速绕道来讨论方差减少。

考虑一个简单的设定,你只是试图估计一组数字的均值。i是列表的索引。每个数字都有一个特定的概率,所以有四个数字。这应该是0.25,0.25,概率总和为一,点数是-4,-6,6和8。所以你希望真实均值是这些向量的点积,我们暂时假设这些总和为一,我稍后会修正。

一个估计量,正式地说,是任何试图接近μ的随机变量。记住,μ是你想要计算的东西,这里计算起来很昂贵,因为你要求和对四个东西,一般来说,你是在对所有可能轨迹取均值,这很难。

每个估计量都有某种偏差和方差,也许还有一些计算成本。

μ的简单估计是你只采样一个索引,然后返回该位置的点。所以你可能会采样一个索引,然后你得到点,然后你返回它。所以每次你计算估计量,你可能会得到一个不同的值。然后我们如何知道估计量是否好,我们必须计算它的偏差和方差,所以让我们尝试1000次,我们将调用估计量函数,然后我们查看它的均值和方差。

对于这个特定的估计量,均值是1,这是它应该的,所以我猜一切都归一化了,所以想象这是0.25,0.25,然后方差是36,如果你想想,这并不好。通常,如果你在做随机梯度下降,高方差意味着你将需要更多迭代才能得到正确答案。

这是另一个估计量。为什么我们不只采样两个点呢?然后只是平均它们。所以如果你看那个估计量,均值大致相同,但方差小得多。所以在某种意义上,这是对均值的更好估计。如果你选择一个点,然后只是给它添加一些随机噪声,你也可以让它变得更糟。所以如果你这样做,那么均值仍然大致正确,它是无偏的,但方差会更糟,甚至比原始的更糟。

现在是有趣的部分。现在假设我有这个神奇的函数偏移量i。这将具有均值零。这意味着如果我减去这个偏移量,根据期望的线性,这与这个相同。然后这部分是0。所以那是相同的。它具有相同的均值。所以假设我只是定义这个偏移量为-6,-6,6,6。所以我要采样一个特定的索引,而不是只取那个点,我只是要移除一个偏移量,然后我要返回它。所以如果我这样做,你会注意到均值是好的,方差突然下降了很多。

所以这是魔法,对吧?我设法在不影响均值的情况下大幅减少了方差。如果你不关心均值,很容易让方差下降,你只返回0。然后那会给你一个不正确的答案。但在这里,只要我选择某个均值为0的函数,我可以把它加到我的估计量中,并希望我能减少方差。这在统计学中被称为控制变量,这是一个非常强大的通用思想。

那么回到强化学习设定,我们如何找到一个均值为0的偏移量?并希望它能减少方差。只是提供一些直觉,为什么这有效?这是有效的,因为如果你想想均值是1,对吧?所以这边的那些太低了,那边的那些太高了。所以这所做的是,它把太低的那些拉上来,把太高的那些拉下来。所以如果我对均值相对于我的点可能在哪里有一些先验知识,那么我可以希望减少方差。

这是关键的恒等式。我要声称,我将定义一个函数B(s)。它可以是任何只依赖于状态而不依赖于行动的函数。然后我要声称这个量成立。那么这是什么?记住,这是log策略梯度乘以这个基线的期望。这对所有从该策略中抽取的s和a都成立。我还没有证明这个,但我只是希望你们盯着这个看一会儿。如果你想想为什么这有帮助,如果你看这里,策略梯度定理是这个东西。所以这意味着如果这是零,我可以把它加或减到那个上。我不影响均值,但我有机会减少方差。

如果你记得A算法,A中的启发式思想是使用领域知识来改进算法,如果它能估计未来成本,我就能得到一个非常快的算法。所以这有点类似,如果我能找出正确的基线,这个B将被称为基线函数,我实际上也可以大大减少方差。

证明是相当直接的。它就像这样。让我们取B(s)的期望,这是一个常数。它不依赖于θ。现在我要取这个量相对于θ的梯度,梯度是零。实际上为了节省时间,我将跳过这个,只是相信我这是可行的,基本上它与用于策略梯度定理的数学相同,只是朝另一个方向进行。

所以使用这个思想,有几件事。我只是想强调它们,我没有时间详细讨论它们。

  • 使用基线:我可以简单地从效用中减去一个基线,只要那个函数不依赖于行动,那么我可以做任何我想做的事情,我可以想出一个模型,某种启发式方法,这可以减少方差。
  • 仅使用未来奖励:我可以在每一步使用仅从该点开始的奖励,而不是使用效用。这是有效的,因为过去不影响未来。
  • 引入价值函数估计:我也可以插入价值函数的偏差估计。所以我要带回Q值。我要说我在做策略梯度,但我不使用实际效用(这是我在无模型蒙特卡洛中所做的),我要带回Q值,这是我在这些自举方法中所做的。这些方法被称为演员-评论家方法,因为它们允许你同时估计价值和策略,在深度学习中,你甚至可以将参数绑定在一起。

总结一下,这里的游戏是找到这个期望效用的梯度的估计,该估计具有低偏差和低方差。

  • 通过使用基线,这是一个相当通用的策略来减少方差,但它仍然是无偏的,这很好,偏差为零。
  • 你还可以使用自举法以减少方差为代价引入一些偏差。

最后,让我总结一下整个关于MDP和强化学习的讲座。我们研究了进行强化学习的三种方法类别:

  1. 基于模型:估计MDP,计算最优策略。
  2. 基于价值:直接估计Q值并推导最优策略。
  3. 基于策略:直接估计策略。

在所有三种情况下,算法的形式是相似的:你用某个探索策略进行轨迹,你形成某种损失函数,它可以是关于MDP参数、Q值或策略的,然后你使用梯度步骤更新参数。

这结束了关于MDP和强化学习的部分,我们试图最大化期望效用。接下来我们将研究如果环境中有对手会发生什么,你不能再真正使用期望,你必须考虑最坏情况。


在本节课中,我们一起学习了策略梯度方法,这是一种直接优化策略以最大化期望效用的强化学习技术。我们从回顾强化学习的基本概念开始,包括基于模型和无模型方法、同策略与异策略学习,以及表格设定与函数近似。然后,我们深入探讨了策略梯度定理,学习了如何通过采样轨迹来近似计算梯度,并实现了REINFORCE算法。最后,我们讨论了减少梯度估计方差的技术,如基线函数和演员-评论家方法。这些知识为我们理解现代强化学习算法奠定了坚实的基础。

在本节课中,我们将要学习博弈论的基础知识。我们将从理解什么是博弈开始,学习如何评估博弈的价值,并探索几种计算最优策略的递归方法。最后,我们将讨论如何通过精确或近似的方法来加速这些计算过程。

上一节我们讨论了马尔可夫决策过程和强化学习,再之前我们讨论了搜索问题。博弈将完成我们对基于状态模型的探索之旅。让我们从一个例子开始。

我们将玩一个游戏。这个游戏暂时称为“游戏一”。这里有三个箱子:A、B和C。你需要选择其中一个箱子。然后,我会从你选择的那个箱子里选一个数字。你的目标是最大化最终被选中的数字。

你的策略应该取决于我会做什么。例如,如果有人选择了A,我可能很仁慈,给你50分;或者我可能想让你输,给你-50分。博弈的挑战在于,你不知道对手会怎么做。

在MDP中,智能体试图最大化效用,而环境是随机且未知的。如果环境未知,我们就进行强化学习,使其变得已知。在博弈中,智能体仍然试图最大化效用,但环境中存在一个对手,其策略是未知的。

博弈的关键对象是博弈树。树的根节点是游戏的起始状态。从节点出发的每条边代表在该状态下可以采取的动作。每条从根到叶的路径是一次游戏推演或轨迹。每个节点都需要一个玩家做出决策。有些节点是智能体做决策,有些节点是对手做决策。

在本课程中,我们将专注于两人零和博弈。两人意味着玩家数量为两个,通常是智能体和一个对手。零和意味着智能体的效用等于对手效用的负值。两者相加为零。因此,如果智能体获得效用1,对手就获得效用-1。每个玩家都试图最大化自己的效用,总效用为零。

我们可以正式定义一个博弈。一个博弈包含:

  • 起始状态 s_start
  • 在每个状态,可以调用函数检查游戏是否结束 isEnd(s)
  • 在每个状态,有一个玩家函数 player(s),指明轮到谁行动(智能体 agent 或对手 opp)。
  • 每个状态给出一个后继状态集合 succsAndProbs(s),这里我们将其写为从动作到状态的映射。

博弈的特殊之处在于:

  1. 所有效用都在终局状态获得。这被称为稀疏奖励问题,因为在到达终局之前,你不知道会发生什么。
  2. 不同的玩家控制不同的状态。在MDP中,我们有智能体控制节点和机会节点。在博弈中,我们还会看到对手控制节点。

在符号上,一个策略 π_P(s) 是玩家 P 在状态 s 下采取的动作。一个随机策略 π_P(a|s) 是玩家 P 在状态 s 下采取动作 a 的概率。

给定一个博弈以及每个玩家的策略,博弈的价值是所有可能推演的期望效用。这与MDP中定义策略在特定状态下的价值非常相似。

让我们看一个具体策略。假设在“游戏一”中,智能体总是选择A(确定性策略)。对手随机地在动作1和2之间选择(随机策略,各0.5概率)。我们可以通过模拟函数来玩游戏:从起始状态开始,当游戏未结束时,查看轮到谁,根据该玩家的策略采样一个动作,然后根据游戏动态转移到后继状态。最终,你会得到一个效用值。

多次模拟并取平均,可以得到期望效用的蒙特卡洛估计。我们也可以精确计算博弈价值,而无需模拟。

以下是计算博弈价值的递归公式 V_eval(s)

  • 基础情况:如果状态 s 是终局,则返回该状态的效用 utility(s)
  • 智能体回合:如果 player(s) == agent,则计算 sum_{a} π_agent(a|s) * V_eval(succ(s, a))
  • 对手回合:如果 player(s) == opp,则计算 sum_{a} π_opp(a|s) * V_eval(succ(s, a))

这个计算是精确的,但可能需要指数时间。如果每个节点有两个动作,游戏进行100步,就需要计算 2^100 次,这非常耗时。因此,在实践中,我们可能更倾向于使用蒙特卡洛模拟来估计价值。

总结:价值是智能体在博弈中的期望效用。我们可以通过推演模拟并平均效用来获得蒙特卡洛估计,也可以精确计算(但可能是指数时间)。这类似于MDP中的策略评估

现在,我们不再评估固定的智能体策略,而是要在给定固定对手策略的情况下,找到最优的智能体策略。这被称为期望最大算法

其原理图是:智能体节点(三角形,取最大值),然后是固定策略的对手节点(圆形,取期望值),依此类推。

期望最大价值 V_expectimax(s) 的递归公式如下:

  • 基础情况:如果 isEnd(s),返回 utility(s)
  • 智能体回合:如果 player(s) == agent,则计算 max_{a} V_expectimax(succ(s, a))
  • 对手回合:如果 player(s) == opp,则计算 sum_{a} π_opp(a|s) * V_expectimax(succ(s, a))

与博弈评估的唯一区别在于智能体回合时,我们取最大值而不是加权和。因为智能体希望最大化期望效用。

在“游戏一”的例子中,假设对手策略是随机选择(1或2,各0.5概率)。在对手节点,我们像之前一样取平均值。在智能体节点(根节点),我们取子节点价值中的最大值。因此,最优动作是选择C。

期望最大算法找到了针对固定对手策略的最优智能体策略。这类似于MDP中的价值迭代

到目前为止,我们假设对手策略是已知的。但博弈的核心在于我们不知道对手的策略。我们应该怎么做?这里有一个可以遵循的原则,称为最小最大算法:假设对手会尽最大努力对付你,对手将采取能最小化你效用的**可能策略。

最小最大递归公式体现了这一原则。我们有向上三角形表示取最大值(智能体),向下三角形表示取最小值(对手)。

最小最大价值 V_minimax(s) 的递归公式如下:

  • 基础情况:如果 isEnd(s),返回 utility(s)
  • 智能体回合:如果 player(s) == agent,则计算 max_{a} V_minimax(succ(s, a))
  • 对手回合:如果 player(s) == opp,则计算 min_{a} V_minimax(succ(s, a))

这就是它被称为“最小最大”的原因:我们交替进行最大化和最小化。

在“游戏一”的例子中,对手节点现在是取最小值的节点。我们取 (-50, 50) 的最小值得 -50,取 (1, 3) 的最小值得1,取 (-5, 15) 的最小值得 -5。然后智能体在这些最小值中取最大值,得到1。因此,最优动作是选择B。

最小最大算法给出了一个状态的价值,即当智能体采取最优策略以最大化效用,而对手采取最优策略以最小化效用时,智能体的期望效用。

我们可以将最小最大递归转化为策略。该策略在给定状态下,计算该状态的最小最大价值及对应动作,并返回该动作。当智能体和对手都采取最优策略时,这被称为完美对弈。解决一个博弈意味着知道根节点的最小最大价值。

总结:在最小最大算法中,智能体最大化效用,对手最小化效用。与期望最大算法不同,这里没有给定任何固定策略。期望最大算法仅针对固定策略是最优的,而最小最大算法则与对手的任何先验策略无关。这是博弈独有的部分,在MDP中没有类比。

我们已经计算了各种递归,并得到了相应的策略。让我们看看这些策略和价值之间的关系。

我们有以下策略:

  • π_max: 最小最大算法得到的最优智能体策略。
  • π_min: 最小最大算法得到的最优对手策略。
  • π_expectimax(π_?): 针对某个固定对手策略 π_? 的期望最大策略。
  • π_?: 某个固定的对手策略。

我们用 V(π_agent, π_opp) 表示当智能体策略 π_agent 与对手策略 π_opp 对弈时的博弈价值。

根据定义,我们可以得出一些关系:

  1. π_max 是针对 π_min 的**策略:V(π_max, π_min) >= V(π, π_min) 对于任何其他智能体策略 π
  2. π_min 是针对 π_max 的**策略:V(π_max, π_min) <= V(π_max, π) 对于任何其他对手策略 π。这意味着 V(π_max, π_min) 是智能体在未知对手情况下的一个下界
  3. π_expectimax(π_?) 是针对 π_? 的**策略:V(π_expectimax(π_?), π_?) >= V(π, π_?) 对于任何其他智能体策略 π,包括 π_max

一个重要结论是:如果你了解你的对手,你可以做得比最小最大策略更好。如果你知道对手很弱,你可以采取一些在面对强敌时不敢尝试的策略。

本节将介绍期望最小最大算法,作为递归方法的另一个例子。

假设有一个变体游戏:你选择A、B、C中的一个箱子。然后我抛一枚硬币。如果是正面,我将向左移动一个箱子(循环),并从那个箱子选数字;如果是反面,我保持原箱子不变。你的目标仍然是最大化被选中的数字。

为了建模这个游戏,我们引入一个“硬币”策略,以0.5概率选择“正面”或“反面”。在游戏树中,我们会有智能体节点(取最大值)、对手节点(取最小值)和机会节点(取期望值)。

期望最小最大价值 V_expectiminimax(s) 的递归公式包含三种情况:

  • 基础情况:如果 isEnd(s),返回 utility(s)
  • 智能体回合max_{a} V_expectiminimax(succ(s, a))
  • 对手回合min_{a} V_expectiminimax(succ(s, a))
  • 机会节点回合sum_{a} π_chance(a|s) * V_expectiminimax(succ(s, a))

你可以想象各种不同的递归。这个通用框架可以处理许多情况:多于两个玩家、额外回合、选择下一个玩家等。然而,它不能处理不完全信息博弈(如扑克),因为状态必须包含所有信息。我们目前也只考虑零和、回合制博弈。

现在让我们专注于最小最大算法,并尝试加速它。基本的递归需要指数时间。Alpha-Beta 剪枝的关键在于,你不需要访问所有状态就能知道某些部分不值得探索。

其原理是分支定界。我们为每个节点维护一个区间(界限):

  • 对于Max节点,我们有一个下界 α(值至少这么大)。
  • 对于Min节点,我们有一个上界 β(值至多这么小)。

最小最大价值必然来源于某个叶子节点。最优路径是由最小最大策略到达该叶子节点的路径。如果某个节点的界限与其所有祖先节点的界限都不重叠,那么该节点就不可能位于最优路径上,可以被剪枝。

排序很重要。访问后继状态的顺序会影响剪枝的数量。在实践中,对于Max节点,我们希望先访问价值可能更大的子节点(降序);对于Min节点,我们希望先访问价值可能更小的子节点(升序)。这样能更快地收紧界限,从而进行更多剪枝。我们可以使用启发式评估函数来对子节点排序。

总结:Alpha-Beta 剪枝加速了最小最大搜索,并且是精确的。节省多少时间取决于排序和具体问题。一般来说,它仍然是指数时间的。

评估函数是一种近似加速搜索的方法。其思想是:不再搜索到底,而是直接“猜测”一个状态的好坏。评估函数 eval(s) 捕获了关于什么可能是“好”状态的先验知识。

例如,在国际象棋中,评估函数可能是不同项的总和:棋子价值(材料)、机动性、国王安全性、中心控制等。

如何使用评估函数?你可以进行深度受限搜索。设定一个深度限制 d。在递归进行最小最大搜索时:

  • 如果深度 d == 0,则返回评估函数值 eval(s)
  • 否则,正常递归,但在递归到子节点时,将深度减1(注意确保深度单位对应双方各走一步)。

深度受限搜索没有最优性保证,它是一种启发式方法。其效果取决于评估函数的好坏。搜索得越深,对评估函数错误的敏感性就越低;如果搜索很浅,那么评估函数必须非常好。

评估函数让你想起了什么?在强化学习中,Q值或价值函数就是一种对真实价值的近似。这引出了下一个想法:评估函数也可以通过学习得到(例如通过监督学习或强化学习),这将是我们下一讲的内容。

本节课我们一起学习了博弈论的基础知识。

我们引入了博弈的概念。在博弈中,智能体仍然试图最大化效用,但对手的策略是未知的。最小最大原则告诉我们,假设最坏情况,即对手试图对付你并最小化你的效用。

我们定义了一系列不同的递归方法:给定博弈和策略,我们可以进行博弈评估、期望最大、最小最大、期望最小最大等计算。

我们探讨了两种加速计算的方法:

  1. Alpha-Beta 剪枝:一种精确的方法,通过维护界限和剪枝来减少需要搜索的节点数。
  2. 评估函数:一种近似的方法,通过深度受限搜索并结合对状态的快速评估来指导决策。

下一讲,我们将探讨如何在博弈的背景下进行学习,并介绍一种称为时序差分学习的方法。

在本节课中,我们将学习如何将强化学习应用于游戏,并探讨同时博弈与非零和博弈的概念。我们将从回顾上节课的极小极大原理开始,然后介绍时间差分学习,最后扩展到更复杂的博弈类型。

上一节我们介绍了双人零和博弈,并学习了如何使用极小极大原理来求解。在博弈树中,代理在“最大”节点试图最大化其效用,而对手在“最小”节点试图最小化代理的效用。

极小极大值的计算公式如下:

GPT plus 代充 只需 145value(state) = max_{action} value(result(state, action)) // 如果是代理的回合 min_{action} value(result(state, action)) // 如果是对手的回合 utility(state) // 如果是终止状态 

为了加速精确搜索,我们介绍了Alpha-Beta剪枝,它通过维护祖先节点的值上下界来避免探索不必要的子树分支。

当状态空间过大时,我们使用评估函数来近似估计状态的好坏。例如,在国际象棋中,评估函数可能结合了棋子数量、机动性和中心控制等因素。本节课的核心问题是:我们能否学习这个评估函数?

本节中,我们将利用强化学习,特别是时间差分学习,来学习游戏的评估函数。首先,让我们回顾一下强化学习中的两个核心概念。

在基于价值的强化学习中,我们关注:

  • 状态价值函数 V^π(s):表示从状态 s 开始,遵循策略 π 所能获得的期望效用。
  • 动作价值函数 Q^π(s, a):表示在状态 s 下先采取动作 a,然后遵循策略 π 所能获得的期望效用。

我们之前学过的SARSA算法是一种同策略算法,它通过自举法来估计当前策略的 Q 值。其更新规则为:

Q(s, a) ← Q(s, a) + α * [r + γ * Q(s', a') - Q(s, a)] 

其中 (s, a, r, s', a') 是一次经验,α 是学习率,γ 是折扣因子。

给定 Q 值,我们可以通过简单地选择最优动作来导出一个策略:π(s) = argmax_a Q(s, a)。这可以看作是一步策略提升。

然而,如果我们只有状态价值函数 V(s),要导出策略就需要知道环境的动态(即转移概率和奖励),因为我们需要计算 Q(s, a) = Σ_s‘ P(s’|s, a) * [R(s, a, s‘) + γ * V(s‘)]。在一般的强化学习中,我们不知道环境模型,所以通常直接学习 Q 函数。但对于游戏,规则通常是已知且确定性的。我们使用强化学习的原因并非未知模型,而是因为状态空间巨大,我们需要借助函数逼近来有效处理。

TD学习可以看作是 SARSA 对 V^π 的类比。它直接估计状态价值函数 V(s)。其核心思想是利用经验进行自举更新。

给定一次经验 (s, a, r, s‘),TD学习按以下步骤更新:

  1. 计算当前模型对状态 s 的预测值:V_pred = V(s)
  2. 计算目标值target = r + γ * V(s‘)。这里 V(s‘) 使用当前参数计算,但在梯度更新时被视为常数(即“断开”梯度连接)。
  3. 定义损失函数,例如均方误差:L = (target - V_pred)^2
  4. 通过梯度下降更新参数 w,使预测值向目标值靠近:w ← w - α * ∇_w L

参数更新公式可以简写为:

GPT plus 代充 只需 145w ← w + α * (target - V(s; w)) * ∇_w V(s; w) 

以下是TD学习在简单MDP(非游戏)中的伪代码示例,展示了如何从V值导出的策略进行行动:

# 假设我们有一个估计的 V 值函数和已知的 MDP 模型 def get_action(state, V, mdp): # 计算每个动作的 Q 值 Q_values = {} for action in mdp.actions(state): # 由于知道模型,可以计算期望 next_state = mdp.transition(state, action) # 确定性情况 reward = mdp.reward(state, action, next_state) Q_values[action] = reward + mdp.gamma * V[next_state] # 使用 epsilon-贪婪策略选择动作 return epsilon_greedy(Q_values) def incorporate_feedback(state, reward, next_state, V, alpha): # TD(0) 更新 target = reward + gamma * V[next_state] V[state] = V[state] + alpha * (target - V[state]) 

现在,我们将TD学习专门用于双人零和博弈。游戏的特殊性在于:转移通常是确定性的,奖励只在游戏结束时给出,并且存在两个利益对立的玩家(代理和对手)。

适应方法非常巧妙:让代理和对手使用同一个价值函数 V(s)。这被称为自对弈。代理和对手都根据这个共享的 V(s) 来决定行动,但目标相反:

  • 代理的策略:选择能使后续状态价值最大化的动作。π_agent(s) = argmax_a V(Succ(s, a))
  • 对手的策略:选择能使后续状态价值最小化的动作。π_opponent(s) = argmin_a V(Succ(s, a))

这样,我们只需要学习一个评估状态好坏的函数 V(s),就能同时为双方玩家提供策略。

历史实例

以下是利用自对弈和强化学习在游戏中取得突破的几个著名例子:

  • 西洋跳棋 (1959):Arthur Samuel的程序通过自我对弈学习线性评估函数,结合手工特征和Alpha-Beta剪枝,达到了业余水平。
  • 双陆棋 (1992):Gerald Tesauro的TD-Gammon使用神经网络和简单的特征表示,通过数百万局自我对弈,达到了人类专家水平,甚至为游戏策略提供了新见解。
  • 围棋 (2016):AlphaGo Zero仅使用棋盘石头位置作为输入,通过深度神经网络和蒙特卡洛树搜索进行自我对弈,完全无需人类知识,最终超越了所有旧版本和人类选手。

这些案例表明,随着计算力和数据的增长,学习系统对人工特征工程的依赖逐渐减少。

上一节我们专注于回合制博弈。现在,我们来看看两种重要的扩展。

在同时博弈中,玩家同时行动,例如“石头剪刀布”。我们无法再用博弈树建模,因为每个节点无法明确归属单一玩家。

我们通过收益矩阵来定义这种博弈。考虑一个“猜手指”游戏:

  • 玩家A和B各出示1或2根手指。
  • 若都出1,B给A 2美元。
  • 若都出2,B给A 4美元。
  • 否则,A给B 3美元。

收益矩阵 V(a, b) 表示玩家A的收益(玩家B的收益为 -V(a, b)):

AB 1 2 1 2 -3 2 -3 4

策略分为纯策略(确定性地选择一个动作)和混合策略(按一定概率分布选择动作)。博弈值定义为双方按各自混合策略行动时,A的期望收益:V(π_A, π_B) = Σ_a Σ_b π_A(a) * π_B(b) * V(a, b)

一个关键问题是:后行动者是否有优势?在纯策略下,是的,因为后行动者可以根据先行动者的选择做出**反应。但在混合策略下,冯·诺依曼极小极大定理指出:对于任何有限的双人零和同时博弈,先动与后动的极小极大值相等。即:

GPT plus 代充 只需 145max_{π_A} min_{π_B} V(π_A, π_B) = min_{π_B} max_{π_A} V(π_A, π_B) 

这意味着,如果你采用最优的混合策略,即使向对手公开你的策略,也不会处于劣势。在“猜手指”游戏中,最优混合策略是玩家A以 7/12 的概率出1,以 5/12 的概率出2,博弈值为 -1/12(对A略不利)。

在非零和博弈中,玩家的收益之和不一定为零,这更接近现实中的许多互动情境。经典的例子是囚徒困境

  • 两个囚徒被分开审讯,可以选择“坦白”或“抵赖”。
  • 收益(以刑期负值表示)矩阵如下:
    • (坦白, 坦白): (-5, -5)
    • (坦白, 抵赖): (0, -10)
    • (抵赖, 坦白): (-10, 0)
    • (抵赖, 抵赖): (-1, -1)

这里,每个格子中的第一个数字是玩家A的收益,第二个是玩家B的收益。

非零和博弈的核心解概念是纳什均衡。一组策略 (π_A*, π_B*) 构成纳什均衡,如果没有单个玩家可以通过单方面改变自己的策略而获得更高收益。纳什证明,在任何有限玩家和有限动作的博弈中,至少存在一个纳什均衡(可能是混合策略均衡)。

在囚徒困境中,唯一的纳什均衡是(坦白,坦白),尽管(抵赖,抵赖)对双方整体更好。这揭示了个人理性可能导致集体非最优结果。

与零和博弈相比:

  • 零和同时博弈:有唯一的极小极大值和最优混合策略。
  • 非零和博弈:可能存在多个纳什均衡,且均衡点仅代表局部稳定性,而非全局最优。

本节课中,我们一起学习了如何将强化学习与博弈论结合。

  • 我们首先回顾了极小极大搜索和评估函数,并提出了学习评估函数的需求。
  • 接着,我们介绍了时间差分学习,它通过自举法直接估计状态价值函数 V(s)。
  • 我们将TD学习适配到游戏中,引入了自对弈的概念,让代理和对手共享同一个价值函数,但根据最大化或最小化其值来采取行动。我们还回顾了历史上自对弈在跳棋、双陆棋和围棋中取得的成功。
  • 最后,我们将视野扩展到同时博弈,学习了收益矩阵、混合策略和冯·诺依曼极小极大定理。我们还简要介绍了非零和博弈以及纳什均衡的概念,理解了在合作与竞争交织的环境中找到稳定策略的方法。

至此,我们完成了关于序列模型和博弈论的单元。下一讲我们将开始一个全新的主题:贝叶斯网络。

在本节课中,我们将学习如何表示和推理不确定的世界。我们将从概率论的基础知识开始,然后介绍贝叶斯网络——一种用于定义复杂联合分布的强大工具。最后,我们将探讨如何使用概率程序和拒绝采样进行近似推理。

上一节我们介绍了智能体的不同建模方法。本节中,我们来看看如何用概率论来形式化地表示世界状态。

我们通过一组随机变量来表示世界的属性。例如,变量 S 表示是否晴天(1是,0否),变量 R 表示是否下雨。

给定这些变量,我们可以描述世界可能处于的所有状态,称为赋值。例如,S=0, R=0 表示既不是晴天也不是雨天。

联合分布为每一个可能的赋值分配一个概率。它就像世界的“真相之源”。对于两个变量,我们可以用一个矩阵(或张量)来表示。

# 示例:联合分布 P(S, R) # 行对应 S 的值 (0, 1),列对应 R 的值 (0, 1) P_SR = [[0.20, 0.08], [0.70, 0.02]] 

边缘化 操作是忽略某些变量,将只在这些变量上取值不同的赋值合并(概率相加)。直觉上,你是在“忽略”一些变量的差异。

例如,计算 P(S),我们需要对变量 R 求和:
P(S=s) = Σ_r P(S=s, R=r)



我们可以使用爱因斯坦求和约定(einsum)来表示这个计算:

GPT plus 代充 只需 145P_S = np.einsum('sr->s', P_SR) 

条件概率 是在观察到某些证据(部分赋值)后,更新对其他变量的信念。例如,观察到下雨 (R=1) 后,晴天 (S) 的概率是多少?

计算分为三步:

  1. 选择:只保留满足证据 (R=1) 的赋值行。
  2. 计算证据概率:将选中行的概率相加,得到 P(R=1)
  3. 归一化:将选中行的每个概率除以证据概率,得到条件分布 P(S | R=1)

einsum 表示选择过程:

# R1 是一个选择张量,当 R=1 时为 1,否则为 0 R1 = [0, 1] # 选择并边缘化 R P_S_given_R1_selected = np.einsum('sr,r->s', P_SR, R1) # 计算证据概率 P_evidence = np.einsum('s->', P_S_given_R1_selected) # 归一化得到条件概率 P_S_given_R1 = P_S_given_R1_selected / P_evidence 

总结:联合分布是基础。边缘化是忽略变量,条件概率是在证据下重新归一化。概率表就是张量,可以用 einsum 进行计算。

上一节我们回顾了概率论的基本操作。本节中,我们来看看如何利用这些操作进行推理,并引入贝叶斯网络来更高效地定义联合分布。

概率推理的任务是:给定一个定义好的联合分布(就像数据库),回答关于某些变量的问题(就像数据库查询)。问题通常形式为:P(查询变量 | 证据变量=某些值)。未在查询或证据中提及的变量会被边缘化掉。

假设你家有警报器。地震 (E) 和盗窃 (B) 都可能触发警报 (A)。已知 P(B)=0.05, P(E)=0.05,且两者独立。警报在 BE 发生时响起。
现在,你在旅行时收到警报 (A=1),随后又看到新闻说发生了地震 (E=1)。问题是:得知地震后,你家里发生盗窃的概率 P(B|A=1,E=1) 是上升、下降还是不变?



直觉上,地震“解释”了警报的原因,因此盗窃的可能性应该下降。这就是“解释消除”现象。为了精确计算,我们需要定义 P(B, E, A) 的联合分布。直接列出所有8种赋值的概率很繁琐,而贝叶斯网络提供了模块化的方法。

上一节我们看到了一个需要联合分布的例子。本节中,我们来看看如何通过四个步骤系统地构建一个贝叶斯网络,从而定义联合分布。

以下是构建贝叶斯网络的通用步骤:

  1. 定义随机变量:确定要建模的世界中的关键属性。在警报例子中,变量是 B (盗窃), E (地震), A (警报)。
  2. 绘制有向无环图 (DAG):用节点表示变量,用有向边表示直接的依赖或影响关系。边从“因”指向“果”(需谨慎理解因果关系)。在警报例子中,BEA 的父节点。
    GPT plus 代充 只需 145B -> A E -> A 
  3. 定义局部条件概率:为图中的每一个节点 X_i 定义一个概率表 P(X_i | Parents(X_i))
    • 根节点(无父节点)的条件概率即其先验概率。
    • 在警报例子中:
      • P(B){0: 0.95, 1: 0.05}
      • P(E){0: 0.95, 1: 0.05}
      • P(A | B, E):一个函数,当 A = (B OR E) 时概率高,否则概率低。
  4. 通过乘积定义联合分布:整个网络的联合分布是所有局部条件概率的乘积。
    P(B, E, A) = P(B) * P(E) * P(A | B, E)
    对于每一个具体的赋值 (b, e, a),其概率等于三个对应概率值的乘积。











重要提醒

  • 每个节点只有一个条件概率表,它依赖于其所有父节点的联合取值。
  • 用小写 p 表示我们直接定义的局部条件概率,用大写 P 表示从联合分布推导出的边缘或条件概率

通过这个四步法,我们以一种直观、模块化的方式定义了整个联合分布,无需显式列出指数级数量的赋值。

上一节我们学会了如何构建贝叶斯网络。本节中,我们来看看如何利用已定义的联合分布进行概率推理,并验证“解释消除”效应。

一旦有了联合分布 P(B, E, A),我们就可以回答任何概率查询。计算过程本质上是应用之前介绍的选择(条件化)和边缘化操作。

查询1:仅收到警报时,盗窃的概率是多少?
计算 P(B | A=1)



  1. 用张量 A1 选择 A=1 的行。
  2. 边缘化变量 E
  3. 计算证据 A=1 的概率(对选中行求和)。
  4. 归一化得到 P(B | A=1)
    计算结果约为 0.51。收到警报后,盗窃的概率从先验的 0.05 大幅上升。



查询2:收到警报且得知地震后,盗窃的概率是多少?
计算 P(B | A=1, E=1)



  1. 用张量 A1E1 同时选择 A=1E=1 的行。
  2. 边缘化变量 EA(实际上选择后 E 已固定,A 在查询中未出现)。
  3. 计算证据 A=1, E=1 的概率。
  4. 归一化得到 P(B | A=1, E=1)
    计算结果约为 0.05



结论P(B | A=1, E=1) ≈ 0.05 < P(B | A=1) ≈ 0.51。得知地震后,盗窃的概率下降了。这证实了“解释消除”效应:观察到的地震(原因)解释了警报(结果),从而降低了对另一个潜在原因(盗窃)的怀疑度。即使 BE 先验独立,在给定其共同后代 A 的证据后,它们也变得相关了。

上一节我们在警报例子中看到了贝叶斯网络的威力。本节中,我们通过一个医疗诊断的例子来巩固理解,并再次观察“解释消除”。

问题:如果你咳嗽 (H=1) 并眼睛发痒 (I=1),你患感冒 (C) 的概率是多少?

构建贝叶斯网络

  1. 变量C (感冒), A (过敏), H (咳嗽), I (眼睛发痒)。
  2. 图结构:感冒和过敏是独立原因。咳嗽可由感冒或过敏引起。眼睛发痒仅由过敏引起。
    C -> H A -> H A -> I 
  3. 局部概率(示例值):
    • P(C=1) = 0.1
    • P(A=1) = 0.2
    • P(H=1 | C, A):如果 C=1A=1,则概率高 (0.9),否则低 (0.1)。
    • P(I=1 | A=1) = 0.9, P(I=1 | A=0) = 0.1
  4. 联合分布P(C, A, H, I) = P(C) * P(A) * P(H|C,A) * P(I|A)

概率推理

  • 查询1P(C=1 | H=1)。计算结果约为 0.28。仅咳嗽时,感冒概率从先验 0.1 上升。
  • 查询2P(C=1 | H=1, I=1)。计算结果约为 0.13

分析:增加“眼睛发痒”这一证据后,感冒的概率降低了。这同样是“解释消除”:眼睛发痒强烈提示过敏 (A),而过敏可以解释咳嗽的症状,从而降低了对感冒 (C) 作为咳嗽原因的信度。贝叶斯网络自动捕捉并量化了这种复杂的推理模式。

上一节我们通过两个实例演练了贝叶斯网络。本节中,我们给出贝叶斯网络的一般形式化定义,并总结其核心思想。

一个贝叶斯网络由以下部分组成:

  1. 一组随机变量X_1, X_2, ..., X_n
  2. 一个描述变量间依赖关系的有向无环图 (DAG)。每个节点对应一个变量。
  3. 一组局部条件概率分布 (CPD):对于每个变量 X_i,给定其父节点 Parents(X_i),有一个条件概率分布 p(X_i | Parents(X_i))

该网络定义的联合概率分布为所有局部条件概率的乘积:
P(X_1, ..., X_n) = Π_{i=1}^n p(X_i | Parents(X_i))



概率推理的任务是:给定证据 E = e(部分变量的观测值),计算查询变量 Q 的后验分布:
P(Q | E = e)
所有既不在 Q 也不在 E 中的变量都会被边缘化。










关键点

  • 模块化:允许我们直观地、分块地构建大型概率模型。
  • 解释消除:是贝叶斯网络中一个重要的定性推理模式,当多个原因共同影响一个结果时会出现。
  • 表示能力:许多模型可以看作贝叶斯网络,例如自回归语言模型(每个词依赖于之前的所有词)。

上一节我们形式化地定义了贝叶斯网络。本节中,我们介绍另一种表示分布的方法——概率程序,并学习一种简单的近似推理算法:拒绝采样。

我们可以用一段生成式程序来定义联合分布,这称为概率程序。它通过描述如何生成一个随机样本来隐式地定义分布。

以警报问题为例:

GPT plus 代充 只需 145def alarm_model(): B = np.random.binomial(1, 0.05) # 采样盗窃 E = np.random.binomial(1, 0.05) # 采样地震 A = 1 if (B == 1 or E == 1) else 0 # 确定警报 return {'B': B, 'E': E, 'A': A} 

运行这个函数一次,就得到联合分布 P(B, E, A) 的一个样本。

给定一个可以生成样本的概率程序(即定义了联合分布),我们可以用拒绝采样来近似计算条件概率 P(Q | E=e)

算法步骤如下:

  1. 从联合分布(先验)中生成大量样本。
  2. 对于每个样本,检查它是否满足证据 E = e
  3. 丢弃所有不满足证据的样本(“拒绝”)。
  4. 在满足证据的样本中,统计查询变量 Q 取各个值的频率。
  5. 用这些频率来近似后验概率 P(Q | E=e)
def rejection_sampling(model, evidence_fn, query_fn, num_samples=1000): counts = {} for _ in range(num_samples): sample = model() if evidence_fn(sample): # 检查证据 q_val = query_fn(sample) # 提取查询值 counts[q_val] = counts.get(q_val, 0) + 1 total = sum(counts.values()) # 归一化频率得到近似概率 probs = {k: v/total for k, v in counts.items()} return probs 

优点:概念简单,易于实现,适用于任何能采样的概率模型。
缺点:当证据 P(E=e) 很小时,绝大多数样本会被拒绝,效率极低。但它保证在样本数趋于无穷时收敛到真实值。



本节课中,我们一起学习了概率推理和贝叶斯网络的基础知识。

我们首先回顾了概率论的核心概念:用联合分布表示世界状态,以及边缘化和条件概率两种基本操作。接着,我们引入了贝叶斯网络,它通过四步法——定义变量、构建图、指定局部条件概率、取乘积——提供了一种模块化、直观地定义复杂联合分布的方法。

我们通过“警报”和“医疗诊断”两个例子,实践了在贝叶斯网络上进行概率推理,并观察到了重要的“解释消除”现象。然后,我们探讨了概率程序作为一种替代表示法,并学习了拒绝采样这一简单但低效的近似推理算法。

贝叶斯网络将知识表示与概率推理相结合,能处理缺失数据、融入先验知识、提供可解释性。然而,精确推理的计算成本可能很高。在下一讲中,我们将探讨更高效、更精巧的精确与近似推理算法,以应对这一挑战。

在本节课中,我们将学习贝叶斯网络中的概率推断方法,特别是吉布斯采样算法。我们还将探讨条件独立性的概念,并理解图结构与概率属性之间的联系。


上一讲我们开始讨论贝叶斯网络。贝叶斯网络是表示世界,特别是世界不确定性的新篇章。上次我们研究了拒绝采样作为回答贝叶斯网络查询的一种方法。本次课程我们将主要关注吉布斯采样,这是一种可能更快的概率推断方法。之后我们将讨论条件独立性。

让我们从回顾贝叶斯网络开始。贝叶斯网络可能是本课程中最深入的部分之一,所以如果有任何困惑,请随时提问。

为了让我们进入正确的思维模式,我们应该将一组变量的联合分布视为一个描述世界如何运作的数据库。世界的状态由一组变量的赋值表示,而数据库基本上说明了每个赋值出现的可能性。

我们通过一个四步程序来定义贝叶斯网络:

  1. 确定问题中的变量。通常我们谈论变量 X1 到 XN,但在具体例子中,我们可能看到三个变量:B(表示是否有入室盗窃)、E(表示是否有地震)和 A(表示警报是否响起)。
  2. 在所有变量上定义一个图。在这个例子中,我们直观地认为入室盗窃和地震是独立事件,但警报会取决于是否有入室盗窃或地震。警报在有入室盗窃或地震时会响起。
  3. 为每个节点指定给定其父节点的局部条件分布。对于节点 B,其概率是 P(B);对于节点 E,其概率是 P(E);对于节点 A,其概率是 P(A | B, E)。
  4. 联合分布定义为所有局部条件分布的乘积。在这个例子中,联合分布 P(B, E, A) = P(B) * P(E) * P(A | B, E)。

为了用代码具体化,我们可以查看概率表。例如,P(B) 表示一个表格,其中入室盗窃发生的概率是 0.05,不发生的概率是 0.95。P(E) 类似。P(A | B, E) 表示给定 B 和 E 状态时警报响起的概率。在这个逻辑模型中,A 等于 B 或 E 的逻辑或结果。

给定这些表格,我们可以将一组随机变量的联合分布简单地定义为所有局部条件分布的乘积。


我们能用贝叶斯网络做什么?我们可以推断给定某些变量时其他变量的概率。这是一种联合分布,可以看作一个数据库,但使用的是概率推断的语言,而不是 SQL。

例如,我们可能感兴趣的是:在警报响起的情况下,发生入室盗窃的概率是多少?计算这个查询的方法如下:

  1. 首先,我们有概率张量 P(A, B, E)。
  2. 然后,我们对证据进行条件化。证据是 A=1。我们取出张量中 A=1 的切片。
  3. 接着,我们边缘化掉我们不关心的变量 E。这对应于将具有不同 E 值但其他值相同的行合并。
  4. 这给出了 P(B, A=1)。
  5. 为了得到条件概率 P(B | A=1),我们需要计算证据的概率 P(A=1),这可以通过对 P(B, A=1) 中 B 的所有可能值求和得到。
  6. 最后,将 P(B, A=1) 除以 P(A=1) 就得到了条件概率 P(B | A=1)。在这个例子中,结果是 0.51。

这种方法的一个缺点是,以这种方式形成联合分布可能非常慢。想象一下,如果你有 100 个变量,每个变量有两个值,那么总赋值数将是 2^100,你肯定不想写出所有这些。

因此,我们将进行近似推断,尝试近似答案并希望得到最好的结果。

我们稍微绕道解释了概率程序,这是思考贝叶斯网络的另一种方式,以便引入拒绝采样。概率程序是一个从联合分布中返回样本的程序,因此它定义了分布。

拒绝采样的思想是:

  1. 声明感兴趣的查询变量(例如 B)和证据(例如 A=1)。
  2. 从概率程序中抽取样本。
  3. 检查样本是否满足证据(即 A 是否等于 1)。
  4. 如果满足,则提取查询变量的值(B 的值)并计入计数。
  5. 重复此过程多次,最后根据计数归一化得到概率估计。

拒绝采样的问题在于,如果证据很罕见,它会非常慢。因为你是生成样本而不考虑证据,只是希望程序恰好生成证据。虽然拒绝采样简单且在极限情况下被证明有效,但它并不是最有效的方法。


那么,我们如何能更快地做到这一点?这将是本讲座下一部分的主题。

现在我将讨论吉布斯采样。拒绝采样的特点是每个样本都是独立的,但缺点是我每次都是从零开始,并且生成样本时不考虑证据。如果证据罕见,会导致大量拒绝。

吉布斯采样是另一种采样过程。其思想是,我将处理一个始终满足证据的先前样本,然后随时间逐渐修改它。这是一种更渐进的方法,而不是丢弃所有内容、重新采样并希望命中证据。

吉布斯采样的基本思想是:

  1. 从一个任意的满足证据的赋值开始。
  2. 然后,我迭代地一次改变一个变量,给定其他变量的值。
  3. 我以一种特定的方式这样做,以便得到一堆样本,这些样本在极限情况下也能给出正确的答案。

值得注意的是,吉布斯采样是更广泛算法类别——马尔可夫链蒙特卡洛的一个特例。其思想是你有一系列抽取的样本,每个样本都依赖于前一个,这就是为什么它被称为马尔可夫链。吉布斯采样的特点是我们从一开始就使用满足证据的样本,因此不需要拒绝任何东西。但缺点是样本之间不是独立的。

让我通过一个简单的例子来讲解吉布斯采样。假设我们有一个“传话游戏”的贝叶斯网络模型。消息是单个比特(0 或 1)。第一个消息 A 以 0.5 的概率为 0,0.5 的概率为 1。B 给定 A 的概率是:以 0.8 的概率保留消息,以 0.2 的概率翻转它。C 给定 B 的概率相同。

现在,我想问的概率推断查询是:假设最后一个人 C 收到 1,那么 A 等于 1 或 0 的概率是多少?直观上,看到 C=1 可能会增加 A=1 的概率,因为出错的概率小于 50%,但有噪声,所以不一定是 1。

首先,我们运行拒绝采样。使用 100 个样本,我们估计 P(A=1 | C=1) 约为 0.65。

现在,让我们进行吉布斯采样。伪代码如下:

  1. 从一个满足证据(C=1)的特定初始化样本开始(例如 A=1, B=0, C=1)。
  2. 然后,我轮询所有变量(除了证据变量 C),一次改变一个变量。
  3. 要改变一个变量(例如 B),我计算给定所有其他变量(A 和 C)时,该变量的条件分布。
  4. 然后,根据这个条件分布,为该变量采样一个新值。
  5. 更新赋值,并记录查询变量(A)的值。
  6. 重复多次迭代。

计算条件分布 P(B | A, C) 的方法是:它等于联合概率 P(A, B, C) 除以 P(A, C)。联合概率是局部条件概率的乘积。我们只需要为正在采样的变量(B)考虑其不同取值(0 和 1)下的联合概率,然后归一化这些值以获得一个有效的分布,并从中采样。

在吉布斯采样中,我们不需要为所有可能的 A、B、C 赋值实例化联合分布,因为我们只关心特定赋值及其附近赋值的概率。这是获得节省的地方。

吉布斯采样算法的运行时间是:迭代次数 × 变量数 × 变量取值域大小 × 计算联合概率时需要涉及的变量数。


接下来,我将展示如何通过利用贝叶斯网络的属性使吉布斯采样更高效。这将引入一个新概念:马尔可夫毯。

想象一个任意的概率图。在吉布斯采样中,对于每个变量,对于该变量的每个值,我都必须考虑整个贝叶斯网络中的所有变量。直觉上,我们似乎可以避免这样做,因为只有一个变量在变化,其他变量可能并不都重要。这些交互可能是局部的。

在“传话”贝叶斯网络(A -> B -> C)中,假设我们正在采样 P(A | B, C)。通常,我们会查看 A=0 和 A=1 的联合分布。但观察表达式 P(A) * P(B|A) * P(C|B),其中最后一个因子 P(C|B) 不依赖于 A。在分子和分母中,这个因子会被乘以和除以相同的数,因此可以完全忽略它。

一般来说,问题在于可以丢弃哪些变量,不能丢弃哪些变量。我们只需要包含与正在采样的变量直接交互的变量。B 连接到 A,所以我不能丢弃 P(B|A)。但 C 没有直接连接到 A,所以我可以丢弃 P(C|B)。

需要考虑的变量集合称为马尔可夫毯。在贝叶斯网络中,一个变量的马尔可夫毯简单地包括其所有子节点和父节点。

这意味着,在计算赋值概率时,我们不需要包含整个联合概率,而只需要包含马尔可夫毯中的项。对于三变量网络:

  • 如果采样变量是 A,我只需要看 P(A) 和 P(B|A),不需要看 P(C|B)。
  • 如果采样变量是 B,我只需要看 P(B|A) 和 P(C|B),不需要看 P(A)。

如果使用这个函数来评估每个赋值的得分并运行吉布斯采样,我们会得到与使用完整联合概率的吉布斯采样相同的结果(在浮点精度内)。但这更快,因为评估一个赋值的概率时,只需要考虑马尔可夫毯的大小,而不是变量的总数。

如果马尔可夫毯很小,这会高效得多。即使马尔可夫毯很大,这也不会有什么坏处。


现在让我们将吉布斯采样应用到我们熟悉的警报网络。我们有入室盗窃 B、地震 E 导致警报 A。我们初始化一个满足证据(A=1)的任意样本。我们感兴趣的是 P(B=1 | A=1)。运行吉布斯采样,我们可能得到像 0.6 或 0.33 这样的估计,而不是精确的 0.51。这表明它可能效果不佳。

采样算法只是近似的,其效果因情况而异。在尝试这些算法之前,了解它们何时有效、何时无效非常重要。

让我们从拒绝采样开始。拒绝采样何时困难?答案是当证据概率很低时。因为你将拒绝大多数样本,实际保留的样本数基本上与证据概率成反比。如果证据概率低,你只能得到很少的样本,甚至可能为零。

那么,什么例子对吉布斯采样来说是困难的?答案是当变量高度相关时。例如,两个变量 A 和 B,A 以 0.5 概率为 0 或 1,而 B 总是等于 A。那么 P(A) 应该是 0.5。拒绝采样没有问题。但吉布斯采样会卡住。如果从 (0,0) 开始,尝试采样 A:给定 B=0,A=1 的概率是 0,所以只能选择 A=0。同样,采样 B 也会被固定。因此,吉布斯采样会完全卡在 (0,0),无法移动,从而错误地估计 P(A=1)=0。

所以,我们看到了对吉布斯采样和拒绝采样都不利的互补例子。对于拒绝采样,罕见事件是困难的。对于吉布斯采样,高度相关的变量是困难的。坏消息是,在大多数现实世界问题中,两者都可能为真,因此对两种采样来说都可能很困难。但了解问题困难的原因是有帮助的。

吉布斯采样是 MCMC 算法的一个例子。还有更通用的 MCMC 算法,如 Metropolis-Hastings,它使用提议分布来更智能地引导搜索。关于马尔可夫链及其运行速度有一些漂亮的理论,与实践中的混合时间有关。在实践中,吉布斯采样相当常用,因为它相对简单有效。唯一更简单的是拒绝采样,但由于命中证据的概率通常很低,它一般不被使用。但吉布斯采样也可能相当慢。


现在我将转换话题,讨论条件独立性。这与之前不同。到目前为止,我们专注于贝叶斯网络中的概率推断算法,它们大多与贝叶斯网络的结构无关。在拒绝采样中,你只是采样所有变量然后拒绝,不关心依赖关系。在吉布斯采样中,我们稍微关注了结构,定义了马尔可夫毯。但贝叶斯网络中有一些非常有趣的深层结构,让我们尝试探索一下。

贝叶斯网络同时是一个概率对象(一组变量上的分布)和一个组合对象(一个图)。图的属性和概率属性之间存在联系,特别是在我们谈论独立性时。

回顾一下,两个随机变量独立,当且仅当对于 A 和 B 的所有可能值,P(A, B) = P(A) * P(B)。

让我们看一些贝叶斯网络中变量独立性的例子:

  1. 最简单的网络:两个不连接的变量 A 和 B。联合概率就是 P(A) * P(B)。A 和 B 是独立的。独立性对应于图中两个未连接的节点。
  2. 链式结构:A -> B。联合概率是 P(A) * P(B|A)。A 和 B 不独立。它们是连接的。
  3. 共同效应结构(V 型结构):A -> C <- B。A 和 B 是独立的吗?通过计算边缘分布 P(A, B),并利用对 C 的求和使得 P(C|A,B) 的和为 1,可以证明 P(A, B) = P(A) * P(B)。因此,A 和 B 实际上是独立的。这是一个需要注意的特殊情况:两个独立的原因,其共同效应不会改变原因之间的独立性。
  4. 共同原因结构:C -> A, C -> B。A 和 B 独立吗?不独立。联合分布是 P(C) * P(A|C) * P(B|C),无法简化为 P(A) * P(B)。方向性很重要。

现在来看条件独立性。我们说两个变量 A 和 B 在给定 C 时条件独立,如果 P(A, B | C) = P(A | C) * P(B | C)。

让我们重新审视之前的例子:

  • 在共同原因结构(例4)中,A 和 B 在给定 C 时是条件独立的,因为 P(A, B | C) = P(A|C) * P(B|C)。
  • 在共同效应结构(例3)中,A 和 B 在给定 C 时是条件独立的吗?不独立。给定 C 后,A 和 B 通过 C 耦合在一起,不再是独立的。
  • 在警报例子中,B 和 E 是独立的。但给定 A=1 时,B 和 E 不是条件独立的,这就产生了“解释远离”效应。

一般来说,如何判断一个大图中两个变量是否在给定某些证据下条件独立?有一个通用的图准则(D-分离):

  1. 将条件变量(证据)对应的节点涂黑。
  2. 递归移除任何未涂黑的叶节点(这处理了 V 型结构中边际独立但路径存在的情况)。
  3. 将任何拥有共同子节点的父节点连接起来(“结婚”父节点)。
  4. 最后,判断在修改后的图中,A 和 B 之间是否存在一条不经过任何涂黑节点的路径。如果存在,则不是条件独立;如果不存在,则是条件独立。

我们可以用医疗诊断的例子(感冒 C、过敏 A、咳嗽 H、眼睛发痒 I)快速练习一下。例如,C 和 A 独立吗?是的,因为没有条件,移除未涂黑的叶节点后,C 和 A 之间没有路径。C 和 I 在给定 A 时独立吗?给定 A 后,路径被阻断,所以是独立的。


本节课我们一起学习了:

  1. 概率推断:在贝叶斯网络这个“数据库”上回答查询的能力。
  2. 精确推断:通过形成联合分布并进行边缘化和条件化来实现,其复杂度可能随贝叶斯网络节点数指数增长。
  3. 近似推断方法
    • 拒绝采样:简单,但在证据概率低时效率低下。
    • 吉布斯采样:一种马尔可夫链蒙特卡洛方法,通过逐步更新变量进行采样,能处理罕见证据,但在变量高度相关时可能陷入困境。
  4. 效率优化:利用马尔可夫毯(一个节点的父节点和子节点)可以显著提高吉布斯采样的计算效率。
  5. 条件独立性:评估两个变量在给定证据下是否独立,可以归结为图的属性(如 D-分离),判断两个变量在处理后的图中是否连通。

到目前为止,我们假设贝叶斯网络是给定的,并回答相关问题。下一次课,我们将讨论如何实际学习贝叶斯网络的参数,即如何得到这些概率表。

在本节课中,我们将学习贝叶斯网络的参数学习。我们将从回顾贝叶斯网络和概率推断的基础知识开始,然后深入探讨如何从数据中学习模型的参数。课程将涵盖完全可观测和部分可观测两种场景,并介绍最大似然估计、拉普拉斯平滑以及期望最大化算法。

贝叶斯网络是一种定义在一组随机变量上的联合概率分布的方法。你可以将其视为一个数据库,其中存储了你对世界的认知。

具体来说,首先定义一组随机变量。例如,在“警报”例子中,我们有三个变量:B(入室盗窃)、E(地震)和A(警报)。
然后,在这些变量上定义一个有向无环图,连接你认为相互关联的变量,通常表示因果关系。
接着,为图中的每一个节点(而非每一条边)定义一个局部条件概率分布P(X_i | Parents(X_i))










在我们的例子中,我们有:

  • P(B):入室盗窃的先验概率。
  • P(E):地震的先验概率。
  • P(A | B, E):在已知BE的情况下,警报响起的条件概率。

每个局部条件分布通常表示为一个表格或张量。最后,将所有局部条件概率相乘,就得到了所有变量的联合分布:
P(B, E, A) = P(B) * P(E) * P(A | B, E)



上一节我们介绍了贝叶斯网络如何表示联合分布。本节中,我们来看看如何利用这个“数据库”进行查询,即概率推断。例如,我们可以计算在警报响起的情况下发生入室盗窃的概率:P(B=1 | A=1)

我们曾讨论过三种推断算法:

  1. 精确推断:直接操作概率表,通过选择证据、边缘化无关变量并归一化来计算后验概率。
  2. 拒绝采样:一个随机近似算法,根据联合分布生成样本,然后丢弃不满足证据条件的样本,用剩余样本估计概率。
  3. 吉布斯采样:另一个随机近似算法,从一组完整的变量赋值开始,然后迭代地根据其他变量的当前值更新每个变量。

理解变量间的条件独立性对于高效推断和分析模型至关重要。两个变量AB在给定C时条件独立,当且仅当AB之间的所有路径都被C中的节点“阻塞”。路径阻塞遵循“d-分离”准则:

  • 顺连 A -> C -> B:若C被观测,则路径阻塞。
  • 分连 A <- C -> B:若C被观测,则路径阻塞。
  • 汇连 A -> Z <- B:若Z或其任何后代未被观测,则路径阻塞;若Z或其后代被观测,则路径畅通

条件独立性意味着在给定某些证据后,部分变量可以独立处理,这能极大简化计算。

前面我们假设概率参数是已知的。现在我们来探讨一个更根本的问题:这些参数从何而来?一个自然而系统的方法是从数据中学习这些参数。

首先,我们考虑完全可观测的场景,即训练数据中的每个样本都包含了所有变量的赋值。学习的目标是估计所有局部条件概率分布中的参数(即那些概率表格中的数字)。

其核心思想异常简单:计数然后归一化。让我们通过几个逐步复杂的例子来理解这个过程。

假设我们想对电影评分R(取值1-5)建模。这是最简单的贝叶斯网络,只有一个节点。

  • 参数P(R=1), P(R=2), ..., P(R=5)
  • 训练数据:一系列评分,如 [1, 3, 4, 4, 4, 5, ...]
  • 学习:统计每个评分出现的次数,然后归一化(每个计数除以总样本数)。
    GPT plus 代充 只需 145# 例如,计数后得到 count = {1: 10, 2: 5, 3: 20, 4: 30, 5: 35} total = sum(count.values()) P_R = {rating: count[rating]/total for rating in count} 

现在增加电影类型G(戏剧或喜剧),并假设评分R依赖于类型G。网络结构为 G -> R

  • 联合分布P(G, R) = P(G) * P(R | G)
  • 训练数据:样本为(G, R)对,如 (戏剧, 5), (喜剧, 1), ...
  • 学习
    1. 估计P(G):统计每种类型出现的次数并归一化。
    2. 估计P(R | G):对于G每一个取值,统计在该类型下每个评分出现的次数,然后分别归一化。
      • 例如,对于G=戏剧,统计所有G=戏剧的样本中R的分布。

当网络规模变大时,例如有1000个用户U1...U1000都对电影评分,且评分都依赖于类型G。如果为每个用户都学习一个独立的P(R_i | G),数据可能不足。

参数共享是一种解决方案:让所有用户共享同一个条件概率分布 P(R | G)。在模型表示上,这意味着多个节点(R1, R2, ...)由同一个参数集(P(R | G))驱动。

  • 学习:计数时,所有用户的数据都贡献到同一个P(R | G)的计数表中。这相当于增加了估计共享参数的数据量。

对于任意结构的贝叶斯网络(包含参数共享),在完全可观测情况下的参数学习可以总结为以下伪代码:

def learn_parameters(data, network_structure): counts = {} # 字典,键为(参数名,父节点取值,节点取值) for example in data: for variable in network_structure: param_name = get_parameter_name(variable, network_structure) parent_values = get_parent_values(example, variable, network_structure) node_value = example[variable] key = (param_name, tuple(parent_values), node_value) counts[key] = counts.get(key, 0) + 1 parameters = {} for param_name in all_param_names: for parent_val in all_parent_vals_for_param: # 归一化:对给定的参数名和父节点取值,归一化不同节点取值的计数 total = sum(counts for ...) for node_val in all_node_vals: parameters[(param_name, parent_val, node_val)] = counts[...] / total return parameters 

这个算法本质上是为每个局部条件分布(由参数名和父节点取值唯一确定)独立地执行“计数-归一化”。

“计数-归一化”这个直观方法背后有坚实的理论支撑——最大似然估计。其目标是找到一组参数θ,使得观测到的数据D似然 P(D | θ) 最大化。
在完全可观测的贝叶斯网络下,可以证明,最大似然估计的闭式解正是“计数-归一化”。这避免了复杂的梯度下降等迭代优化过程。



最大似然估计在数据稀疏时可能产生问题。例如,如果评分数据中从未出现2分,最大似然估计会认为P(R=2)=0,这过于绝对,可能只是数据不足导致的过拟合

拉普拉斯平滑是一种简单的正则化技术:在开始计数之前,为每个可能事件的计数加上一个伪计数λ(通常是一个小正数,如1)。

  • 操作平滑后计数 = 观测计数 + λ
  • 效果
    • 避免了零概率,使分布更平滑。
    • λ=0时,退化为最大似然估计。
    • λ非常大时,趋向于均匀分布。
    • 随着数据量增加,平滑的影响逐渐减小。

到目前为止,我们假设数据是“完全标注”的。但在现实中,数据常常是部分可观测的,即某些变量(尤其是隐变量)的值是缺失的。例如,在电影评分数据中,我们可能只知道用户评分,而不知道电影类型G

此时,我们无法直接对缺失的变量进行计数。期望最大化算法 是解决此类问题的经典方法。它是一种迭代算法,包含两个步骤:

  1. E步(期望步):基于当前参数估计,计算每个数据样本中缺失变量的后验概率分布 P(缺失变量 | 观测变量,当前参数)。这相当于为缺失的变量生成一个“软”的、加权的赋值。例如,对于一个评分(1,1),EM可能计算得出P(G=戏剧)=0.69, P(G=喜剧)=0.31
  2. M步(最大化步):将E步得到的加权完整数据(每个可能补全的样本都带有其概率权重)视为新的训练数据。然后,在这个加权数据上执行完全可观测情况下的参数学习(即加权版的“计数-归一化”),更新参数。

EM算法流程

GPT plus 代充 只需 145初始化参数 θ 重复直到收敛: # E步 加权数据 = [] for 每个部分观测样本 in 数据: 计算 P(隐变量 | 观测变量, θ) # 推断 for 隐变量的每个可能取值: 创建一个“完整”样本(观测值+该隐变量值) 权重 = 该取值的后验概率 将(完整样本, 权重)加入加权数据 # M步 θ = 基于加权数据,进行“计数-归一化”(计数时乘以权重) 

EM算法每次迭代都能保证增加数据的似然(或保持不变),最终收敛到一个局部最优解。需要注意的是,结果对初始参数敏感,且对于像聚类标签这样的隐变量,其具体标识(如哪类是“戏剧”,哪类是“喜剧”)可能无法恢复,只能恢复出聚类的结构。

本节课我们一起学习了贝叶斯网络的参数学习。

  • 我们首先回顾了贝叶斯网络作为表示联合分布的工具,以及概率推断和条件独立性的概念。
  • 完全可观测设定下,参数学习的核心是最大似然估计,其闭式解是直观的“计数-归一化”方法。我们还讨论了参数共享如何帮助在数据有限时学习更稳健的模型。
  • 为了防止数据稀疏导致的过拟合,我们引入了拉普拉斯平滑技术,通过添加伪计数来得到更合理的概率估计。
  • 对于部分可观测数据(含有隐变量),我们介绍了强大的期望最大化算法。EM通过交替执行E步(基于当前模型推断隐变量分布)和M步(基于加权完整数据更新模型参数),迭代地学习模型参数。

通过学习这些技术,我们不仅能够构建贝叶斯网络,还能从实际数据中自动学习其参数,使其成为对现实世界进行概率建模和推理的完整工具。

在本节课中,我们将学习逻辑推理,这是本课程最后一个技术性主题。我们将从一个新的视角来审视逻辑,重点关注命题逻辑和谓词逻辑。逻辑推理比概率推理更基础,因为它不处理不确定性,但这种简化允许我们进行更复杂的推理。

本节课我们将学习逻辑作为一种语言,它由语法、语义和推理规则三部分构成。我们将深入探讨命题逻辑,理解模型、解释函数、知识库以及蕴含、矛盾和偶然性等核心概念。最后,我们将看到如何将这些概念应用于知识库的“询问”和“告知”操作,并了解逻辑推理与概率推理的联系。

上一节我们介绍了逻辑的总体框架。本节中,我们来看看命题逻辑的语法,它定义了哪些表达式是有效的公式。

在命题逻辑中,我们从定义一组命题符号开始,这些也称为原子公式。它们可以是任何标识符,例如 PQrainwet,它们只是符号,目前不赋予任何含义。

接下来,我们引入一组逻辑连接词¬(非)、(与)、(或)、(蕴含)和 (双向蕴含/等价)。

如果 FG 是任何命题公式,那么以下也是命题公式:

  • ¬F
  • F ∧ G
  • F ∨ G
  • F ⇒ G
  • F ⇔ G

除此之外,没有其他东西是公式。公式集合是递归定义的。

以下是有效的公式示例:

  • P
  • ¬P
  • ¬P ∨ Q
  • P ⇒ Q
  • ¬(P ∧ Q)

以下不是命题逻辑中的有效公式:

  • P Q (缺少连接词)
  • P + Q+ 不是有效的连接词)
  • (P) (命题逻辑中通常不需要括号,但某些表示法中允许用于分组)

在代码中,我们可以这样表示:

# 公式可以是原子符号(字符串)或由连接词构成的复合结构 # 例如:('and', 'rain', 'wet') 表示 rain ∧ wet # ('implies', 'rain', 'wet') 表示 rain ⇒ wet 

现在我们已经知道了哪些是有效的公式。接下来,我们需要理解这些公式的含义,这就是语义部分。

首先引入模型的概念。在逻辑中,一个模型代表世界的一种可能状态。在命题逻辑中,模型 W 是对所有命题符号的真值赋值。

例如,对于命题符号 {A, B, C},一个可能的模型是 {A: True, B: False, C: True}。所有可能的模型构成了所有可能世界状态的集合。

解释函数 I(F, W) 连接了语法(公式 F)和语义(模型 W)。它接收一个公式和一个模型,返回该公式在该模型下为真(True)还是为假(False)。其定义是递归的:

  • 对于原子公式 PI(P, W) = W[P](即查找模型中 P 的真值)。
  • 对于复合公式:
    • I(¬F, W) = not I(F, W)
    • I(F ∧ G, W) = I(F, W) and I(G, W)
    • I(F ∨ G, W) = I(F, W) or I(G, W)
    • I(F ⇒ G, W) = (not I(F, W)) or I(G, W) (蕴含的逻辑定义)
    • I(F ⇔ G, W) = I(F, W) == I(G, W)

一个更直观的理解方式是考虑公式的模型集合 M(F)M(F) 是所有使 I(F, W) 为真的模型 W 的集合。换句话说,一个公式的语义就是所有使其成立的可能世界的集合。

例如,对于公式 F1 = rain ∨ wet,其模型集合 M(F1) 包含:{rain: T, wet: F}{rain: F, wet: T}{rain: T, wet: T}。对于公式 F2 = rain ∧ wetM(F2) 只包含 {rain: T, wet: T}。可以看到,一个简洁的公式可以代表一个庞大的可能世界集合。

上一节我们定义了单个公式的语义。本节中,我们来看看如何将多个公式组合成知识库,并探讨添加新公式时产生的不同关系。

一个知识库 KB 是一组公式的集合,代表我们已知为真的事实。知识库的语义 M(KB) 是满足 KB 中所有公式的模型集合,即所有可能世界的交集。KB 也可以看作是其所有公式的合取 (F1 ∧ F2 ∧ ... ∧ Fn)

当我们向知识库 KB 添加一个新公式 F 时,新的模型集合是 M(KB) ∩ M(F)。这个交集的大小变化定义了三种关系:

  1. 蕴含:如果 M(KB) ∩ M(F) = M(KB),即添加 F 后模型集合没有缩小,则称 KB 蕴含 F,记作 KB ⊨ F。这意味着在所有与 KB 一致的可能世界中,F 都成立。F 没有提供新信息。
  2. 矛盾:如果 M(KB) ∩ M(F) = ∅,即添加 F 后模型集合为空,则称 KB 矛盾于 F。这意味着 FKB 中的知识无法同时成立。
  3. 偶然性:如果 M(KB) ∩ M(F) 既不是空集,也不等于 M(KB),则称 F 相对于 KB偶然的。这意味着 F 提供了新信息,缩小了可能世界的范围。

注意,KB 矛盾于 F 等价于 KB 蕴含 ¬F

理解了蕴含、矛盾和偶然性后,我们现在可以构建两个核心操作来与知识库交互。

询问操作 ask(KB, F) 向知识库提出一个是非问题。其响应基于 KBF 的关系:

  • 如果 KB ⊨ F(蕴含),则回答 “是”
  • 如果 KB 矛盾于 F,则回答 “否”
  • 如果 F 是偶然的,则回答 “我不知道”

告知操作 tell(KB, F) 向知识库添加一个新事实。其响应同样基于关系:

  • 如果 KB ⊨ F(蕴含),则响应 “我已经知道了”,不更新 KB
  • 如果 KB 矛盾于 F,则响应 “我不相信这个”,拒绝更新 KB
  • 如果 F 是偶然的,则响应 “我学到了新东西”,并将 F 加入 KB

这两个操作的核心都是计算 M(KB)M(KB) ∩ M(F) 的关系。ask 返回一个答案,而 tell 在偶然情况下会实际更新知识库。

我们之前学习了概率推理。现在来看看逻辑推理与贝叶斯网络的联系与区别。

联系

  • 命题逻辑中的命题符号对应贝叶斯网络中的随机变量(二值)。
  • 逻辑中的模型对应贝叶斯网络中的变量赋值(即联合概率表的一行)。
  • 逻辑中的知识库 KB 对应贝叶斯网络中的证据
  • 逻辑中的询问 ask(KB, F) 对应贝叶斯网络中的概率查询 P(F | evidence)

关键区别

  1. 表达能力:在逻辑中,证据和查询可以是任意复杂的公式(如 rain ∨ snow)。在基础贝叶斯网络中,证据通常是简单的变量赋值(如 Rain=True)。逻辑的表达能力更强。
  2. 不确定性:贝叶斯网络处理概率,输出 [0, 1] 之间的数值,概括了“是”、“否”、“不知道”。逻辑是确定性的,输出是绝对的“真”或“假”。概率是逻辑在不确定性下的泛化。

概率 P(F | KB) 可以看作是所有与 KBF 一致的模型(世界)的概率之和,与所有与 KB 一致的模型的概率之和的比值。当概率为 1 或 0 时,就对应逻辑中的“是”或“否”。

之前我们通过枚举所有模型来实现 asktell,这在变量多时效率极低。高效推理的关键在于可满足性问题。

一个知识库 KB可满足的,当且仅当 M(KB) 非空,即存在至少一个模型满足它。

我们可以将蕴含、矛盾和偶然性的判断归结为两次可满足性检查:

  1. 检查 KB ∪ {¬F} 是否可满足。
    • 如果不可满足,则 KB ⊨ F(蕴含)。
    • 如果可满足,则进行第二步。
  2. 检查 KB ∪ {F} 是否可满足。
    • 如果不可满足,则 KB 矛盾于 F
    • 如果可满足,则 F 是偶然的。

这样,我们就把问题转化成了可满足性问题。存在高效的可满足性求解器(如 Z3),即使问题在理论上是 NP 完全的,也能在实践中处理成千上万个变量。

到目前为止,我们通过语义(模型)来定义真值。但在人类推理中,我们常常直接操作符号进行推导,例如数学证明。这就是推理规则的作用。

推理规则是语法层面的转换规则。它从一组前提公式 {F1, ..., Fn} 推导出一个结论公式 G,记作 F1, ..., Fn ⊢ G

一个经典的规则是肯定前件P, P ⇒ Q ⊢ Q

给定一组推理规则和一个初始知识库 KB,我们可以反复应用规则,将推导出的新公式加入 KB,直到没有新公式产生。如果公式 F 最终被加入 KB,则称 KB 证明F,记作 KB ⊢ F

这就引出了两个连接语法和语义的核心概念:

  • 可靠性:如果 KB ⊢ F,则 KB ⊨ F。即所有能证明的都是真的(不会推出错误结论)。这保证了推理的正确性。
  • 完备性:如果 KB ⊨ F,则 KB ⊢ F。即所有真的都能被证明。这保证了推理的能力足够强。

理想情况是既可靠又完备。肯定前件规则是可靠的。一个不可靠规则的例子是:Q, P ⇒ Q ⊢ P(肯定后件),这不是有效的逻辑推理。

本节课我们一起学习了逻辑推理的基础,重点关注了命题逻辑。

  • 我们首先将逻辑视为一种语言,由语法(有效公式)、语义(公式含义,通过模型和解释函数定义)和推理规则构成。
  • 我们定义了知识库,并学习了向知识库添加新公式时产生的三种关系:蕴含矛盾偶然性
  • 基于这些关系,我们实现了知识库的 ask(询问)tell(告知) 操作。
  • 我们探讨了逻辑推理与贝叶斯网络的概率推理之间的联系与区别。
  • 为了高效推理,我们将问题归结为可满足性检查,并可以利用高效的求解器。
  • 最后,我们介绍了在语法层面进行推导的推理规则,以及衡量规则质量的可靠性完备性概念。

这些概念是逻辑学的基础,下一节课我们将把它们推广到更强大的一阶逻辑中。

在本节课中,我们将学习一阶逻辑。一阶逻辑比命题逻辑更强大,它允许我们表示关于对象及其关系的复杂知识,并进行推理。我们将介绍其语法、语义和推理规则,并通过实例展示如何将自然语言翻译成一阶逻辑表达式。

上一节我们介绍了命题逻辑,它使用命题符号和逻辑连接词来表示知识。本节中,我们将看到命题逻辑的局限性,并引入更强大的一阶逻辑。一阶逻辑引入了对象谓词函数量词,使我们能够更简洁、更自然地表示关于世界的陈述。

让我们尝试用命题逻辑表示一些事实,看看其局限性。

  • 事实1:Alice和Bob都懂算术。
    • 命题逻辑表示AliceKnowsArithmetic ∧ BobKnowsArithmetic
    • 这看起来没问题。
  • 事实2:所有学生都懂算术。
    • 命题逻辑表示(AliceIsStudent → AliceKnowsArithmetic) ∧ (BobIsStudent → BobKnowsArithmetic) ∧ ...
    • 问题出现了:如果有1000个学生,就需要写一个非常长的公式。这不够简洁。
  • 事实3:每个大于2的偶数都是两个素数之和(哥德巴赫猜想)。
    • 在命题逻辑中,我们需要为每个可能的整数创建一个命题符号,这显然不可行。

命题逻辑缺少的是对象谓词量词。它就像编程中没有循环,必须枚举所有情况。一阶逻辑通过引入这些概念解决了这个问题。

一阶逻辑的语法定义了哪些是有效的公式。与命题逻辑不同,一阶逻辑区分表示对象的和表示真值的公式

项表示对象。有三种类型的项:

  1. 常量:如 AliceArithmetic。它们表示具体的对象。
  2. 变量:如 xy。它们可以代表任何对象。
  3. 函数:函数将项映射到新的项。例如:
    • father(Alice) 是一个项(表示Alice的父亲)。
    • add(x, y) 是一个项(表示x和y的和)。
    • 函数可以嵌套:father(father(Alice))

重要:项表示对象,而不是真值。

公式表示真值。原子公式由谓词应用于项构成。

  • 谓词:将对象映射为真值(True/False)。
    • 零元谓词(命题):Snowing(要么下雪,要么不下雪)。
    • 一元谓词:Student(x)(x是学生)。
    • 二元谓词:Knows(x, y)(x懂y)。

示例

  • Knows(Alice, Arithmetic) 是一个原子公式。
  • Student(x) 是一个原子公式。

有了原子公式,我们可以使用逻辑连接词(, , ¬, , )组合它们,形成更复杂的公式。例如:Student(x) → Knows(x, Arithmetic)

最后,我们可以使用量词

  • 全称量词 ∀x (Student(x) → Knows(x, Arithmetic)) 表示“所有学生都懂算术”。
  • 存在量词 ∃x (Student(x) ∧ Knows(x, Arithmetic)) 表示“存在一个懂算术的学生”。

语法检查(常见错误):

  • father(x),不是公式。
  • Knows(Student, Arithmetic) 无效,因为 Student 是谓词,不是项(对象)。
  • Student(Knows(Alice, Arithmetic)) 无效,因为 Knows(...) 返回真值,不能作为谓词的参数(需要对象)。

命名约定:通常用小写字母表示项和函数,用大写字母表示谓词。

语义定义了公式在特定世界(模型)中的含义。在命题逻辑中,模型是对命题符号的真值赋值。在一阶逻辑中,模型更为复杂。

一个一阶逻辑模型 M 由两部分组成:

  1. 域 D:一个非空对象的集合(例如,{o1, o2, o3})。
  2. 解释 I:将语法符号映射到域中的元素或关系。
    • 常量:映射到域中的特定对象。例如,I(Alice) = o1, I(Arithmetic) = o3
    • 函数:映射到域上的函数。例如,I(father) 是一个函数,使得 I(father)(o1) = o2(o1的父亲是o2)。
    • 谓词:映射到域上的关系(真值函数)。例如,I(Student) = {o1: True, o2: False, o3: False}I(Knows) = {(o1, o3): True, (o2, o3): False}

可以将模型想象成一个知识图谱:节点是对象,常量是节点标签,一元谓词是节点属性,二元谓词是节点间的边。

给定一个模型 M = (D, I),解释函数 [[]] 递归地计算任何公式或项在该模型下的值。

  • [[Alice]]^M = I(Alice) = o1[[father(Alice)]]^M = I(father)([[Alice]]^M) = I(father)(o1) = o2
  • 原子公式[[Knows(Alice, Arithmetic)]]^M = I(Knows)([[Alice]]^M, [[Arithmetic]]^M) = I(Knows)(o1, o3) = True
  • 量词公式
    • ∀x P(x) 为真,当且仅当对域 D 中的每一个对象 dP(d) 都为真。
    • ∃x P(x) 为真,当且仅当在域 D 中至少存在一个对象 d,使得 P(d) 为真。
  • 连接词:与命题逻辑相同(递归计算子公式的真值)。

我们的目标仍然是实现 AskTell 函数。这可以归结为检查可满足性(SAT)。对于一阶逻辑,有几种推理方法。

如果知识库满足以下两个强假设,则可以将其转换为命题逻辑问题:

  1. 唯一名称假设:每个常量符号指向域中不同的对象。
  2. 域封闭假设:域中的每个对象都有一个常量符号指向它。

如果满足,那么每个形如 P(c) 的原子公式都可以看作一个命题符号。量词可以被展开:

  • ∀x P(x) 变为 P(c1) ∧ P(c2) ∧ ... ∧ P(cn)
  • ∃x P(x) 变为 P(c1) ∨ P(c2) ∨ ... ∨ P(cn)

转换后,就可以使用命题逻辑的推理技术(如模型检查)。但这两个假设通常不成立,且如果域无限或函数能生成无限项,则无法命题化。

对于一类特殊的公式——定子句,我们可以使用推广的肯定前件推理规则。

定子句是形如下式的公式:
∀x1...∀xn (A1 ∧ A2 ∧ ... ∧ Ak → B)
其中 AiB 都是原子公式。它表示一个“如果...那么...”的规则,且不含析取()。










示例∀x ∀y ∀z (Student(x) ∧ Takes(x, y) ∧ Covers(y, z) → Knows(x, z))
(如果学生x选修了课程y,且课程y涵盖概念z,那么x懂z。)



推广的肯定前件推理规则

  1. 前提:知识库中有原子公式 A1', A2', ..., Ak'
  2. 前提:知识库中有定子句 ∀x1...∀xn (A1 ∧ A2 ∧ ... ∧ Ak → B)
  3. 步骤:找到一个替换 θ(将变量映射为项),使得对于每个 i,有 Ai' = θ(Ai)。这个过程称为合一
  4. 结论:可以推导出公式 θ(B),并将其加入知识库。

关键概念

  • 替换:对公式中的变量进行“搜索并替换”的操作。例如,对公式 Knows(x, y) 应用替换 {x/Alice, y/Arithmetic},得到 Knows(Alice, Arithmetic)
  • 合一:找到使两个公式(或项)变得相同的替换。例如,合一 Knows(Alice, y)Knows(x, Arithmetic) 得到替换 {x/Alice, y/Arithmetic}

推理示例

  • 知识库包含:
    • Takes(Alice, CS221)
    • Covers(CS221, Logic)
    • ∀x ∀y ∀z (Takes(x, y) ∧ Covers(y, z) → Knows(x, z)) (规则)
  • 推理过程:
    1. 将前提 Takes(Alice, CS221) ∧ Covers(CS221, Logic) 与规则体 Takes(x, y) ∧ Covers(y, z) 进行合一。
    2. 得到替换 θ = {x/Alice, y/CS221, z/Logic}
    3. θ 应用于规则头 Knows(x, z),得到 Knows(Alice, Logic)
    4. 推导出新事实:Knows(Alice, Logic)

性质:肯定前件推理规则是可靠的(推导出的结论都是知识库所蕴含的),但对于一阶逻辑,它不是完备的(有些被蕴含的结论无法用它推导出来,特别是涉及析取时)。存在完备的推理规则(如归结原理),但更为复杂。

将自然语言翻译成一阶逻辑是一项关键技能。以下是一些常见模式:

以下是翻译示例:

  1. Alice和Bob都懂算术
    • Knows(Alice, Arithmetic) ∧ Knows(Bob, Arithmetic)
  2. 所有学生都懂算术
    • ∀x (Student(x) → Knows(x, Arithmetic))
    • 注意:全称量词 通常与蕴含 配对。
  3. 有些学生懂算术
    • ∃x (Student(x) ∧ Knows(x, Arithmetic))
    • 注意:存在量词 通常与合取 配对。
  4. 有一门课每个学生都上过
    • ∃x (Course(x) ∧ ∀y (Student(y) → Takes(y, x)))
  5. 哥德巴赫猜想(简化)
    • ∀x (Even(x) ∧ GreaterThan(x, 2) → ∃y ∃z (Prime(y) ∧ Prime(z) ∧ (Sum(y, z) = x)))
  6. 如果学生选修了一门课,且该课涵盖某个概念,那么该学生懂这个概念
    • ∀x ∀y ∀z (Student(x) ∧ Takes(x, y) ∧ Course(y) ∧ Covers(y, z) ∧ Concept(z) → Knows(x, z))

重要提示:避免 ∀x (Student(x) ∧ Knows(x, Arithmetic))(这声称所有对象都是懂算术的学生)或 ∃x (Student(x) → Knows(x, Arithmetic))(这很容易为真,例如只要有一个不是学生的对象即可)。牢记 ∀→∃∧ 的配对模式。

本节课中我们一起学习了一阶逻辑:

  • 动机:命题逻辑无法简洁表示涉及对象和量化的知识。
  • 语法:引入(对象)、函数谓词量词, )来构建公式。
  • 语义:模型由解释函数定义,解释函数递归地给出了公式在模型下的真值。
  • 推理
    • 在强假设下可命题化为命题逻辑问题。
    • 对于定子句,可使用结合了替换合一肯定前件推理规则进行可靠但不完备的推理。
  • 应用:掌握了将自然语言语句翻译成一阶逻辑表达式的基本模式。

一阶逻辑为表示和推理结构化知识提供了强大的基础。虽然它仍有局限性(例如,难以表达“70%的学生”这样的概率或数量概念,这需要更高阶的逻辑),但它已是人工智能中知识表示的核心工具之一。

在本节课中,我们将要学习语言模型。语言模型是当今人工智能领域的核心,它们驱动着聊天机器人、代码补全等众多应用。我们将探讨语言模型是什么、为何建模语言是一个好主意、使其成功的关键思想,以及当前的发展现状。

上一节我们介绍了课程概述,本节中我们来看看语言模型究竟是什么。

语言模型,顾名思义,是对语言的建模。从我们的目的出发,语言可以被视为结构化的字符序列。这种结构主要来自两个方面:词汇表(语言中可用的基本单元)和语法(这些单元如何组合的规则或惯例)。学习一个语言模型,意味着学习这种语言的结构,以便能够预测或生成符合该语言的序列。

从本质上讲,语言模型是一个对序列进行建模的对象。给定一个文本前缀,它能预测或生成后续的文本。目前最常见的方式是自回归建模,即逐个预测下一个词/标记。

为了更具体地理解,我们可以从张量的角度来看待语言建模。

首先,我们有一个词汇表,它是一个将字符串映射到索引的字典,例如:

GPT plus 代充 只需 145vocab = {“the”: 0, “stock”: 1, “market”: 2, …} 

一个句子如 “the stock market crashed” 可以被表示为索引序列 [0, 1, 2, 3]

接着,通过词嵌入层,每个索引被转换为一个D维的连续向量。因此,一个长度为T的输入序列,其嵌入表示是一个形状为 (T, D) 的矩阵。

语言模型的核心任务是一个多类别分类问题:根据之前的上下文,预测下一个词是词汇表中哪个词的概率最高。模型的输出是词汇表V上的一个概率分布。

更一般地,模型可以在每个位置都进行预测,而不仅仅是最后一个位置。这样,对于一个批次大小为B、序列长度为T的输入,模型会输出一个形状为 (B, T, V) 的张量,表示每个位置上下一个词的概率分布。

从概率角度看,一个理想的语言模型定义了整个序列空间上的一个概率分布 P(sequence)。根据链式法则,这个联合概率可以分解为一系列条件概率的乘积:

P(w1, w2, …, wT) = P(w1) * P(w2|w1) * P(w3|w1, w2) * … * P(wT|w1, w2, …, wT-1)

这意味着,我们只需要一个模型,它能够根据之前的所有词,预测下一个词的概率。这正是自回归语言建模的目标。

目前,下一个词/标记预测是预训练语言模型最主流的目标。另一个历史上有名的目标是掩码语言建模(例如BERT使用的),即预测句子中被遮盖的词,但如今已不如前者常用。

上一节我们定义了语言模型,本节中我们来看看为什么投入巨大资源来建模语言是值得的。

以下是三个主要原因:

  1. 许多任务本质上是语言建模问题:日常生活中的许多任务都可以被形式化为序列补全问题。例如,写邮件、编写代码、回复消息等,都是在给定上下文后生成后续文本。
  2. 实现多任务学习:通过在海量多样化文本数据上训练“下一个词预测”模型,模型被迫学习并记忆其中蕴含的广泛知识,包括事实、数学、逻辑推理等。这使得单一模型能够潜在解决多种任务,而无需为每个任务单独标注数据。GPT-2论文《Language Models are Unsupervised Multitask Learners》阐述了这一思想。
  3. 卓越的扩展性:语言模型在数据量、模型规模和计算量扩大时,性能会持续提升,且没有明显的性能瓶颈。这种“缩放定律”意味着,遵循简单的配方——使用更大的模型、更多的数据和计算——就能持续获得更好的结果。如今,一个统一的巨型模型(如GPT-4)可以替代过去多个专门化的小模型。

上一节我们了解了建模语言的优势,本节中我们来探讨使其成功运作的一些关键思想。

传统的多层感知机(MLP)用于语言建模会面临几个问题:参数量随序列长度和词汇表大小增长过快、缺乏动态权重机制、计算无法有效复用。

Transformer架构(出自论文《Attention Is All You Need》)巧妙地解决了这些问题:

  • 参数共享:其核心组件(如自注意力机制中的Q、K、V投影)在不同序列位置上共享参数,降低了模型对序列长度的敏感度。
  • 动态注意力:自注意力机制允许模型根据输入内容动态地决定关注上下文中的哪些部分,实现了“动态权重”。
  • 计算复用:其结构设计便于缓存中间计算结果,当输入序列只有局部变化时,可以复用大部分已计算的结果,提高了效率。

现代大语言模型的训练通常分为两个阶段:

1. 预训练
目标是在海量互联网文本数据上,使用简单的“下一个词预测”目标,训练一个通用的基础模型。这个阶段的目标是让模型吸收广泛的知识和语言模式。一个关键发现是,当模型规模足够大时,会涌现出上下文学习的能力:只需在输入中给出任务描述和几个示例(即“提示”),模型就能完成新任务,而无需更新其参数。



2. 后训练
预训练得到的基础模型虽然知识丰富,但行为像是一个“加强版的自动补全”,不一定有用或安全。后训练旨在使模型更符合人类需求,主要包括:



  • 指令微调:在指令-回答格式的数据集上进一步训练,使模型学会遵循指令。
  • 基于人类反馈的强化学习:收集人类对模型生成结果的偏好数据,训练一个奖励模型,然后用强化学习(如PPO算法)优化语言模型,使其生成更受人类偏好的内容。这项技术对于打造像ChatGPT这样有用且无害的对话模型至关重要。
  • 分词:由于无法将所有单词都纳入词汇表,现代语言模型使用子词分词器(如Byte-Pair Encoding)。它将单词拆分为更常见的子单元,既能处理常见词,也能处理罕见词或拼写错误。
  • 系统工程:训练和部署千亿参数模型需要复杂的系统工程,包括模型并行(将模型拆分到多个GPU)、数据并行量化(用更低精度表示权重以节省内存)以及内核融合(如Flash Attention)等技术来优化计算和内存使用。

上一节我们探讨了语言模型成功的关键,本节中我们来看看当前领域的格局。

如今,“语言模型”通常特指大语言模型。它们的影响已超越自然语言处理,被应用于机器人(将感知和动作视为特殊标记)、多模态理解等领域。

从开发和组织模式看,主要分为三类:

  1. 前沿闭源模型:由OpenAI、Anthropic等公司开发,通过API提供服务。它们通常性能最强,但训练细节、数据和算法不公开,存在所谓的“黑箱”。
  2. 开源权重模型:由Meta(Llama)、阿里(Qwen)等公司发布模型权重,公众可下载、研究、微调和部署。虽然训练细节可能不完全透明,但开放权重促进了研究和应用创新,且性能正在快速追赶闭源模型。
  3. 完全开源模型:由学术机构或开源社区主导,公开训练数据、算法、代码和权重。这类模型通常规模较小,但对于理解模型原理、进行可复现研究至关重要。

与此同时,大语言模型能力的飞速提升也引发了关于AI安全伦理社会影响监管的广泛关注与讨论。

本节课中我们一起学习了语言模型的核心概念。我们首先明确了语言模型是对序列概率分布进行建模的对象,通常通过自回归的下一个词预测来实现。接着,我们探讨了建模语言的三大优势:任务通用性、多任务学习能力和卓越的扩展性。然后,我们深入分析了使现代大语言模型成功的关键,包括Transformer架构、预训练与后训练的两阶段范式、分词技术以及系统工程。最后,我们概述了当前语言模型领域由闭源前沿模型、开源权重模型和完全开源模型构成的生态格局及其带来的机遇与挑战。理解这些基础,是进一步探索和应用人工智能这一强大工具的重要起点。

在本节课中,我们将探讨人工智能在社会中的角色。我们将从技术细节转向更广泛的社会影响,理解为什么作为技术开发者,我们需要关注并思考AI如何塑造我们的世界。


上一节我们介绍了AI的技术基础,本节中我们来看看为什么需要关注其社会影响。这主要有两个原因。

首先,技术对社会有着巨大的影响。从历史上的印刷术、蒸汽机,到近期的互联网、手机和社交网络,技术不断重塑社会结构。人工智能是历史上发展最快的技术之一,其增长部分得益于互联网和社交媒体等现有基础设施。例如,ChatGPT目前拥有8亿周活跃用户,且这一数字仍在增长。我们正处于这场技术革命的初期阶段。

其次,作为技术开发者,我们拥有巨大的影响力。我们比任何人都更了解这项技术的能力和局限。我们可以选择要解决的问题,并在构建系统时做出影响其运作方式和可及性的设计决策。例如,构建模型时,我们需要决定支持哪些语言、是否发布模型权重、接受或拒绝哪些服务请求。这些并非纯粹的技术问题,而是具有深远社会影响的设计决策。


既然我们关心技术的社会影响,那么下一步该怎么做?一个广泛的原则是:我们希望确保AI的发展能够造福社会,并尽可能减少危害。这听起来像是一句陈词滥调,但实践起来却充满挑战。

主要问题在于,我们无法完全控制AI的使用方式。AI是一种典型的“双重用途”技术,既能用于造福,也能用于伤害。双重用途技术并非AI独有,例如:

  • :可用于农业肥料,也可用于制造化学武器。
  • 火箭:可用于发射导弹,也可用于太空探索。
  • 核能:可用于发电,也可用于制造武器。
  • 网络安全工具:可用于渗透测试以加固系统,也可用于发动网络攻击。
  • 加密技术:可用于保护隐私,也可用于掩盖犯罪活动。

AI同样如此。但这并不意味着我们只能袖手旁观。我们可以采取措施,引导AI技术向有益的方向倾斜。

我们可以通过一个二维框架来思考AI的社会影响:意图(好/坏)和影响(积极/消极)。

  • 有益应用:意图好,影响积极。例如医疗保健、教育、科学发现。
  • 滥用:意图坏,影响消极。例如垃圾邮件、欺诈、网络攻击。
  • 意外后果:意图好,但影响消极。这是更常见且微妙的情况,我们稍后会详细讨论。
  • 坏意图好结果:理论上存在,但现实中罕见。

我们通常只关注AI模型本身,例如它是否能生成正确答案。但这远远不够。要理解AI如何影响社会,我们需要采取生态系统视角。

想象一个AI系统,它通过上游下游与世界互动。

上游指的是AI系统的构建过程。对于大型语言模型,这包括:

  • 数据:来自互联网,本质上是人们劳动的产物。
  • 计算资源:来自能源消耗和材料提取,用于建造数据中心和GPU。

上游的考量包括:

  • 隐私:人们的个人信息可能被无意中泄露。
  • 版权:创作者可能未得到适当补偿。
  • 劳动实践:为AI标注数据的工作人员可能待遇不佳。
  • 环境影响:大规模数据中心带来的碳排放、水资源消耗和资源开采。

下游指的是AI系统的使用过程。AI被人们使用,可能产生积极或消极的影响,包括:

  • 不平等:AI对某些群体的帮助大于其他群体。
  • 生成有害内容或采取有害行动
  • 过度依赖:人们可能失去批判性思维能力。
  • 就业影响:AI可能取代某些工作岗位。

在接下来的内容中,我们将深入探讨几个具体话题。


不平等是AI系统可能加剧的一个严重问题。2018年的一项经典研究(Gender Shades项目)评估了微软和IBM的人脸识别系统在不同人口统计群体(按肤色和性别划分)上的准确率。研究发现,对于肤色较深的女性群体,系统的准确率显著低于其他群体。如果只看平均准确率,我们会认为系统表现良好,从而忽略了这一特定群体受到的不公平对待。

这项研究发布后,相关系统得到了修复。这凸显了第三方审计的力量,它能激励公司解决问题。解决问题的第一步是发现问题。

以下是减少不平等的技术方法:

  • 收集更多数据:为代表性不足的群体收集更多数据,但这通常成本高昂。
  • 算法调整:对数据中代表性不足的群体进行上采样。
  • 分布鲁棒优化:优化目标不是平均准确率,而是所有群体中最差的准确率。其公式可以表示为:
    最大化 min_{群体g} 准确率(g)



另一种不平等体现在全球层面。一项研究使用基于Llama微调的奖励模型(用于评估AI助手回复的质量)来评估不同国家用户的输入。结果发现,该模型给来自美国和加拿大的输入打分很高,而给来自沙特阿拉伯等地的输入打分很低。如果使用这种有偏见的奖励模型来训练语言模型,将会导致严重的偏见。

更微妙的不平等来自伪相关。例如,一个用于从X光片预测气胸(肺部萎缩)的模型,在训练数据中发现“胸部引流管”(治疗气胸的常见方法)与“气胸”高度相关。于是,模型学会了通过检测引流管来预测气胸,而不是真正识别疾病本身。这导致了对未接受治疗(即没有引流管)的患者预测能力很差,而这类患者恰恰是最需要被正确诊断的。伪相关常常对少数群体影响最大。

关键启示:不能只关注一个总体指标(如90%的准确率)。必须监控不同群体上的指标,以确保没有损害特定子群体。


对齐问题关乎如何让AI系统做我们真正想让它做的事。听起来简单,实则不然。从强化学习的角度看,我们会定义一个奖励函数来捕获我们的价值观,然后训练智能体最大化期望奖励。

那么,哪里可能出错呢?

1. 奖励函数难以定义
奖励函数很难精确指定所有情况。如果定义不当,就会导致奖励黑客攻击。例如,在一个名为《海岸赛手》的划船游戏中,奖励是撞到物体得分。一个强化学习智能体学会的策略不是完成比赛,而是不停地绕圈撞击一个浮标来刷分。这违背了开发者的本意(“按我的意思做,而不是按我说的做”),但算法只能按你说的做。



在更现实的场景中,比如代码生成模型,一个自然的奖励函数是“代码通过单元测试”。但通过测试并不等同于代码正确、安全、高效或风格良好。过度优化一个不完美的奖励函数会导致系统钻空子。

2. 价值观的多元性
奖励函数代表价值观,但问题是:谁的价值观? 不同的人有不同的价值观。例如,对于政府是否应该监管社交媒体内容,人们意见不一。如果只根据一种观点来微调语言模型并推广给全世界,就是将这种观点强加于人。理想情况下,模型应该体现思想的多样性(当然是在合理范围内),并且能够个性化。但这需要在“体现多样性”和“过度个性化导致信息茧房”之间取得平衡。



3. 可扩展的监督
语言模型越来越强大,能够解决极其复杂的问题,其生成的解决方案甚至让专家都难以验证。例如,有一个项目让语言模型回答Stack Exchange上未解决的问题,但很难判断这些答案是否正确。



以下是解决可扩展监督的一些思路:

  • 问题分解:将大问题分解为人类可以验证的小问题。
  • AI监督AI:使用另一个AI来监督第一个AI(例如辩论、宪法AI),但这有递归问题。
  • 过程监督:要求模型展示推理步骤(思维链),然后检查这些步骤,这比只看最终答案更有效。
  • 形式化验证:对于能转化为定理证明的问题很有效,但大多数现实世界问题过于复杂。

总结对齐的挑战

  • 奖励函数不准确导致奖励黑客攻击。
  • 不存在单一的“正确”奖励函数,需要多元思维。
  • 人类很难提供反馈或写下奖励函数,需要可扩展的监督方案。

版权问题涉及语言模型训练数据的上游依赖。目前AI领域有许多围绕版权的法律诉讼。

版权为何存在?
版权是知识产权法的一部分,旨在激励知识产品的创造。通过保护创作者,激励人们进行创作。在美国,版权适用于“以任何有形媒介固定的原创作品”。其门槛极低——你的网站、作业、写的文章都自动享有版权。但需要注册后才能起诉他人侵权,版权有效期为创作者去世后70年(或作品发表后95年),之后进入公共领域。



如何使用受版权保护的作品?
有两种方式:获取许可,或诉诸合理使用原则。



  • 许可:例如知识共享许可,允许创作者自由分发作品(如维基百科、可汗学院)。许多模型开发者也会付费获取数据许可(如Google付费给Reddit)。
  • 合理使用:根据美国版权法第107条,需考虑四个因素:
    1. 使用的目的和性质(是否具有转化性、是否商业用途)。
    2. 受版权保护作品的性质(事实性作品比虚构作品更可能构成合理使用)。
    3. 所使用的部分占整个作品的比例。
    4. 使用对作品潜在市场或价值的影响。

对AI模型意味着什么?

  • 训练模型本身可能涉及复制数据,除非符合合理使用。
  • 有观点认为,训练机器学习模型是转化性使用,模型能做的事情与原始数据不同。而且,模型关注的是“思想”(如识别停车标志的概念),而非具体的“表达”(某张停车标志图片的艺术风格)。
  • 但模型可能影响市场,例如AI生成内容可能与艺术家竞争。
  • 即使数据本身可以合理使用,网站的服务条款也可能禁止大规模抓取。

一个微妙之处:记忆与提取
虽然模型训练是转化性的,但研究表明模型可能会记忆训练数据。例如,Llama 3 70B模型对《哈利·波特》等书籍表现出高度记忆。更关键的是提取:普通用户能否从模型权重中提取出原文?实验表明,用“Mr. and Mrs. D…”提示Llama 3 70B,它能生成大量《哈利·波特》的原文。这强化了侵权的论点。不过,这种情况是例外而非普遍规律,取决于具体模型和作品。




我们需要思考的不仅是模型能做什么,还包括模型是如何构建的——即元层面。这关乎谁可以决定模型的行为,甚至谁有能力构建模型。一个风险是权力集中化,目前只有少数资本雄厚的大公司能构建前沿模型,且其工作原理很少公开。

透明度是改进的前提。如果我们想让AI系统更安全、危害更小,但不知道它们如何构建、能做什么,就无从下手。有一个项目叫“基础模型透明度指数”,它通过100个指标评估模型开发者的透明度实践,涵盖上游(数据、计算)、模型本身(能力、风险)和下游(分发、使用、反馈)。公开报告可以激励公司提高透明度。

开放性是一个光谱:

  • 封闭模型:仅通过API或产品使用(如GPT-4、Claude)。
  • 开放权重模型:发布模型权重,但不公开数据、代码或训练细节(如Llama、Dbrx、Qwen)。
  • 开源模型:发布权重、代码和数据配方,但开发过程可能不开放。
  • 开放开发模型:完全开放,社区可参与贡献和审计。

开放性的重要性

  • 促进创新和定制:研究人员和开发者可以微调、量化、以各种创造性方式修改模型。
  • 提高透明度:尽管开放权重本身不足以保证全面透明,但它是重要一步。
  • 减少权力集中:人们可以获取并定制模型,而不是由一个中央权威决定所有人的模型行为。

开放性的风险主要与滥用有关。任何人都可以获取开放权重模型,并可能移除安全限制,用于生成虚假信息或发动攻击。在评估风险时,应考虑边际风险——即相对于没有开放模型的世界(但仍有封闭模型和互联网),开放模型带来的额外风险是多少。此外,需要考虑整个危害发生的生态系统(例如,制造生物武器还需要物理步骤,在这些环节设防可能比在模型层面更容易)。


本节课我们一起学习了AI与社会相关的多个重要议题。

首先,我们论证了技术开发者为何需要关心社会影响。AI是双重用途技术,发展迅猛,影响深远,而我们拥有塑造其发展的力量。

其次,我们探讨了如何引导AI向善,包括关注有益应用、防止滥用和减少意外事故。我们引入了意图-影响框架和生态系统视角,强调不能只孤立地看待模型。

接着,我们深入分析了几个核心问题:

  • 不平等:AI可能加剧社会不公,需要通过多维度评估、数据收集和算法公平性技术来缓解。
  • 对齐:让AI按人类意图行事充满挑战,包括定义奖励函数、协调多元价值观和实施可扩展监督。
  • 版权:AI训练数据的版权问题复杂,涉及合理使用、转化性、记忆与提取等法律和技术交叉点。
  • 开放性与透明度:它们是确保问责、促进创新和防止权力过度集中的基础。我们需要在开放带来的益处与潜在滥用风险之间权衡。

总体而言,应对AI的社会影响是困难的,但我们必须尝试。我们需要超越单一模型指标,采用全面的评估体系;需要将透明度和开放性视为基础;需要认识到审计(即系统性的评估和曝光)是推动改进的强大工具。

下一讲,我们将更深入地审视AI生态系统中的各个参与者。Rishi将带来关于AI供应链的客座讲座,进一步拓展这种关注整个生态系统而非单个模型的视角,帮助大家更好地思考AI在社会中的角色。

在本节课中,我们将探讨人工智能的社会影响,特别是其经济层面。我们将从技术本身转向更广阔的生态系统,理解AI如何被构建、分发,并最终影响全球经济。我们将学习如何通过供应链和经济增长理论这两个关键视角来分析AI的经济影响。

上一节我们介绍了思考AI社会影响的必要性。本节中,我们来看看分析AI经济影响的两个核心层面:技术和组织。

当我们思考AI时,通常会关注技术本身:模型、算法、目标函数等。但为了理解其全面的经济影响,我们必须同时考虑构建和使用这些技术的组织。

以下是为什么必须考虑组织层面的三个原因:

  1. 广泛采用:AI作为一种通用技术,其整体经济影响取决于各个经济领域中众多组织的采用行为。
  2. 价值分配:理解技术轨迹本身无法告诉我们哪些具体公司会从AI中受益最多或受损最严重。
  3. 微观决策:许多影响经济的关键决策超越了纯粹的技术范畴。

上一节我们强调了组织的重要性。本节中,我们通过一个具体例子来看看,即使技术能力相似,组织决策如何导致不同的经济影响。

假设在某个基准测试中,谷歌、Anthropic和OpenAI的模型得分相近。这可能会让我们得出结论:这些公司的技术能力大致相同,在经济上可以相互替代。

然而,这种看法忽略了这些公司在技术之外做出的关键决策,这些决策深刻影响了它们在经济中的角色:

  • 发布时间:决定何时将模型推向市场。
  • 定价策略:影响消费者和企业对模型的使用。
  • 产品整合:决定如何将模型垂直整合到下游市场中。
  • 生态合作:决定如何与生态系统中的其他参与者合作。

因此,除了核心技术,这些组织层面的决策共同决定了AI对全球经济的实际影响。

上一节我们看到了组织决策的多样性。本节中,我们引入一个框架来系统性地理解AI从资源到应用的完整链条。

我们可以将AI供应链抽象为一个图结构,主要包含以下环节:

  • 输入资源数据计算是构建模型的两大核心输入。
  • 核心模型:基于输入资源训练出的基础模型。
  • 下游应用:建立在基础模型之上的各类AI系统,供个人或企业使用。

思考供应链时,需要并行考虑两个方面:一是具体的技术资产(如数据集、GPU、API),二是运营这些资产并相互关联的公司实体。

上一节我们概述了AI供应链。本节中,我们首先深入探讨计算供应链,其特点是高度集中和存在关键瓶颈。

对于计算供应链,我们通常的认知可能简化了。它远比“英伟达GPU加数据中心”复杂。以下是三个在计算供应链中占据关键垄断地位的公司:

  1. ASML:一家荷兰公司,在高端光刻技术领域拥有全球垄断地位。光刻是芯片制造的关键步骤。
  2. 台积电:位于台湾,是全球领先的半导体制造公司。它是英伟达等芯片设计公司的关键依赖。
  3. 英伟达:在AI加速芯片设计市场占据主导地位。

这些公司在其各自环节都拥有极高的市场份额,这使得它们对计算供应链的运作至关重要。这种集中化带来了几个影响:

  • 韧性风险:供应链的某个环节依赖单一公司,可能带来脆弱性。
  • 价值积累:这些关键公司获取了供应链中的大部分价值。
  • 地缘政治:这些公司的重要性使其成为大国科技竞争的核心议题。

上一节我们探讨了高度集中的计算供应链。本节中,我们转向数据供应链,其特点是参与者更加多样,获取机制复杂。

数据不像计算那样资本密集,因此供应链结构也更多样。从模型开发者的视角,数据来源可以分为几类:

以下是数据进入AI公司的不同途径:

  1. 内部生成:公司自己产生的数据,例如通过强化学习生成的合成数据。
  2. 现有业务获取:通过现有产品或服务(如Gmail、ChatGPT用户交互)获取的用户数据。
  3. 公开可用数据:可公开获取的数据集(如SQuAD)或整个可爬取的互联网。
  4. 专项采购数据:通过特定协议从其他公司购买或授权的数据(如从Scale.ai购买标注数据,或从《纽约时报》授权新闻文章)。

以网络爬取为例,这是预训练数据的主要来源。近年来,网站对爬虫的限制日益增加,并且不同AI公司的爬虫可能受到区别对待。此外,不同数据获取方式的成本结构差异巨大,从计算成本到劳动力成本,再到大规模版权许可费用。

数据供应链的结构帮助我们思考几个关键问题:

  • 数据可用性:我们是否会耗尽训练数据?不同类型数据的生成速率是多少?
  • 法律合规:需要遵守版权、隐私(如GDPR)、非法内容等相关法律。
  • 竞争动态:某些实体对数据的独占访问权是否会带来模型质量优势。

上一节我们讨论了构建模型的资源输入。本节中,我们关注模型如何被分发,从而影响经济。

模型开发者可以选择不同的分发策略,形成一个从封闭到开放的谱系:

以下是当前模型分发的主要方式:

  • 完全封闭:模型不对外分发,仅用于内部产品。
  • 受限访问:通过API提供查询服务,但不开放模型权重。
  • 开放权重:发布模型权重,允许他人本地部署或微调。
  • 完全开源:不仅发布权重,还发布训练数据、代码等。

这个分发选择深刻影响下游供应链和经济:

  • 控制与整合:封闭策略允许开发者对模型使用有更强控制和垂直整合能力。
  • 定价与竞争:封闭API的定价通常高于开放权重的模型,因为后者会引入更多服务提供商和竞争。
  • 应用类型:开放权重支持更多样的应用,如微调、蒸馏,并在隐私要求高的场景可能更有优势。

上一半课程我们描述了当前的供应链状况。现在,我们转向一个更前瞻性的问题:如何理性地预测AI对经济增长的影响?

在思考未来时,我们需要采用宏观经济学视角,将整个经济视为一个聚合体进行分析。我们主要关注以语言模型为代表的前沿AI,及其对GDP等宏观经济指标的潜在影响。

许多人尝试预测AI的影响。例如:

  • 经济学家达龙·阿西莫格卢预测AI对全要素生产率和GDP增长的提升相对温和。
  • 一些计算机科学家和硅谷人士的预测则更为乐观,认为AI将带来变革性影响。

为了系统分析,我们可以借助经济学中“通用技术”的概念。通用技术具有三个特征:

  1. 普遍性:技术被多个经济部门广泛采用。
  2. 持续改进:技术能力随时间提升,同时价格下降。
  3. 催生互补性创新:技术能激发大量下游创新和应用。

AI,特别是基础模型,似乎满足这些条件。历史表明,通用技术的经济效益显现往往存在“J曲线”延迟,即初期需要时间进行组织调整和互补创新,之后才能带来显著的生产率增长。

上一节我们引入了通用技术的概念。本节中,我们探讨衡量AI经济价值的挑战,并分析几种可能的增长情景。

传统GDP核算可能无法完全捕捉AI的价值。许多AI服务是免费或低价提供的,其价值通过广告等其他机制体现,这导致GDP统计可能低估其影响。替代性指标如“GDP-B”试图通过衡量“消费者剩余”(用户愿意为某项服务支付的最高价格)来更好地捕捉技术福利。

如果以GDP为主要衡量指标,我们可以分析几种不同的AI增长情景:

以下是三种关于AI如何影响经济的主要观点及其对GDP的潜在含义:

  1. 单一部门生产力提升:如果AI主要使某个特定部门(如软件业)生产力大幅提升,该部门产品价格会下降,其经济占比可能缩小。其他部门为争夺劳动力可能面临工资上涨压力(鲍莫尔成本病),整体GDP增长可能低于该部门的生产力增速。
  2. 新型劳动力供给:如果将AI视为一种新的、更廉价的劳动力来源注入经济,那么GDP能否显著增长取决于资本能否以相近的速度增长以利用这些新“劳动力”。
  3. 新思想生产引擎:如果AI的核心作用是加速新思想、新知识的产生,由于思想的“非竞争性”特质,这有可能从根本上提高经济增长率,甚至使其超越历史趋势。

本节课中,我们一起学习了如何从供应链和经济增长理论两个角度分析AI的经济影响。我们探讨了计算和数据供应链的结构、模型分发策略的经济后果,并学习了如何运用通用技术理论和增长情景分析来理性思考AI的未来。理解这些经济维度,对于技术开发者在更广阔的社会背景下定位自己的工作至关重要。

在本节课中,我们将一起回顾斯坦福CS221课程第20讲“炉边谈话与结论”的核心内容。本次讲座以问答形式展开,涵盖了职业发展、学术研究、课程设计以及对人工智能未来的展望。我们将整理对话内容,提炼关键观点,并以教程的形式呈现,帮助初学者理解人工智能领域的现状与未来。

本次讲座由课程讲师Percy Liang主持,旨在回答学生们关于人工智能课程、职业规划、研究建议以及AI未来发展的各种问题。讲座分为三个主要部分:职业生活与研究建议、课程与斯坦福相关问题、以及AI的未来展望。通过这次对话,学生们可以获得来自资深研究者和教育者的宝贵见解。


上一节我们介绍了课程的整体结构,本节中我们来看看关于职业发展和学术研究的建议。Percy分享了他对当前AI领域就业市场、技能需求以及研究方向的看法。

随着AI技术的快速发展,传统的软件工程岗位需求正在发生变化。Percy指出,仅仅掌握过去的编程技能可能不足以应对未来的挑战。他建议学生们将重点从“如何构建”转向“构建什么”,即更多地关注问题定义、项目管理和战略规划。

以下是Percy给出的几点具体建议:

  • 关注成长与学习:第一份工作的核心价值在于个人成长和学习新技能的能力。
  • 培养协作能力:在实际工作中,与他人合作的能力至关重要,这往往比单纯的技术能力更重要。
  • 适应快速变化:最重要的技能是快速学习和适应新技术、新环境的能力。

针对“学术界在AI时代是否已经过时”的疑问,Percy认为,学术界依然扮演着不可替代的角色。

以下是学术界可以专注的几类研究方向:

  • 长期基础研究:探索那些尚未被工业界大规模应用的前沿理念和根本性问题。
  • 中立性研究:研究涉及伦理、版权、模型评估等可能存在利益冲突的课题,这些是工业界实验室难以深入进行的。
  • 探索新机遇:不要只盯着当前热门的Transformer模型,应关注其他数据领域(如生物序列、气候数据)应用AI技术的可能性。

在讨论了宏观的职业和研究方向后,本节我们将焦点拉回到CS221这门课程本身以及斯坦福的教育环境。

Percy回顾了CS221课程在过去十年的演变。今年的课程进行了重大调整,主要目标有两个:一是更深入地融入AI的社会影响讨论;二是采用“可执行讲座”格式,将抽象概念与具体代码相结合,以减少理解上的鸿沟。

有学生提问,课程中学习的搜索、MDP(马尔可夫决策过程)等传统AI概念,与如今流行的大语言模型有何关联。Percy解释道,这些基础概念依然高度相关:

  • 搜索:大语言模型在推理时进行的“思维链”或尝试不同解决方案的过程,本质上就是一种搜索。
  • MDPs:对预训练模型进行强化学习微调,就是在学习一个能获得高回报的策略,这与MDP框架一致。

Percy强调,这门课的目的不仅是传授实用技能,更是培养学生对AI系统底层原理的深刻理解,这种理解能让他们在技术快速迭代中保持适应力。


最后,我们展望人工智能的未来。Percy分享了他对当前AI能力评估、发展预测以及公众认知的看法。

Percy认为,公众对AI的认知常常受到科幻作品的影响。实际上,AI的影响更多是渗透性的、作为基础设施存在的,而非一个具象化的智能体。

关于能力评估:

  • 被低估的能力:大语言模型基于概率预测下一个词(token)的基本功。衡量模型在长上下文中的预测损失(perplexity),是评估其底层理解能力的关键,这点常被忽视。
    • 公式P(xt | x ,即在给定前文 x_ 的条件下,预测下一个词 x_t 的概率。
  • 被高估的能力:“思维链”推理。目前的推理过程可能效率低下且难以理解其内部机制,有时甚至会产生错误中间步骤却得到正确答案。

Percy将AI视为与计算技术同等重要的通用目的技术,其影响可能持续一个世纪。他提出,评估AI进展更好的指标不是图灵测试,而是AI在现实中取得的成果,例如做出了多少新的科学发现。

对于未来的应用,他鼓励学生跳出“另一个AI助手”的思维,探索将基础模型技术应用于计算机科学之外的广阔领域,如生物、材料科学、气候学等。


在本节课中,我们一起学习了Percy Liang教授关于AI教育、职业发展和技术未来的深刻见解。讲座以现场问答结束,Percy回答了关于如何参与斯坦福研究、AI公司透明度、如何让用户关注AI伦理等问题。他鼓励学生主动探索,通过阅读论文、联系教授或学生等方式融入研究社区,并强调了在快速变化的AI领域保持好奇心和学习能力的重要性。

本节课中我们一起学习了:在AI时代如何规划职业路径、学术界与工业界的互补角色、CS221课程设计背后的思考,以及如何理性看待AI的当前能力与未来潜力。核心在于掌握基本原理、培养适应与协作能力,并保持对技术社会影响的关注。

小讯
上一篇 2026-03-27 14:38
下一篇 2026-03-27 14:36

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/248966.html