斯坦福-CS221-人工智能导论笔记-全-
斯坦福 CS221 人工智能导论笔记(全)



🧠 课程 P1:人工智能概述


在本节课中,我们将一起了解人工智能(AI)的广阔领域。我们将回顾其发展历史,探讨其核心目标,并介绍本课程将采用的核心学习范式。课程内容旨在为初学者提供一个清晰、全面的入门视角。


📜 人工智能简史
人工智能的故事始于1956年达特茅斯学院的夏季研讨会。当时,约翰·麦卡锡等先驱者提出了一个宏伟的目标:精确地描述学习的各个方面或智能的任何特征,以便机器能够进行模拟。
然而,早期的乐观情绪很快遇到了挑战。例如,在机器翻译领域,将英文句子“The spirit is willing but the flesh is weak”翻译成俄语后再译回英文,却得到了“The vodka is good but the meat is rotten”这样荒谬的结果。这导致了资金削减和第一个“AI寒冬”的到来。
早期失败的原因主要有两点:
- 计算能力不足:当时的计算能力远不及现在。
- 问题建模的局限性:许多方法本质上依赖于指数级搜索,并且缺乏从数据中学习的能力。
尽管如此,这个时期为计算机科学贡献了许多重要思想,如LISP语言、垃圾回收和时间共享。
到了20世纪80年代,研究重点转向了知识。专家系统通过编码人类专家的规则知识来解决特定领域问题(如疾病诊断),并首次在工业界产生了实际影响。然而,基于确定性规则的系统难以捕捉世界的所有细微差别,维护成本高昂,最终导致了第二个“AI寒冬”。
与此同时,另一条研究脉络——人工神经网络——也在悄然发展。1943年,McCulloch和Pitts提出了人工神经网络的理论。1969年,Minsky和Papert的著作《Perceptrons》指出线性分类器无法解决异或(XOR)问题,这在一定程度上抑制了神经网络的研究。
直到20世纪80年代,反向传播算法的(重新)发现使得训练多层神经网络成为可能。1989年,Yann LeCun应用卷积神经网络成功识别手写数字,并将其部署于美国邮政系统。但神经网络,特别是深度学习,真正迎来爆发是在2010年代,以2012年AlexNet在ImageNet竞赛中的突破性表现为标志。
人工智能领域汲取了来自逻辑、神经科学、统计学、经济学和优化理论等多个学科的养分。它就像一个“大熔炉”,将各种技术融合并应用于解决有趣的问题。


🎯 人工智能的目标:智能体与工具
关于人工智能的目标,存在两种主要视角,区分它们有助于避免混淆。


第一种视角:AI 即智能体
这个视角关注如何创造或重现智能。它审视人类令人惊叹的能力:感知世界、操纵物体、使用语言、拥有知识、进行推理,以及最重要的——通过经验进行学习。当前AI的成功大多局限于特定任务,并且需要海量数据,而人类则能从少量样本中学习,并处理多样化的任务。如何让机器具备人类这种通用学习能力,仍然是一个巨大的挑战。
第二种视角:AI 即工具
这个视角更关注如何利用技术造福社会,而不一定非要制造类人的智能。许多成功的AI应用都属于此类,它们解决的是对人类而言并不自然,但对社会有重大价值的问题。例如:
- 利用卫星图像和计算机视觉预测地区GDP。
- 优化数据中心冷却以节约能源。
然而,当AI被部署到自动驾驶、身份认证等关键任务中时,也带来了新的挑战:
- 安全性问题:例如对抗性样本,可以欺骗图像识别系统。
- 偏见问题:机器学习模型可能从训练数据中学习并放大社会现有的偏见(例如,在翻译中体现性别职业偏见)。
- 公平性难题:不同的公平性定义在数学上可能是互斥的(例如在风险评估系统中),这需要社会和技术共同解决。
总结:智能体的视角激励我们探索更通用、更高效的学习机制;而工具的视角则要求我们认真思考AI系统在现实世界中部署时带来的伦理、安全和社会影响。
🏗️ 课程核心范式:建模、推断与学习
面对复杂的现实世界问题,我们需要一个系统化的解决框架。本课程将围绕 “建模、推断与学习” 这一核心范式展开。
1. 建模
建模是将复杂的现实世界简化为一个数学上精确、可供计算机处理的模型的过程。关键在于决定关注哪些信息,忽略哪些信息。例如,将城市导航问题建模为一个图,其中节点是地点,边代表可通行路径及其代价。
2. 推断
在获得模型后,推断是指针对模型提出问题并计算答案。例如,在图模型中,询问“从A点到B点的最短路径是什么?”。
3. 学习
学习解决的是“模型从何而来”的问题。我们通常先定义一个带参数的模型骨架,然后利用数据来自动学习这些参数。例如,在导航模型中,我们不知道每条边的实际通行时间(代价),但我们可以从大量“从x到y花了z分钟”的历史数据中,学习出各条边的代价参数。
这个范式的流程是:定义模型骨架 -> 用数据学习参数 -> 对带参数的模型进行推断。学习在这里不是指某个特定算法,而是一种通过数据来填充模型细节的哲学。
📚 课程内容路线图
本课程将按照模型智能的层次,从低到高进行讲解:
1. 机器学习
机器学习是AI的基础构建块,其核心思想是将复杂性从代码转移到数据。它依赖于从有限数据到未知情况的泛化能力。
2. 反射模型
这类模型像条件反射一样,接收输入后经过固定计算直接产生输出,没有内部状态或“思考”过程。例如线性分类器、深度神经网络。它们速度快,适合感知类任务。
3. 基于状态的模型
对于下棋、机器人规划等需要“前瞻”和决策的问题,我们使用基于状态的模型。它将世界描述为一系列状态,并通过动作进行状态转移。主要包括三类:
- 搜索问题:在确定性的环境中寻找最优路径。
- 马尔可夫决策过程:在具有随机性的环境中进行决策。
- 对抗性游戏:在与对手的对抗中制定策略。


4. 基于变量的模型
对于像数独这样受多种约束同时影响的问题,我们使用基于变量的模型。它将解决方案视为满足一系列约束的变量赋值。主要包括:
- 约束满足问题:处理硬约束(如一个人不能同时在两个地方)。
- 贝叶斯网络:处理变量间的软概率依赖(如基于传感器数据追踪汽车位置)。

5. 逻辑
逻辑系统致力于实现高层次的推理能力。它能够处理异构信息,并进行深度的逻辑推理。例如,一个基于逻辑的系统可以理解“学生都是人”、“爱丽丝是学生”、“爱丽丝不是人”这几条陈述之间存在矛盾。
⚙️ 课程优化基础:动态规划与梯度下降
在课程的技术开端,我们将通过两个经典问题,介绍支撑“推断”和“学习”的两大优化工具。
1. 离散优化:编辑距离与动态规划
问题:计算将字符串S转换为字符串T所需的最少编辑次数(插入、删除、替换)。

挑战:直接枚举所有可能的编辑序列是指数级的,不可行。
解决方案:动态规划
核心思想是将复杂问题分解为更简单的子问题,并避免重复计算。
- 定义子问题:设
dp(m, n)为S前m个字符与T前n个字符的编辑距离。 - 建立递推关系:
- 若
S[m] == T[n]:dp(m, n) = dp(m-1, n-1)。 - 否则:
dp(m, n) = 1 + min(dp(m-1, n-1), // 替换 dp(m-1, n), // 删除S[m] dp(m, n-1))// 在S插入T[n](等价于删除T[n])
- 若
- 使用记忆化:存储已计算的
dp(m, n)结果,避免重复递归。
def edit_distance(s, t):
memo = {}
def dp(m, n):
if (m, n) in memo:
return memo[(m, n)]
if m == 0:
result = n
elif n == 0:
result = m
elif s[m-1] == t[n-1]:
result = dp(m-1, n-1)
else:
result = 1 + min(dp(m-1, n-1), # 替换
dp(m-1, n), # 删除
dp(m, n-1)) # 插入
memo[(m, n)] = result
return result
return dp(len(s), len(t))
2. 连续优化:线性回归与梯度下降
问题:给定一组数据点 (x_i, y_i),拟合一条形如 y = w * x (假设过原点)的直线,使得预测值与真实值的误差平方和最小。
形式化:最小化目标函数 F(w) = Σ_i (w * x_i - y_i)^2。

解决方案:梯度下降
当无法直接求解解析解时,梯度下降提供了一种迭代逼近的方法。
- 核心思想:函数值下降最快的方向是其梯度的反方向。
- 算法步骤:
- 初始化参数
w。 - 重复直到收敛:
- 计算当前
w处的梯度(导数)∇F(w)。 - 沿梯度反方向更新:
w = w - η * ∇F(w),其中η为学习率(步长)。
- 计算当前
- 初始化参数

对于本例,导数 dF/dw = 2 * Σ_i (w * x_i - y_i) * x_i。
def gradient_descent(points, steps=100, learning_rate=0.1):
w = 0.0 # 初始化参数
for _ in range(steps):
grad = 0.0
loss = 0.0
for x, y in points:
error = w * x - y
grad += 2 * error * x # 计算梯度
loss += error ** 2 # 计算损失
w = w - learning_rate * grad # 沿负梯度方向更新
print(f"w: {w:.4f}, Loss: {loss:.4f}")
return w

🏁 总结

本节课我们一起学习了:
- 人工智能的发展历程,从早期的逻辑推理、专家系统到如今的深度学习,是一个多学科融合、不断迭代的过程。
- 人工智能的双重目标:既是创造类人智能体的科学探索,也是构建造福社会工具的技术实践。
- 本课程的核心范式——“建模、推断与学习”,为我们提供了解决复杂AI问题的系统化框架。
- 课程的知识路线图,将从机器学习基础,逐步深入到反射模型、状态模型、变量模型和逻辑推理。
- 两大基础优化技术:用于离散优化的动态规划和用于连续优化的梯度下降,它们是实现高效推断和有效学习的数学工具。



希望这节课能为你打开人工智能世界的大门,在接下来的课程中,我们将深入探索这个激动人心的领域的每一个组成部分。


🎮 课程10:博弈论与游戏AI 2 - 时序差分学习与博弈论


在本节课中,我们将继续探讨游戏AI。我们将学习如何通过时序差分学习来优化游戏中的评估函数,并进一步了解同时博弈与非零和博弈的基本概念。



🔄 回顾:零和、回合制游戏
上一节我们介绍了零和、双人、回合制游戏的框架。我们讨论了智能体与对手对抗的场景,智能体试图最大化其效用,而对手则试图最小化智能体的效用。
我们引入了极小化极大算法来解决这类问题。其核心思想是,智能体在决策时会假设对手总是做出对其最不利的回应。
对于状态 S 的价值 V(S),我们通过以下递推关系定义:
- 如果
S是终止状态,则V(S) = Utility(S)。 - 如果是智能体的回合,则
V(S) = max_{a} V(Successor(S, a))。 - 如果是对手的回合,则
V(S) = min_{a} V(Successor(S, a))。
然而,对于像国际象棋这样分支因子大、深度深的游戏,完整的搜索树是不现实的。因此,我们引入了评估函数 eval(S)。我们只搜索到一定深度 d,然后使用评估函数来估计该状态的价值,从而加速决策过程。
随之而来的问题是:我们如何获得一个好的评估函数?




🤖 学习评估函数:时序差分学习
评估函数可以手工设计,例如在国际象棋中,可以根据棋子数量、机动性、王的安全等因素来构建。但更强大的方法是从数据中学习这个函数。

我们可以将评估函数 V 参数化,表示为 V(S; w),其中 w 是需要学习的权重参数。最简单的形式是线性函数:
V(S; w) = w · f(S)
其中 f(S) 是手工设计的特征向量。当然,V 也可以是更复杂的模型,如神经网络。

那么,数据从何而来?我们可以通过自我对弈来生成数据。让智能体根据当前策略 π(例如,基于当前 V 的贪婪策略)与自己对弈,产生一系列游戏对局(片段)。
以下是生成的数据形式:
S1, A1, R1, S2, A2, R2, ..., Sn
在大多数棋类游戏中,只有在游戏结束时才有非零奖励,即 R1...Rn-1 = 0,Rn 为最终结果(赢/输/平)。
时序差分学习算法

我们可以从每一个经验片段 (S, A, R, S') 中学习。其核心思想是让当前预测值 V(S; w) 更接近一个更优的“目标值”。
我们定义:
- 预测值:
Prediction = V(S; w) - 目标值:
Target = R + γ * V(S'; w)(在游戏中,折扣因子γ通常为1)



我们希望最小化预测值与目标值之间的误差。采用平方误差:
Error = 1/2 * (Prediction - Target)^2


通过梯度下降来更新权重 w:
w ← w - α * (Prediction - Target) * ∇_w V(S; w)
其中 α 是学习率。


对于线性函数 V(S; w) = w · f(S),梯度 ∇_w V(S; w) = f(S),因此更新规则简化为:
w ← w - α * (Prediction - Target) * f(S)


一个简单的计算示例



假设一个游戏有三个状态 S1, S2, S3,特征向量分别为 f(S1)=[1,0], f(S2)=[1,2], f(S3)=[1,0]。奖励仅在 S3 获得 R=1。
- 初始化权重
w = [0, 0]。 - 第一局:
S1 -> S2 -> S3。- 在
S1和S2,预测值和目标值均为0,权重不更新。 - 在
S2(导致进入S3的状态):预测值V(S2)=0,目标值Target = R + V(S3) = 1 + 0 = 1。误差为-1。 - 更新
w:w = [0,0] - 0.5*(-1)*[1,2] = [0.5, 1]。
- 在
- 第二局:从
S1开始,权重已更新。预测值和目标值不再全为零,权重会继续调整,最终收敛。

与Q学习的比较



时序差分学习与Q学习非常相似,但存在关键区别:
- 操作对象:TD学习基于状态价值函数 V(s),而Q学习基于状态-动作价值函数 Q(s,a)。在游戏规则已知的设定下,知道状态价值通常足以决策。
- 策略性质:TD学习通常是同策略的,它评估并改进用于生成数据的策略本身。Q学习是异策略的,它直接学习最优策略的价值,而不依赖于当前行为策略。
- 环境模型:TD学习需要知道游戏的规则(后继函数) 来计算
S'。Q学习可以在不知道环境模型的情况下,仅通过经验(s,a,r,s')进行学习。
🕹️ 扩展:同时博弈与非零和博弈
上一节我们介绍了基于回合的博弈,本节中我们来看看当玩家同时行动,或者利益并非完全对立时,情况会如何变化。


同时博弈:石头剪刀布与猜拳游戏
考虑一个“两指莫拉”游戏:两个玩家A和B同时出示1或2根手指。
- 若都出1,B给A 2美元。
- 若都出2,B给A 4美元。
- 若出示不同,A给B 3美元。
我们可以用收益矩阵来表示玩家A的效用(玩家B的效用为其相反数,因为是零和):
| A\B | 出1 | 出2 |
|---|---|---|
| 出1 | 2 | -3 |
| 出2 | -3 | 4 |
在同时博弈中,策略分为:
- 纯策略:确定性地选择一个动作(如“总是出1”)。
- 混合策略:以一定概率分布选择动作(如“以50%概率出1,50%概率出2”)。


冯·诺依曼极小极大定理
一个关键结论是:在零和同时博弈中,行动顺序不影响博弈的均衡值。即使你先公开自己的最优混合策略,对手也无法利用这一点获得比你预期更差的结果。
以“两指莫拉”为例,计算可得玩家A的最优混合策略是以 7/12 的概率出1,以 5/12 的概率出2。此时,无论玩家B如何应对(B的最优反应是一个纯策略),A的期望收益都是 -1/12。如果交换行动顺序,B先宣布混合策略,A后行动,最终的均衡期望收益依然是 -1/12。
这一定理意味着,在零和同时博弈中,拥有并公布一个最优的随机化策略(混合策略)是安全的。
非零和博弈:囚徒困境
现实中的博弈往往不是严格的零和。囚徒困境是一个经典的非零和博弈模型:
两个共犯被分开审讯。他们可以选择“坦白”或“抵赖”。
- 都坦白:各判5年。
- 都抵赖:各判1年。
- 一人坦白,一人抵赖:坦白者获释,抵赖者判10年。
收益矩阵如下((A的刑期, B的刑期)):
| A\B | 坦白 | 抵赖 |
|---|---|---|
| 坦白 | (-5, -5) | (0, -10) |
| 抵赖 | (-10, 0) | (-1, -1) |
纳什均衡
在非零和博弈中,我们使用纳什均衡的概念。一组策略 (π_A*, π_B*) 构成纳什均衡,当且仅当没有任何一个玩家可以通过单方面改变自己的策略而获得更高的收益。
分析囚徒困境:
- (坦白, 坦白) 是一个纳什均衡。给定对方坦白,自己坦白判5年,抵赖则判10年,所以不会改变策略。
- (抵赖, 抵赖) 不是纳什均衡。给定对方抵赖,自己抵赖判1年,但若改为坦白则能直接获释(0年),有动机改变。


有趣的是,(抵赖,抵赖)这个对双方整体更优的结果(总刑期2年),由于个人理性的驱使,却无法成为稳定的均衡点。而(坦白,坦白)这个对双方更差的结果(总刑期10年)却是稳定的均衡。这体现了个人理性与集体理性的矛盾。
纳什存在性定理指出:任何有限玩家、有限动作的博弈,都至少存在一个(可能是混合策略的)纳什均衡。

📚 总结

本节课我们一起学习了以下内容:
- 时序差分学习:我们探讨了如何通过自我对弈生成数据,并利用TD学习算法来优化游戏评估函数的参数,从而让AI在游戏中自我提升。
- 同时博弈:我们分析了玩家同时行动的游戏,引入了收益矩阵、纯策略与混合策略的概念,并理解了冯·诺依曼极小极大定理——在零和同时博弈中,最优混合策略可以公开。
- 非零和博弈:我们跳出了零和框架,以囚徒困境为例,介绍了纳什均衡的概念,看到了个人理性可能导致集体非最优的有趣现象。


从手工评估函数到通过TD学习自我进化,从回合制到同时博弈,从零和到非零和,我们对游戏AI和博弈论的理解又加深了一层。这些理论不仅是游戏AI的基础,也在经济学、政治学等多个领域有广泛应用。



课程 P11:因子图 1 - 约束满足问题 🧩
在本节课中,我们将学习一种新的建模框架——变量模型,特别是因子图和约束满足问题。我们将了解它们与之前学过的状态模型有何不同,并学习如何用这种新框架来建模和解决特定类型的问题。


概述:从状态模型到变量模型


到目前为止,我们讨论的模型(如搜索问题、MDP、对抗游戏)都属于状态模型。状态模型的核心是状态,它是对过去所有行动的总结,足以让我们为未来做出最优决策。我们通过行动在状态之间移动,并寻找最优的行动序列。


然而,有一类问题,其核心不在于行动的顺序,而在于满足一系列约束。例如,地图着色问题要求为每个省份分配颜色,并满足相邻省份颜色不同的约束。解决这类问题时,我们并不关心先给哪个省份着色,只关心最终能否满足所有约束。
这种特点促使我们引入变量模型。在变量模型中,我们不再关注状态和行动序列,而是直接定义变量和它们的赋值,并通过因子(或约束)来描述变量之间的关系。这提供了更高层次的抽象,使建模更简单,而将变量和值的选择顺序问题推给了推理算法去处理。


什么是因子图?📊

因子图是一种用于表示变量模型的图形化工具。它由两部分组成:变量和因子。



核心定义






- 变量:用大写字母表示,例如
X1, X2, ...。每个变量Xi都有一个定义域,即它可以取值的集合。 - 因子:用小写字母
f表示,例如f1, f2, ...。每个因子是一个非负函数,其输入是它所依赖的一组变量(称为该因子的作用域),输出表示该变量组合的“满意度”或“权重”。 - 赋值:为所有变量分配具体值的过程。一个完整的赋值用小写
x表示。 - 赋值的权重:一个赋值
x的权重是所有因子在该赋值下输出值的乘积。我们的目标是找到权重最大的赋值。
公式:权重计算
weight(x) = ∏_{j=1}^{m} f_j(x)
因子图示例
假设有三个人(X1, X2, X3)每人选择红色或蓝色,并有以下偏好和约束:
X1强烈希望选蓝色。X1和X2必须选相同颜色。X2和X3最好选相同颜色。X3倾向于选红色。
我们可以用因子图表示如下:
- 变量:
X1,X2,X3,定义域均为{红, 蓝}。 - 因子:
f1(X1):若X1=蓝则输出 1,否则为 0。f2(X1, X2):若X1 = X2则输出 1,否则为 0。f3(X2, X3):若X2 = X3则输出 3(更满意),否则输出 2。f4(X3):若X3=红则输出 2,否则为 1。


通过计算不同赋值的权重,我们可以找到最令人满意的颜色组合。

约束满足问题:特殊的因子图 ✅

约束满足问题 是因子图的一个特例,其中所有因子都是约束。约束的输出只能是 0 或 1:
- 1 表示该约束被满足。
- 0 表示该约束被违反。
在 CSP 中,一个赋值的权重是所有约束取值的乘积。因此,权重只能是 0 或 1:
- 权重 = 1:所有约束均被满足,称为一致赋值。
- 权重 = 0:至少有一个约束被违反,称为不一致赋值。
CSP 的目标是找到任何一个一致赋值(即权重为 1 的赋值)。
CSP 示例:地图着色
问题:为澳大利亚的七个省份着色,可用颜色为红、绿、蓝,要求相邻省份颜色不同。
- 变量:七个省份(如 WA, NT, SA...)。
- 定义域:每个变量的定义域都是
{红, 绿, 蓝}。 - 约束(因子):对于每对相邻省份,定义一个二元约束
f_neighbor(Xi, Xj),当Xi ≠ Xj时输出 1,否则输出 0。



我们的目标就是找到一个满足所有相邻约束的着色方案。

如何解决 CSP?回溯搜索算法 🔍

解决 CSP 最直接的方法是回溯搜索。其基本思想是逐步构建赋值,并在发现不一致时回溯。
以下是回溯搜索算法的核心步骤:
- 选择未赋值的变量:使用启发式方法决定下一个要赋值的变量。
- 为变量选择值:从该变量的当前定义域中,按某种顺序选择一个值。
- 检查一致性:检查当前部分赋值与新值组合后,相关的约束是否被违反(即因子输出是否为 0)。
- 递归搜索:如果一致,则用新值扩展部分赋值,并递归调用搜索。
- 回溯:如果不一致,或者从该值出发的递归搜索失败,则尝试该变量的下一个值。如果所有值都失败,则回溯到上一个决策点。
提升效率的启发式方法
为了让回溯搜索更高效,我们可以在两个关键步骤使用启发式方法:
1. 变量选择启发式:最受约束变量优先
- 策略:选择当前定义域最小(即可选值最少)的未赋值变量。
- 原因:“尽早失败”。如果问题无解,定义域最小的变量最可能很快导致矛盾,从而尽早剪枝,避免在无望的分支上浪费搜索时间。

2. 值选择启发式:最少约束值优先
- 策略:为选定的变量赋值时,优先选择那个能给其他未赋值变量留下最多选择的值。
- 原因:既然已经决定要给这个变量赋值,就应选择最有可能让后续搜索成功的值,以提高找到解的概率。

利用一致性检查进行剪枝 ✂️
在回溯搜索中,我们可以通过主动检查并缩小变量的定义域来提前发现矛盾,这称为维持一致性。有两种主要方法:
1. 前向检查
- 做法:当给变量
Xi赋值后,立即检查Xi的所有邻居变量。从邻居变量的定义域中,删除所有与Xi的当前值不兼容的值。 - 效果:如果任何邻居变量的定义域因此变为空集,则当前部分赋值必然导致失败,可以立即回溯。
2. 弧相容
- 做法:比前向检查更彻底。它反复检查图中所有变量对
(Xi, Xj)。对于Xi定义域中的每个值,检查Xj的定义域中是否存在某个值能满足它们之间的约束。如果不存在,则从Xi的定义域中删除该值。 - 算法:常用的弧相容算法是 AC-3。它会维护一个需要检查的弧(变量对)的队列,不断传播约束,直到没有定义域可以再被缩小为止。
- 效果:能更大幅度地剪枝搜索空间,有时甚至能在开始回溯前就推导出唯一解。但请注意,弧相容是局部的,它不能保证一定能检测出所有全局不一致性。
建模实践:更多 CSP 示例 🏛️

理解如何将实际问题建模为 CSP 至关重要。以下是两个例子:
示例 1:雕塑展览问题
- 问题:三件雕塑 A, B, C 需放入房间 1 或 2。约束:A 和 B 不能同室;B 和 C 必须同室;房间 2 最多放一件雕塑。
- 建模:
- 变量:
A,B,C,定义域{1, 2}。 - 约束:
A ≠ B(二元约束)B = C(二元约束)(A=2) + (B=2) + (C=2) ≤ 1(三元约束,可转换为二元约束)
- 变量:
示例 2:课程安排问题
- 问题:将 E 门课程安排到 T 个时间段。约束:每门课必须且只能安排一个时间;每个时间段最多安排一门课;某些课程只能安排在特定时间。
- 建模(两种方式):
- 方式一(以课程为变量):
- 变量:每门课程
Course_i,定义域{1, 2, ..., T}。 - 约束1(每时段最多一门课):对所有课程对
(i, j),添加约束Course_i ≠ Course_j。共有 O(E²) 个二元约束。 - 约束2(特定时间限制):对每门课添加一元约束,限制其可取值。
- 变量:每门课程
- 方式二(以时间为变量):
- 变量:每个时间段
TimeSlot_t,定义域{课程1, 课程2, ..., 空}。 - 约束1(每门课一个时间):需要一个大约束,确保每门课恰好出现在一个时间段变量的值中。这是一个涉及 T 个变量的高阶约束。
- 变量:每个时间段
- 选择:根据课程数
E和时间段数T的相对大小,选择产生约束更少、更简单的建模方式。通常高阶约束可以转换为多个二元约束来处理。
- 方式一(以课程为变量):

总结 📝
本节课我们一起学习了变量模型的基础——因子图和约束满足问题。



- 核心思想:与关注状态和行动序列的状态模型不同,变量模型直接关注变量、赋值以及变量间的约束。它适用于那些顺序不重要,但需要满足一系列局部关系的问题。
- 因子图:由变量和因子组成。因子是表示变量组合满意度的非负函数。赋值的权重是所有因子值的乘积,目标是最大化权重。
- CSP:是因子图的特例,因子均为输出 0/1 的约束。目标是找到权重为 1 的一致赋值。
- 求解方法:使用回溯搜索,并可通过启发式方法(最受约束变量、最少约束值)和一致性检查(前向检查、弧相容)来大幅提升搜索效率。
- 建模:将实际问题转化为 CSP 是关键步骤,有时存在多种建模方式,需要根据约束的数量和复杂度进行选择。




在下一节课中,我们将继续探讨 CSP 的更多推理算法。


课程 P12:因子图 2 - 条件独立性 🧩
在本节课中,我们将继续学习约束满足问题,重点探讨如何利用因子图中的条件独立性来更高效地求解。我们将介绍几种关键的算法思想,包括束搜索、局部搜索、条件化和消元法。
概述
上一节我们介绍了因子图的基本概念和回溯搜索算法。本节我们将看到,当变量之间存在独立性时,问题可以大大简化。我们将学习如何识别和利用这种独立性,并介绍几种更高效的近似和精确求解算法。
回顾:因子图与CSP
首先,我们快速回顾一下约束满足问题的因子图表示。
- 变量:例如
x1,x2,x3,每个变量都有一个离散的定义域。 - 因子:是作用于一个或多个变量的函数,用于评估对变量赋值的“喜好”程度。因子所作用的变量集合称为其作用域。
- 权重:一个完整赋值(所有变量都取值)的权重,是所有因子取值的乘积。
- 目标:找到使总权重最大的变量赋值。
一个简单的例子是人员着色问题:三个人(变量)可以选择红色或蓝色(定义域),因子编码了诸如“两人必须一致”或“倾向于一致”等约束。
束搜索:在速度与精度间权衡 🔍
回溯搜索虽然能保证找到最优解,但速度很慢(指数时间)。贪心搜索很快(线性时间),但可能错过全局最优解。
束搜索是一种折衷方案。以下是其工作原理:
- 维护一个包含
k个部分赋值的列表(称为“束”)。 - 在每一步,对束中的每一个部分赋值,尝试扩展一个新的变量(测试其定义域中的所有值)。
- 将所有扩展出的新部分赋值按权重排序,只保留权重最高的前
k个,形成新的束。 - 重复此过程,直到所有变量都被赋值。
核心思想:参数 k 是一个旋钮。k=1 时就是贪心搜索;k 很大时,则接近广度优先搜索,探索更多状态空间。它不保证找到最优解,但通常比纯贪心更好,且比完全回溯更快。
局部搜索:改进现有赋值 ✨
束搜索是从零开始构建赋值。局部搜索则从一个完整的(可能是随机的)赋值开始,然后尝试逐步改进它。
迭代条件模式
ICM 是一种简单的局部搜索算法:
- 选择一个变量。
- 固定所有其他变量的当前值(即“条件化”)。
- 尝试该变量定义域中的所有可能值,计算整个赋值的权重(只需重新计算与该变量相连的因子,因为其他因子值不变)。
- 将该变量的值设置为能产生最高权重的那个值。
- 对下一个变量重复此过程。
特点:ICM 会收敛到一个局部最优解,但不一定是全局最优。其名称来源于:迭代(遍历变量)、条件(固定其他变量)、模式(选择最优值)。
吉布斯采样
吉布斯采样与 ICM 类似,但引入了随机性以帮助跳出局部最优:
- 选择一个变量。
- 固定所有其他变量的值。
- 对于该变量的每个可能值,计算其权重。
- 不是直接选择最大权重的值,而是根据权重按比例采样一个值。例如,如果权重为 [1, 2, 2],则采样概率为 [1/5, 2/5, 2/5]。
- 用采样到的值更新该变量。
特点:长期运行后,高质量赋值出现的频率会更高。理论上,在极限情况下,全局最优解会成为最常出现的状态,但这并非保证,且严重依赖于初始状态。
条件独立性:图结构的威力 🕸️
现在,我们转向通过改变图结构本身来解决问题的方法。关键在于独立性。
什么是独立性?
如果两个变量之间没有路径相连(在因子图中即没有共享的因子),则它们是独立的。例如,澳大利亚地图着色问题中的塔斯马尼亚岛与其他州是独立的。
独立性的好处:独立变量可以分开单独优化。例如,有两个独立变量 x1 和 x2,各自有一个一元因子,那么最优解就是分别选择使各自因子值最大的赋值,时间复杂度是线性的 O(2),而不是穷举的 O(2^2)。
条件化:创造独立性
如果变量之间不独立,我们可以通过条件化来创造独立性。
条件化操作:
- 选择一个变量,并固定它的值为某个特定值(例如,
x2 = blue)。 - 将这个变量从图中移除。
- 所有与该变量相连的因子,都将其对应的参数替换为这个固定值,从而简化为作用于剩余变量的新因子。
效果:通过移除某些变量(称为“条件集”),原本相连的组件可能会变得独立。例如,在一个链 A -- C -- B 中,A 和 B 原本通过 C 相连。如果条件化 C(固定 C 的值并移除它),A 和 B 之间就没有连接了,它们变得条件独立。
数学表示:(A ⟂ B | C) 表示在给定 C 的条件下,A 和 B 独立。
马尔可夫毯
一个变量集的马尔可夫毯是指,当条件化这个集合后,该变量集与图中其余部分变得独立。它是图中分离该变量集所需的最小节点集合。
变量消元法:更高效的“条件化” ⚙️
条件化需要为条件变量的每个可能值都求解一次剩余问题。变量消元法更聪明:它在移除变量时,会动态地为该变量的每个邻居赋值组合选择最优值。
消元操作(以消除变量 Z 为例):
- 找出
Z的马尔可夫毯(所有与Z直接相连的变量)。 - 对于马尔可夫毯变量的每一种可能赋值组合:
- 计算
Z取不同值时,涉及Z的所有因子的乘积。 - 记录下能产生最大乘积的那个
Z的值,并将该最大乘积值作为新因子在这个赋值组合下的值。
- 计算
- 这样,我们得到了一个新的因子,其作用域是
Z的马尔可夫毯(不再包含Z),该因子内部已经“优化”掉了Z。 - 将
Z和与之相连的旧因子从图中移除,加入这个新因子。
与条件化的对比:
- 条件化:为
Z选一个固定值(如blue),然后传播。 - 消元法:对于邻居的每一种情况,都为
Z选择局部最优的值,并将这个选择“编码”进新因子中。
消元算法
- 顺序:选择一个变量消除顺序。
- 向前过程:按顺序对每个变量执行上述消元操作,直到图中只剩一个变量。该变量的一元因子值就代表了全局最优权重。
- 向后过程:根据向前过程中记录的信息(“回溯指针”),从最后一个变量开始,反向读出每个被消除变量的最优取值。
运行时间关键:消元过程中创建的最大因子的作用域大小(即其变量的个数,称为“元数”)。这决定了算法的复杂度,大约是 O(d^(w+1)),其中 d 是定义域大小,w 是消元过程中产生的最大因子元数减一。
变量顺序与树宽
- 变量顺序至关重要:好的顺序能产生元数小的因子,从而高效。一个启发式策略是优先消除邻居少的变量。
- 树宽:对于一个图,使用最优消元顺序所能得到的最小
w值,称为该图的树宽。树宽衡量了图的“类似树”的程度。- 链或树的树宽为 1。
- 环的树宽为 2。
n x n网格的树宽约为n。
- 计算最小树宽或最优消元顺序本身是 NP 难问题。
总结 🎯
本节课我们一起学习了多种解决约束满足问题的高级技术:
- 束搜索:通过维护多个候选部分赋值,在搜索速度和解的质量之间取得平衡。
- 局部搜索(ICM 和吉布斯采样):从完整赋值出发,通过局部修改进行优化。ICM 追求快速收敛,吉布斯采样利用随机性探索空间。
- 条件独立性:理解变量间的独立关系是加速求解的关键。条件化操作通过固定变量值来创造独立性。
- 变量消元法:一种系统性的精确算法,通过逐步消除变量并内部优化其取值,最终高效地找到全局最优解。算法的效率高度依赖于消元顺序和图的树宽。



这些方法为我们提供了从精确到近似、从全局到局部的一整套工具,以应对不同规模和结构的约束满足问题。


课程 P13:贝叶斯网络 1 - 推理 🧠
在本节课中,我们将要学习贝叶斯网络的基础知识。贝叶斯网络是一种强大的概率图模型,它允许我们以紧凑的方式表示复杂的联合概率分布,并在此基础上进行概率推理。我们将从概率基础回顾开始,逐步理解贝叶斯网络的定义、构建方法,以及如何将其与因子图联系起来。最后,我们会初步探讨如何进行概率推理。
概率基础回顾 📊
在深入贝叶斯网络之前,我们需要回顾一些核心的概率概念。这些概念是理解后续内容的基础。
随机变量 是值未知的变量。例如,Sunshine 和 Rain 可以是两个随机变量。
联合分布 描述了所有随机变量同时取特定值的概率。我们通常用 P(S, R) 表示,它是一个表格,为每个可能的变量赋值组合分配一个概率值。
边缘分布 是从联合分布中,通过对我们不关心的变量求和,推导出我们关心的变量子集的分布。例如,从 P(S, R) 得到 P(S) 的过程称为“边缘化”。
条件分布 描述了在已知某些证据(变量取值)的情况下,其他变量的概率分布。例如,P(S | R=1) 表示在已知下雨的条件下,天气是晴天的概率。计算时,我们选取联合分布中满足条件的行,然后进行归一化,使其概率和为1。
上一节我们回顾了概率的基本操作,本节中我们来看看如何用更结构化的方式——贝叶斯网络——来定义复杂的联合分布。
什么是贝叶斯网络? 🕸️
贝叶斯网络为我们提供了一种紧凑且直观的方式来定义高维联合概率分布,从而避免了直接列出所有可能组合(其数量是指数级的)的麻烦。

一个贝叶斯网络由两部分组成:
- 一个有向无环图:其中节点代表随机变量,有向边代表变量间的依赖或影响关系。
- 一组局部条件概率分布:每个节点都有一个条件概率表,描述在该节点父节点取特定值的条件下,该节点取各个值的概率。

网络的联合分布被定义为所有局部条件概率分布的乘积:
P(X1, X2, ..., Xn) = ∏ P(Xi | Parents(Xi))
这体现了“局部定义,全局优化”的思想:我们只需定义每个变量与其直接父节点的局部关系,整个系统的全局概率分布便自动生成。
构建贝叶斯网络:警报网络示例 🚨
让我们通过一个经典的“警报网络”例子,一步步学习如何构建贝叶斯网络。这个网络涉及入室盗窃、地震和警报器。
以下是构建贝叶斯网络的四个步骤:
步骤一:定义变量
确定模型中需要包含的随机变量。
B:入室盗窃发生(是/否)E:地震发生(是/否)A:警报响起(是/否)
步骤二:绘制图结构
根据变量间的因果关系或影响关系绘制有向边。
- 盗窃和地震都可能触发警报,因此
B和E指向A。 - 盗窃和地震本身被认为是独立的,因此
B和E之间没有边。
步骤三:定义局部条件概率分布
为每个节点给定其父节点的情况指定概率。
P(B):盗窃的先验概率,例如P(B=1) = ε(一个很小的数)。P(E):地震的先验概率,例如P(E=1) = ε。P(A | B, E):在已知盗窃和地震是否发生的情况下,警报响起的概率。例如,一个可靠的警报器在两者都不发生时几乎不误报,在任一发生时几乎必响。
步骤四:形成联合分布
整个网络的联合概率分布是上述所有局部分布的乘积:
P(B, E, A) = P(B) * P(E) * P(A | B, E)
通过这个定义好的联合分布,我们就可以回答各种概率查询。


贝叶斯网络与因子图 🔗
贝叶斯网络可以自然地转化为因子图,这有助于我们利用上一节课学到的推理算法。
转换规则很简单:每个局部条件概率分布 P(Xi | Parents(Xi)) 就对应因子图中的一个因子。该因子的作用域包含变量 Xi 及其所有父节点。
以警报网络为例:
- 变量
B对应因子fB(B) = P(B) - 变量
E对应因子fE(E) = P(E) - 变量
A对应因子fA(B, E, A) = P(A | B, E)
因此,贝叶斯网络的联合分布 P(B, E, A) 等价于因子图中所有权重因子的乘积。这种联系至关重要,因为它意味着我们可以使用变量消除、采样等因子图算法在贝叶斯网络上进行概率推理。
概率推理:我们想解决什么问题? ❓
拥有了贝叶斯网络定义的联合分布后,我们的核心任务就是进行概率推理。
概率推理通常遵循以下模式:在观察到一些证据(某些变量已知取值)后,计算我们对另一些查询变量的信念(概率分布)。
用公式表示就是计算:
P(查询变量 | 证据变量 = 观测值)
在警报网络例子中:
P(B):没有任何证据时,发生盗窃的概率(先验)。P(B | A=1):听到警报响后,发生盗窃的概率(后验)。直觉上,这个概率应该上升。P(B | A=1, E=1):听到警报响并且从广播得知地震后,发生盗窃的概率。直觉上,因为地震可以“解释”警报,所以盗窃的概率应该比仅听到警报时下降。这种现象称为“解释消除”。
通过精确的模型计算,我们可以验证或修正这些直觉。
贝叶斯网络的特性与概率程序 🖥️
贝叶斯网络有两个重要特性,源于其局部条件概率是规范的概率分布:
- 边缘化的一致性:如果从网络中边缘化掉一个叶节点(没有子节点的节点),得到的新分布正好对应于从原图中删除该节点及其入边后形成的简化贝叶斯网络。
- 条件分布的一致性:网络中定义的局部条件分布
P(X | Parents),与从整个联合分布通过概率规则推导出的条件分布P(X | Parents)是相同的。
此外,贝叶斯网络还可以用概率程序的思想来理解。概率程序是一段包含随机抽样的代码,每次运行都会根据定义的概率生成变量的一组赋值。多次运行就得到了联合分布的样本。
例如,警报网络可以写成:
B = draw from Bernoulli(ε)
E = draw from Bernoulli(ε)
A = B or E (以某种概率,模拟噪声)
这种视角有助于我们构思更复杂的模型,如隐马尔可夫模型、朴素贝叶斯分类器等,它们都可以看作是生成观测数据的“故事”。

推理计算策略 🧮

最后,我们探讨如何进行实际的概率推理计算。直接对联合分布求和或积分在变量多时是不可行的。我们需要利用图结构来简化计算。
一个通用的五步策略如下:
- 移除非祖先节点:查询变量和证据变量的非祖先节点可以提前被边缘化掉(从图中删除),因为它们不影响最终结果。
- 转换为因子图:将贝叶斯网络转化为因子图,便于统一处理。
- 处理证据:将证据(变量取值)代入,修改或固定相关的因子。
- 移除断开部分:删除图中与查询变量不再连接的部分。
- 执行计算:对剩余变量使用变量消除等算法进行求和,得到查询变量的分布。
我们通过马尔可夫链和警报网络中的简单查询例子演示了这个过程。在简单情况下,前四步可能直接给出答案;在复杂情况下,第五步需要系统化的计算。
总结 📝

本节课中我们一起学习了贝叶斯网络的基础。我们首先回顾了必要的概率知识,然后介绍了贝叶斯网络作为一种用有向图和局部条件概率来紧凑定义联合分布的方法。我们通过警报网络的例子详细讲解了构建步骤,并建立了贝叶斯网络与因子图之间的联系。接着,我们明确了概率推理的核心任务——在证据下计算查询变量的后验分布。我们还了解了贝叶斯网络的重要特性以及概率程序的建模视角。最后,我们初步接触了利用图结构进行有效推理的计算策略。在下一讲中,我们将更深入地探讨自动执行这些推理的算法。



课程 P14:贝叶斯网络 2 - 前向-后向算法 🧠
在本节课中,我们将继续学习贝叶斯网络,并重点探讨如何高效地进行概率推断。我们将介绍两种核心算法:用于隐马尔可夫模型精确推断的前向-后向算法,以及用于大规模或连续状态空间近似推断的粒子滤波算法。最后,我们还会从概率推断的角度重新审视吉布斯采样。
贝叶斯网络回顾
上一节我们介绍了贝叶斯网络的基本概念。它是一种通过有向无环图表示变量间依赖关系的概率模型。每个节点代表一个随机变量,每条边表示依赖关系。每个变量都有一个局部条件概率分布,给定其父节点的取值。将所有局部条件概率分布相乘,就得到了所有变量的联合概率分布。
贝叶斯网络可以看作因子图与概率的结合,它允许我们紧凑地定义涉及大量随机变量的复杂联合分布。概率推断的任务是:给定一个贝叶斯网络(即我们对世界的知识模型)和一些观察到的证据,计算我们感兴趣的查询变量在给定证据下的条件概率。
隐马尔可夫模型
本节中,我们来看看一种特殊的贝叶斯网络——隐马尔可夫模型。HMM包含一个隐藏状态变量序列和一个对应的观测变量序列。
模型定义:
- 初始分布:
P(H_1),表示第一个隐藏状态的概率。 - 转移分布:
P(H_i | H_{i-1}),表示当前隐藏状态如何依赖于前一个状态。 - 发射分布:
P(E_i | H_i),表示当前观测值如何依赖于当前隐藏状态。
所有变量的联合概率分布为这些分布的乘积:
P(H, E) = P(H_1) * ∏_{i=2}^n P(H_i | H_{i-1}) * ∏_{i=1}^n P(E_i | H_i)
在HMM中,我们主要关心两类推断问题:
- 滤波:计算
P(H_t | E_1=e_1, ..., E_t=e_t)。这相当于实时估计当前状态。 - 平滑:计算
P(H_t | E_1=e_1, ..., E_n=e_n)。这相当于利用所有过去和未来的观测数据来估计过去某一时刻的状态。
我们将重点讨论平滑问题,因为一旦能解决平滑问题,滤波问题也可以通过边缘化未来变量来解决。


格架表示与前向-后向算法
为了高效计算平滑概率,我们引入格架表示法。格架的每一列对应一个时间步的隐藏变量 H_i,每一行对应 H_i 的一个可能取值。从起点到终点的一条路径,就对应隐藏变量序列的一种完整赋值。
构建加权格架:
- 将初始概率
P(H_1)和第一个发射概率P(E_1 | H_1)的乘积,赋给从起点到第一个状态节点的边。 - 将转移概率
P(H_i | H_{i-1})和发射概率P(E_i | H_i)的乘积,赋给连接H_{i-1}和H_i的边。 - 终点边的权重设为1。
这样,任意路径的权重就是路径上所有边权重的乘积,它正比于该路径对应的完整赋值(包含观测证据)的联合概率。
我们的目标是计算所有经过特定节点(例如 H_t = v)的路径权重之和,然后除以所有路径的权重之和,从而得到平滑概率 P(H_t = v | 所有证据)。直接求和是指数级的,我们需要动态规划。
前向-后向算法通过传递两种消息来高效计算:
- 前向消息
F_i(v):从起点到节点(i, v)的所有部分路径的权重之和。- 计算公式:
F_i(v) = ∑_{u} [F_{i-1}(u) * P(H_i=v | H_{i-1}=u) * P(E_i | H_i=v)]
- 计算公式:
- 后向消息
B_i(v):从节点(i, v)到终点的所有部分路径的权重之和。- 计算公式:
B_i(v) = ∑_{w} [P(H_{i+1}=w | H_i=v) * P(E_{i+1} | H_{i+1}=w) * B_{i+1}(w)]
- 计算公式:


对于每个节点 (i, v),经过它的所有完整路径的权重之和 S_i(v) 恰好是前向和后向消息的乘积:S_i(v) = F_i(v) * B_i(v)。
算法步骤:
- 前向传递:从
i=1到n,计算所有F_i(v)。 - 后向传递:从
i=n到1,计算所有B_i(v)。 - 计算平滑分布:对于每个时间步
i和每个值v,计算S_i(v),然后归一化得到P(H_i = v | 所有证据)。
该算法的时间复杂度为 O(n * K^2),其中 n 是时间步数,K 是隐藏状态的可能取值数。它一次性计算了所有时间步的平滑分布。

粒子滤波算法

前向-后向算法在状态空间 K 很大时(例如物体跟踪在连续或大网格空间),K^2 的计算成本可能过高。此外,许多状态的概率实际接近于零,全部计算是浪费的。粒子滤波是一种适用于大规模状态空间的近似滤波算法。
粒子滤波维护一组称为粒子的样本,每个粒子代表隐藏状态序列的一种可能轨迹(或仅当前状态)。它通过三个步骤迭代更新粒子集:
以下是粒子滤波的三个核心步骤:
- 提议:根据当前粒子的状态
H_{t-1},利用转移模型P(H_t | H_{t-1})采样出下一个状态H_t,从而将每个粒子向前扩展一步。 - 加权:获得新的观测
E_t后,根据发射模型P(E_t | H_t)为每个粒子计算一个权重。权重反映了该粒子与当前观测的吻合程度。 - 重采样:根据粒子的权重进行有放回地采样,生成一个新的粒子集合。权重高的粒子更可能被多次选中,权重低的粒子可能被淘汰。这确保了粒子群集中在高概率区域。
粒子滤波直观上就像用一群“粒子”来模拟和追踪物体的可能位置。随着时间推进和观测更新,粒子群会逐渐聚集到物体最可能出现的区域。
与束搜索相比,粒子滤波的采样步骤引入了随机性,有助于维持假设的多样性,避免过早陷入局部最优。
吉布斯采样用于概率推断
现在,让我们从概率推断的角度重新审视吉布斯采样。之前我们将其用于在因子图中寻找高分赋值。实际上,如果我们将因子图的权重归一化为一个概率分布,吉布斯采样可以用于从该分布中生成样本。


算法流程:
- 随机初始化所有变量的赋值。
- 循环多次:
- 依次选取每个变量
X_i。 - 固定其他所有变量的当前取值,计算
X_i取每一个可能值的条件概率:P(X_i | 所有其他变量)。这个概率正比于所有涉及X_i的因子在其邻居变量当前取值下的乘积。 - 根据这个条件概率分布,为
X_i采样一个新值。
- 依次选取每个变量
在满足一定条件(如遍历性)下,经过足够次数的迭代后,吉布斯采样产生的样本会近似服从目标联合概率分布。通过收集大量样本,我们可以近似计算任意变量的边际分布或期望。
应用示例:图像去噪
- 模型:将图像像素建模为二值变量网格。相邻像素间有一个因子,鼓励它们取值相同(平滑先验)。部分像素被观测(噪声图像),这些观测作为固定值的因子。
- 推断:对未观测像素运行吉布斯采样。每次迭代,根据相邻像素的当前值和观测(如果有),更新一个像素的值。经过多次迭代后,采样结果或像素的边际概率(取平均)可以给出一个去噪后的图像。
总结
本节课我们一起学习了贝叶斯网络中的概率推断算法。
- 对于具有链式结构的隐马尔可夫模型,前向-后向算法能提供精确且高效的平滑推断。
- 当状态空间很大时,粒子滤波通过维护一组加权样本进行近似滤波,特别适用于跟踪等问题。
- 对于一般的图模型,吉布斯采样是一种通用的近似推断方法,通过从条件分布中采样来逼近联合分布。

这些算法与我们之前学过的概念有紧密联系:前向-后向类似于变量消除,粒子滤波类似于束搜索,而吉布斯采样则是其随机优化版本的直接应用。下一节课,我们将探讨如何从数据中学习贝叶斯网络的参数。


课程 P15:贝叶斯网络 3 - 最大似然估计 📊
在本节课中,我们将学习贝叶斯网络中的参数学习问题,特别是当所有变量都被观测到时(监督学习)以及当部分变量未被观测到时(无监督学习)的情况。我们将从直观的“计数与归一化”方法入手,逐步理解其背后的最大似然原理,并介绍拉普拉斯平滑与期望最大化算法。
公告与回顾 📢
在深入贝叶斯网络之前,先宣布几项事宜。作业将于明天截止,项目进展报告将于周四截止。最重要的考试安排在下周二。考试将涵盖从课程开始到本节课(包括贝叶斯网络)的所有内容,但不包括逻辑部分。复习课将在本周四和周六进行。所有补考安排已确定,如有特殊情况请立即与我们沟通。请注意,考试题目与作业题目有所不同,更侧重于问题解决能力,最佳备考方式是练习往届试题。
上一节我们介绍了贝叶斯网络的概率推断算法。本节中,我们来看看如何从数据中学习网络的参数。
学习问题概述 🔍
学习问题的核心是:模型的参数从何而来?在贝叶斯网络中,参数指的是定义每个变量在其父变量条件下的局部条件概率分布。我们假设这些参数是未知的,需要从数据中推断出来。
我们将从最简单的监督学习(所有变量都被观测到)开始,然后过渡到更具挑战性的无监督学习(部分变量未被观测到)。
监督学习:计数与归一化 🧮

在监督学习设置下,我们拥有完整的训练数据,即每个数据点都是对所有变量的一个完整赋值。参数学习的直观方法是“计数与归一化”。

单变量网络

考虑最简单的贝叶斯网络,仅包含一个表示电影评级的变量 R,其取值为1到5。参数就是 P(R=1), P(R=2), ..., P(R=5) 这五个概率。




给定训练数据 [1, 3, 4, 4, 4, 4, 4, 5, 5, 5],我们进行如下操作:
- 计数:统计每个评级值出现的次数。
count(R=1) = 1count(R=2) = 0count(R=3) = 1count(R=4) = 5count(R=5) = 3
- 归一化:将每个计数除以总数据点数(10),得到概率估计。
P(R=1) = 1/10 = 0.1P(R=2) = 0/10 = 0P(R=3) = 1/10 = 0.1P(R=4) = 5/10 = 0.5P(R=5) = 3/10 = 0.3


多变量网络与参数共享
对于更复杂的网络,我们为每个局部条件分布独立地进行“计数与归一化”。关键在于理解参数共享的概念:网络中的多个变量可以由同一个条件分布表“驱动”。
例如,在朴素贝叶斯模型中,有一个类别变量 Y 和多个词变量 W1, W2, ..., WL。所有词变量 Wi 都共享同一个条件分布 P_word(W | Y),尽管它们对应不同的位置。


在隐马尔可夫模型中,存在三种类型的分布:
P_start(H):驱动初始状态H1。P_trans(H' | H):驱动所有状态转移(H_{i-1} -> H_i)。P_emit(E | H):驱动所有发射状态(H_i -> E_i)。
通过参数共享,我们可以用少量参数定义包含大量变量的模型。
最大似然原理:为何“计数与归一化”有效? 🤔
“计数与归一化”并非随意为之,其背后是最大似然估计 这一统计原理。该原理主张:应选择能使观测到的数据出现概率最大的参数。
公式:对于参数 θ 和数据集 D,最大似然估计为:
θ_MLE = argmax_θ P(D | θ)

可以证明,在数据完全观测且满足贝叶斯网络条件独立结构的假设下,分别对每个局部条件分布进行“计数与归一化”,所得结果正是全局联合分布的最大似然估计。这使得参数学习在监督场景下非常高效。



拉普拉斯平滑:应对零概率问题 ⚖️
最大似然估计的一个问题是过拟合。例如,抛硬币一次得到正面,MLE会得出 P(正面)=1,这显然不合理。拉普拉斯平滑通过添加“伪计数”来解决此问题。
方法:在计数时,为每个可能的事件预先加上一个小的常数 λ(通常为1),然后再进行归一化。


公式(以单变量为例):
P(X=x) = (count(x) + λ) / (N + λ * K)
其中 N 是总样本数,K 是变量 X 可能取值的个数。

拉普拉斯平滑可以理解为引入了均匀先验的贝叶斯估计,它防止了概率估计为0,并使估计在数据量较小时更趋向于均匀分布。


无监督学习:期望最大化算法 🌀

当数据中部分变量(隐变量)未被观测时,我们无法直接计数。此时需要采用期望最大化算法。
EM算法通过迭代以下两步来解决这个“鸡生蛋蛋生鸡”的问题:
- E步(期望步):基于当前参数估计,计算隐变量在给定观测数据下的后验分布
Q(H)。这本质上是一个概率推断问题,可以使用前向-后向算法、吉布斯采样等方法。 - M步(最大化步):将E步得到的后验分布
Q(H)视为“软”赋值或权重,构造一个加权的完整数据集,然后在此数据集上执行最大似然估计(即“计数与归一化”),更新参数。
算法从随机初始化参数开始,交替进行E步和M步,直至收敛。
实例:破译替换密码
EM算法的一个有趣应用是破译替换密码。我们将明文视为隐状态序列,密文视为观测序列,利用一个已知的英文语言模型(转移概率 P_trans)和待学习的替换表(发射概率 P_emit),构建一个隐马尔可夫模型。
通过运行EM算法,我们可以同时估计出替换表和对密文进行解码。虽然结果可能不完美,但算法能够从乱码中捕捉到语言结构信息,为最终破译提供有力线索。
总结 📝
本节课我们一起学习了贝叶斯网络的参数学习。
- 在监督学习中,对于完全观测的数据,我们可以通过直观的“计数与归一化”方法高效地获得参数的最大似然估计。
- 拉普拉斯平滑是一种简单有效的技术,用于避免零概率估计并缓解过拟合。
- 在无监督学习中,当存在未观测变量时,我们使用期望最大化算法。该算法迭代地进行概率推断(E步)和参数最大化(M步),是解决此类潜在变量模型学习问题的强大工具。



通过理解这些核心概念,你便掌握了贝叶斯网络从建模、推断到学习的完整流程。


课程 P16:第 16 讲 逻辑 1 - 命题逻辑 🧠
在本节课中,我们将要学习逻辑的基础知识,特别是命题逻辑。我们将从定义逻辑的基本组成部分开始,包括语法、语义和推理规则,并探讨如何利用逻辑进行知识表示和推理。
概述 📖
逻辑是人工智能中一个强大的建模范式,它允许我们以精确和简洁的方式表达复杂知识。本节课将系统性地介绍命题逻辑,这是一种基于命题符号及其连接词的形式化语言。我们将学习如何构建逻辑公式,如何为这些公式赋予含义,以及如何利用推理规则从已知知识中推导出新结论。
逻辑的动机与背景
在课程开始时,我们回顾了本课程所涵盖的建模范式。我们学习了基于状态的模型(如搜索问题、MDP和博弈)和基于变量的模型(如约束满足问题和贝叶斯网络)。本节课,我们将转向基于逻辑的模型。
历史上,逻辑在20世纪90年代之前是人工智能的主导范式。虽然现代AI更侧重于处理不确定性和从数据中学习,但逻辑在表达复杂概念方面的简洁性和精确性是其独特优势。逻辑允许我们构建能够进行深度推理的系统,而不仅仅是进行模式匹配。

逻辑语言:语法与语义

要定义一个逻辑语言,我们需要明确三个核心组成部分:语法、语义和推理规则。
语法:定义有效的表达式


语法规定了在逻辑语言中,哪些表达式是有效的或合乎语法的。
在命题逻辑中,我们有以下基本元素:
- 命题符号:通常是大写字母或单词,如
A、Rain、Wet。它们是原子公式,不可再分。 - 逻辑连接词:包括
¬(非)、∧(与)、∨(或)、⇒(蕴含)、⇔(双向蕴含)。 - 公式:通过递归方式构建。如果
F和G是公式,那么以下也是公式:¬FF ∧ GF ∨ GF ⇒ GF ⇔ G
示例:
A是公式。¬A是公式。(¬B) ⇒ C是公式。A ∧ ¬B不是公式(缺少连接词)。A + B不是公式(+不是有效连接词)。


语义:为表达式赋予含义
语义定义了每个公式在特定情境下的意义。这通过解释函数来实现。
首先,我们定义模型(在逻辑文献中,也称为“世界”)。在命题逻辑中,模型是对所有命题符号的真值赋值。例如,对于命题符号 A、B、C,一个可能的模型是 {A: 真, B: 假, C: 假}。
解释函数 I(F, w) 接收一个公式 F 和一个模型 w,返回 真 或 假,表示公式 F 在模型 w 下是否为真。
解释函数的定义是递归的:
- 原子公式:
I(P, w)就是查找模型w中命题符号P的值。 - 复合公式:基于子公式的解释,通过真值表定义。
I(F ∧ G, w) = 真当且仅当I(F, w) = 真且I(G, w) = 真。I(F ∨ G, w) = 真当且仅当I(F, w) = 真或I(G, w) = 真。I(F ⇒ G, w) = 真当且仅当I(F, w) = 假或I(G, w) = 真。I(F ⇔ G, w) = 真当且仅当I(F, w) = I(G, w)。I(¬F, w) = 真当且仅当I(F, w) = 假。

示例:
对于公式 (¬A ∧ B) ⇔ C 和模型 {A: 真, B: 真, C: 假}:
I(A, w) = 真I(¬A, w) = 假I(B, w) = 真I(¬A ∧ B, w) = 假I(C, w) = 假I((¬A ∧ B) ⇔ C, w) = 真(因为假 ⇔ 假为真)

知识库与模型集合
一个有用的视角是将一个公式 F 视为其所有为真的模型所构成的集合,记作 M(F)。公式的含义就是它在所有可能世界(模型)中划出的一个子集。
知识库 是一组公式的集合,代表已知的事实。知识库 KB 所表示的模型集合 M(KB),是其中所有公式模型集合的交集。随着你向知识库中添加新公式,可能的模型集合会不断缩小,这代表你的知识越来越精确。


知识操作:告知与询问
给定一个知识库 KB 和一个新公式 F,它们之间的关系有三种可能:
- 蕴含:
KB ⊨ F。这意味着M(KB)是M(F)的子集。F没有提供新信息。例如,已知“下雨且下雪”,再被告知“下雪”。 - 矛盾:
KB和F矛盾。这意味着M(KB) ∩ M(F) = ∅。F与现有知识冲突。例如,已知“下雨且下雪”,再被告知“没下雪”。 - 偶然性:
F为知识库增加了非平凡的新信息。M(KB) ∩ M(F)既非空集,也非M(KB)本身。例如,已知“下雨”,再被告知“也下雪”。
基于这些关系,我们可以定义虚拟助理的两种基本操作:
- 告知:当用户陈述一个事实
F时,系统根据关系做出响应(“已知”、“不信”或“学习到新知识”)。 - 询问:当用户提出一个是否问题
F时,系统根据关系回答(“是”、“否”或“不知道”)。
可满足性与模型检验
可满足性 是一个关键概念:一个知识库 KB 是可满足的,当且仅当 M(KB) 非空(即不存在内部矛盾)。
我们可以将“询问”和“告知”操作都归结为检查可满足性问题。例如,要判断 KB ⊨ F(蕴含)是否成立,只需检查 KB ∪ {¬F} 是否不可满足。因为 KB ⊨ F 等价于 KB 与 ¬F 矛盾。
在命题逻辑中,检查可满足性(SAT问题)本质上是一个约束满足问题:命题符号对应变量,公式对应约束。我们可以使用回溯搜索(如DPLL算法)或随机局部搜索(如WalkSAT算法)来寻找一个满足所有约束的赋值(模型),这个过程称为模型检验。
推理规则:在语法层面操作

上一节我们介绍了在语义层面通过模型检验进行推理。本节我们来看看如何在语法层面,通过应用推理规则来直接操作公式,从而推导出新知识。

推理规则的形式为:前提1, 前提2, ..., 前提k / 结论。如果知识库中包含所有前提,就可以将结论添加到知识库中。

最著名的推理规则是肯定前件:
P, P ⇒ Q
---------
Q
例如,从“下雨”和“如果下雨则地湿”,可以推出“地湿”。

应用一组推理规则不断推导新公式的过程,称为证明。如果从知识库 KB 能通过推理规则推导出公式 F,我们记作 KB ⊢ F。
这里出现了两个关键概念:
KB ⊨ F(语义蕴含):由模型关系定义,关注含义。KB ⊢ F(语法证明):由推理规则定义,关注符号操作。
理想情况下,我们希望推理规则既是可靠的(Sound),又是完备的(Complete)。
- 可靠性:如果
KB ⊢ F,那么KB ⊨ F。即推导出的结论都是语义上正确的(“只包含真理”)。 - 完备性:如果
KB ⊨ F,那么KB ⊢ F。即所有语义上正确的结论都能被推导出来(“包含所有真理”)。
肯定前件规则是可靠的,但对于完整的命题逻辑来说,它并不完备。
霍恩子句与肯定前件的完备性
为了使肯定前件规则变得完备,我们需要对逻辑公式的形式加以限制。我们引入霍恩子句。
定式子句 是形如 (P₁ ∧ P₂ ∧ ... ∧ Pₖ) ⇒ Q 的公式,其中右边是单个命题符号。
目标子句 是形如 (P₁ ∧ P₂ ∧ ... ∧ Pₖ) ⇒ False 的公式,等价于 ¬(P₁ ∧ P₂ ∧ ... ∧ Pₖ)。
霍恩子句就是定式子句或目标子句。
对于只包含霍恩子句的知识库,肯定前件规则是可靠且完备的。这意味着,如果一个命题符号 Q 在语义上被知识库蕴含(KB ⊨ Q),那么通过反复应用肯定前件规则,一定能在语法上证明它(KB ⊢ Q)。
示例推理过程:
知识库:{Rain, Rain ⇒ Wet, (Wet ∧ Weekday) ⇒ Traffic, Weekday}
询问:Traffic?
- 匹配
Rain和Rain ⇒ Wet,推出Wet。 - 匹配
Wet、Weekday和(Wet ∧ Weekday) ⇒ Traffic,推出Traffic。
推导成功,回答“是”。
总结 🎯
本节课我们一起学习了命题逻辑的基础。
- 我们介绍了逻辑的三大要素:语法(定义公式)、语义(通过模型和解释函数赋予含义)和推理规则(进行语法推导)。
- 我们学习了如何用公式表示知识,以及知识库与公式之间的蕴含、矛盾和偶然性关系。
- 我们探讨了通过可满足性检查(模型检验)进行语义推理,以及通过推理规则(如肯定前件)进行语法推理这两种途径。
- 最后,我们看到了在霍恩子句这一受限但有用的语言片段中,肯定前件规则既能保证可靠性,又能保证完备性,实现了语义与语法推理的等价。

逻辑为我们提供了一种强大而精确的知识表示和推理工具。在下节课中,我们将学习更强大的推理规则(如归结原理),以处理更一般的命题逻辑公式。



课程 P17:一阶逻辑 🧠



在本节课中,我们将学习一阶逻辑。我们将首先回顾命题逻辑,特别是归结推理规则,然后深入探讨一阶逻辑的语法、语义和推理规则。一阶逻辑通过引入对象、谓词和量词,极大地增强了我们表达和推理世界知识的能力。
公告与工具介绍 📢
在进入逻辑主题之前,有一些课程相关的公告。考试将在明天进行。下周是感恩节假期,因此没有课程和讨论课。假期结束后的周一,将有一个海报展示环节。
此外,我想花几分钟介绍一个名为 Codal Lab Worksheets 的平台。这是一个旨在帮助人们以更高效、可复现的方式进行研究的工具。对于本课程,使用该平台可以获得额外学分,并且它还能提供额外的计算资源。
Codal Lab 的工作表类似于 Jupyter Notebook。你可以在其中编写文本、上传代码或数据。每个资源(数据或代码)在 Codal Lab 中被称为一个“包”。你可以运行命令、指定依赖项、监控作业进度,并将所有实验资产(数据、代码、结果)以可追溯的方式记录下来。
回顾:命题逻辑与推理 🔙
上一节我们介绍了逻辑。任何逻辑系统都包含三个要素:语法、语义和推理规则。
- 语法:定义一组有效的公式。例如,在命题逻辑中,
rain ∧ wet是一个公式。公式本身只是符号,没有内在含义。 - 语义:通过解释函数为公式赋予含义。它将一个公式和一个代表世界状态的模型映射为真或假。更一般地说,一个公式划定了一组使其为真的模型集合。
- 推理规则:给定一个知识库(一组公式),可以推导出哪些新公式。
我们讨论了蕴涵和推导这两个概念。蕴涵是语义上的关系:知识库 KB 蕴涵公式 F,当且仅当所有使 KB 为真的模型也使 F 为真。推导则是符号操作:使用一组推理规则从 KB 产生 F。

推理规则的关键属性是可靠性和完备性。
- 可靠性:所有能推导出的公式都是被蕴涵的(推导不会出错)。
- 完备性:所有被蕴涵的公式都能被推导出来(推导能力足够强)。


我们之前看过的肯定前件推理规则如下:
如果已知 `A` 和 `A → B`,则可以推导出 `B`。
在命题逻辑中,仅使用肯定前件规则是可靠的,但对于完整的命题逻辑来说并不完备。



归结推理规则 ⚙️
为了处理完整的命题逻辑,我们需要更强大的推理规则。本节我们将介绍归结规则。
首先,我们回顾一些概念和恒等式,它们有助于将公式转化为更适合归结的形式。
- 文字:一个命题符号或其否定。
- 子句:文字的析取(用
∨连接)。 - 霍恩子句:至多含有一个正文字的子句。
利用恒等式 p → q ≡ ¬p ∨ q,我们可以将蕴含式写为子句形式。例如,A → C 等价于 ¬A ∨ C。
归结规则是命题逻辑中一个强大且完备的推理规则。它的基本形式是:如果两个子句中包含互补的文字,就可以消去它们,并将其余部分合并。
已知:`P ∨ A1 ∨ ... ∨ Am`
已知:`¬P ∨ B1 ∨ ... ∨ Bn`
可推导:`A1 ∨ ... ∨ Am ∨ B1 ∨ ... ∨ Bn`
直观理解:你知道 P 或一些其他事实成立,同时你也知道 ¬P 或另一些事实成立。那么,P 和 ¬P 不可能同时为假,因此 A1... 或 B1... 中至少有一组必须成立。
为了对任意命题逻辑公式使用归结,我们需要先将所有公式转换为合取范式。
- CNF:子句的合取(用
∧连接)。每个子句是文字的析取。
转换到 CNF 的一般步骤如下:
- 消去双向蕴含
↔和蕴含→。 - 将否定
¬向内移动,直至只作用于命题符号(使用德摩根定律)。 - 消除双重否定。
- 必要时,使用分配律将析取
∨分配到合取∧内部。
归结算法通常采用反证法。要证明 KB ⊨ F:
- 将
¬F加入知识库KB。 - 将
KB ∪ {¬F}中的所有公式转换为 CNF。 - 反复应用归结规则。
- 如果能推导出空子句(代表
False),则说明KB ∪ {¬F}不可满足,从而证明KB ⊨ F。
需要注意的是,虽然归结对于命题逻辑是完备的,但其时间复杂度在最坏情况下是指数级的。相比之下,仅用于霍恩子句的肯定前件推理是线性时间的,但表达能力受限。
引入一阶逻辑 🚀
命题逻辑有什么问题?它对于表达丰富的世界知识可能显得笨拙或力不从心。例如:
- “Alice 和 Bob 都懂算术” 尚可表示为
Knows(Alice, Arithmetic) ∧ Knows(Bob, Arithmetic)。 - “所有学生都懂算术” 在命题逻辑中就需要为每个学生写一条规则,无法简洁表达。
- “每个大于2的偶数都可以写成两个素数之和” 这类涉及无穷域和存在性断言的陈述,命题逻辑几乎无法处理。
问题的核心在于,命题逻辑将每个原子事实视为不可分割的符号。而一阶逻辑引入了内部结构:
- 对象:如 Alice, Arithmetic。
- 谓词:描述对象间的关系或属性,如
Knows(x, y)。 - 量词:如
∀(对所有)和∃(存在)。
这使得我们可以简洁地表达通用规则,例如:
∀x (Student(x) → Knows(x, Arithmetic))

一阶逻辑:语法与语义 📖


一阶逻辑的语法包含两种类型的表达式:项和公式。



项指代对象:
- 常元符号:如
Alice。 - 变量:如
x。 - 函数作用于项:如
fatherOf(John)。
公式具有真值:
- 原子公式:谓词作用于项,如
Knows(x, Arithmetic)。它是构成更复杂公式的基本单位。 - 复合公式:使用连接词
¬、∧、∨、→、↔连接原子公式构成,就像在命题逻辑中一样。 - 量化公式:在公式前加上量词,如
∀x P(x)或∃y Q(y)。
量词是一阶逻辑的核心:
∀x P(x):对所有x,P(x)为真。可视为一个巨大的合取。∃x P(x):存在某个x,使得P(x)为真。可视为一个巨大的析取。- 量词的顺序很重要:
∀x ∃y Loves(x, y)与∃y ∀x Loves(x, y)含义不同。 - 否定穿过量词时遵循规则:
¬∀x P(x) ≡ ∃x ¬P(x),¬∃x P(x) ≡ ∀x ¬P(x)。
将自然语言翻译为一阶逻辑时,一个经验法则是:∀ 通常与 → 搭配,∃ 通常与 ∧ 搭配。
- “每个学生都懂算术”:
∀x (Student(x) → Knows(x, Arithmetic)) - “某个学生懂算术”:
∃x (Student(x) ∧ Knows(x, Arithmetic))
一阶逻辑的语义(模型)比命题逻辑复杂。一个模型需要:
- 定义一个论域(所有可能对象的集合)。
- 为每个常元符号指定论域中的一个对象。
- 为每个谓词符号指定其在论域上的一组关系(哪些对象元组使该谓词为真)。
- 为每个函数符号指定论域上的一个函数。
为了简化,有时会做两个假设:唯一命名假设(不同名称指代不同对象)和域封闭假设(每个对象都有一个名称)。在此假设下,如果论域有限,一阶逻辑知识库可以通过命题化转换为一个等价的(可能很大的)命题逻辑知识库,从而可以使用命题逻辑的推理方法。
一阶逻辑中的推理 🧩
本节我们探讨一阶逻辑中的推理规则。我们将看到,核心思想是通过替换和合一来处
理变量。
首先看一阶霍恩子句和肯定前件的推广。一阶霍恩子句(或称定子句)形式如下:
∀x1,...,xk (A1 ∧ ... ∧ An → B)
其中 Ai 和 B 是原子公式。
简单的肯定前件规则 A, A→B ⊢ B 在一阶逻辑中不能直接应用,因为 A 和规则中的前件可能形式不完全匹配。例如,已知 Knows(Alice, Arithmetic) 和规则 ∀x (Knows(x, Arithmetic) → GoodAtMath(x)),我们需要将规则中的变量 x 替换为 Alice 才能应用。
这引出了两个关键操作:
- 替换:将公式中的变量映射到项。记作
θ = {x/Alice, y/z},应用θ到公式F得到Fθ。 - 合一:找到一种替换,使两个公式变得相同。例如,合一
Knows(Alice, y)和Knows(x, Arithmetic)得到替换{x/Alice, y/Arithmetic}。
现在,一阶肯定前件规则可以表述为:
已知:`A1'`, ..., `Ak'` (具体事实)
已知:`∀x1,...,xm (A1 ∧ ... ∧ Ak → B)` (通用规则)
如果存在替换 `θ` 使得对于每个 `i`,`Aiθ = Ai'`,则可推导出 `Bθ`。
直观理解:用具体事实去匹配通用规则的前件,找到变量应该如何实例化,然后得到相应的结论。
如果没有函数符号,且常元数量有限,这种推理可能在有限步内终止(尽管可能产生大量公式)。但如果存在函数符号,可能产生无限多的新原子公式,导致推理过程是半可判定的:如果公式被蕴涵,算法最终能证明它;如果不被蕴涵,算法可能永远运行下去。
对于完整的一阶逻辑(包含非霍恩子句),我们需要使用一阶归结。策略与命题逻辑类似:
- 将所有公式(包括待证公式的否定)转换为 CNF。这个转换过程更复杂,需要处理量词,特别是要将存在量词
∃通过引入斯柯伦函数来消除。 - 反复应用归结规则,并配合合一操作。
一阶归结规则如下:
已知子句:`L1 ∨ ... ∨ Lm`,其中包含文字 `P`
已知子句:`M1 ∨ ... ∨ Mn`,其中包含文字 `¬Q`
如果 `P` 和 `Q` 可以合一,即存在替换 `θ` 使得 `Pθ = Qθ`,
则可推导出:`(L1 ∨ ... ∨ Li-1 ∨ Li+1 ∨ ... ∨ Lm ∨ M1 ∨ ... ∨ Mj-1 ∨ Mj+1 ∨ ... ∨ Mn)θ`
直观理解:找到两个子句中可合一的一对互补文字,消去它们,并将替换应用于合并后的剩余部分。
总结与回顾 🎯
本节课我们一起学习了从命题逻辑到一阶逻辑的进阶。
我们首先回顾了命题逻辑中的归结规则,它是一种强大且完备的推理方法,但计算成本较高。作为对比,肯定前件规则在霍恩子句片段上是高效且完备的,但表达能力有限。
然后,我们探讨了一阶逻辑,它通过引入项、谓词和量词,极大地提升了知识表示的简洁性和表达能力。一阶逻辑的公式具有丰富的内部结构。
在一阶逻辑推理中,我们介绍了处理变量的关键技术:替换和合一。基于此,我们推广了肯定前件规则用于一阶霍恩子句,并介绍了一阶归结规则用于完整的一阶逻辑。
关键的要点是:
- 逻辑提供了表达复杂知识的严谨语言。
- 一阶逻辑中的变量和量词是实现简洁而强大表达的核心。
- 尽管一阶逻辑的推理(特别是包含函数符号时)是半可判定的,但其理论框架和算法(如归结)为自动化推理奠定了基础。


从实践角度看,可以根据需求选择不同的逻辑“套餐”:追求效率可选择霍恩子片段的肯定前件推理;需要更强表达能力时,则需承担归结等更复杂推理机制的计算成本。


深度学习课程 P18:深度学习入门 🧠
在本节课中,我们将学习深度学习的基础知识。我们将从历史背景开始,了解其发展脉络,然后深入探讨前馈神经网络、卷积神经网络、循环神经网络以及无监督学习等核心概念。课程旨在为初学者提供一个全面而浅显的概览,为后续深入学习打下基础。

历史背景 📜
上一节我们介绍了课程概述,本节中我们来看看深度学习的发展历史。深度学习近年来非常流行,但其历史可以追溯到很久以前。

早在20世纪40年代,人们就开始尝试构建计算神经科学模型。他们注意到大脑中的神经元以网络形式排列,并认为智能源于这些微小的部分。因此,他们非常希望对此进行建模。
- McCulloch 和 Pitts 是真正开始这项工作的人。Pitts是一位逻辑学家,他们关注的是用网络拓扑结构构建逻辑电路,研究网络能实现何种逻辑表达式。
- 当时这只是一个数学模型,没有反向传播,没有参数,也没有推理,主要是尝试撰写关于这些结构能解决何种问题的定理和证明。
- 大约十年后,Hebb 出现,并开始将研究方向引向训练这些网络。他注意到,如果两个细胞经常一起激活,那么它们之间应该存在某种强连接。这是受观察启发,当时并没有正式的数学理论支持,很多只是非常聪明的人的猜想。
- 直到20世纪60年代,神经网络可以说进入了主流,很多人都在思考并对此感到兴奋。但在1969年,Minsky 和 Papert 出版了著名的《Perceptrons》一书,其中包含大量证明。他们基本上证明了浅层神经网络的局限性。
- 当时,这对神经网络研究是一个不小的打击。主流AI变得更加偏向逻辑,而神经网络则被推向了少数派群体。虽然仍有人在思考和研究,但主流AI无疑转向了Percy过去几周讨论的基于符号逻辑的方法。
- 尽管如此,仍有人在幕后继续工作。例如,1974年,Werbos 提出了反向传播的思想,即使用链式法则自动更新权重以改进预测。
- 后来,Hinton、Rumelhart 和 Williams 普及了这一方法。他们重新发现了Werbos的成果,并告诉大家可以使用反向传播,这是一种数学上合理、理论基础良好的训练深度神经网络的方法。
- 在20世纪80年代,卷积神经网络可以追溯到这一时期。日本的Fukushima发明了“Neocognitron”,为CNN架构奠定了基础,但当时没有训练方法。在论文中,他们使用了手动调整的权重。
- 大约十年后,LeCun 出现,他将反向传播的思想应用于CNN。LeCun提出了著名的LeNet网络,这是一个非常著名的支票识别系统,也是深度学习最早的大规模工业应用之一。
- 后来,循环神经网络在20世纪90年代出现。Elman 提出了它。随后出现了训练问题,我们稍后会讨论,即梯度爆炸或消失问题。
- 大约十年后,Hochreiter 和 Schmidhuber 提出了长短期记忆网络,在某种程度上解决了这些问题。
- 尽管如此,神经网络仍然属于少数派。在80年代,人们使用大量基于规则的AI。在90年代,人们热衷于支持向量机和发明新的核函数。
- 在21世纪初,人们终于取得了进展。Hinton提出了一个很酷的想法:我们可以一次训练这些深度网络的一层。先预训练一层,然后预训练第二层并堆叠上去,第三层再堆叠上去,从而逐步构建起这些连续的表示。
- 深度学习大约在三四年前真正开始兴起,并从此进入主流。作为其主流化的证据,你可以看到它在所有领域的应用。

深度学习的力量 💪
上一节我们回顾了历史,本节中我们来探讨深度学习为何如此强大。从广义上讲,深度学习是一种学习方式,可以吸收任何类型的数据,无论是序列、图片、向量,甚至是像围棋这样的游戏,并将其转化为一个向量。
这个向量将成为该数据所捕获信息的密集表示。这非常强大,因为这些向量具有组合性。你可以使用深度学习系统的这些组件,像乐高积木一样,连接向量、将它们相加,并利用它们来修改模型。正是这种组合性使其非常灵活。
今天我们将讨论前馈网络、适用于图像或任何具有重复结构信息的卷积网络、处理序列的循环网络,以及如果有时间,还会涉及一些无监督学习主题。

前馈神经网络 🔄
在课程最开始,我们讨论过线性预测器。线性预测器基本上就是定义一个权重向量 W,然后将其与输入点乘,得到输出。
神经网络的定义非常相似。你可以将每个隐藏单元视为某种线性预测器的结果。反向推导,你定义一个向量 W,用某个激活函数(或一些隐藏输入)与其点乘,得到输出。然后,通过定义一个向量并用输入计算隐藏数,再用隐藏数计算最终输出,从而得到隐藏层。
在某种程度上,你像是在堆叠线性预测器。每个数字,比如 h1, h2 和 f(θ),都可以看作是一个小型线性预测器的结果,它们以某种方式连接在一起。
为了可视化,如果我们想加深网络,只需重复这个过程。


- 这可以称为单层神经网络,也就是我们之前讨论的线性预测器。你有一个权重向量,并将其应用于输入。
- 对于两层网络,你不是将向量应用于输入,而是将矩阵应用于输入,从而得到一个新的向量。然后,将这个中间向量(隐藏向量)与另一组权重点乘,得到最终输出。
- 然后你可以不断重复。通过一个向量,通过一个矩阵得到新向量,再通过另一个矩阵得到新向量,最后在末端与一个向量点乘得到一个数字。

关于深度,这是这些模型真正强大的原因之一。对于为什么深度有帮助以及为什么堆叠这些矩阵效果良好,有很多解释。

- 一种思考方式是,它学习了输入的分层表示。H 将是 X 的某种表示,H‘ 将是 X 的更高层次表示。
- 另一种思考方式是,每一层都像是处理中的一个步骤。你可以把它想象成一个 for 循环,迭代次数越多,步骤越多,深度越深,你能对输入执行的处理就越多。
- 最后,网络越深,它能表示的函数种类就越多,因此也具有灵活性。
但总的来说,对于为什么深度有帮助,并没有很好的正式理解。深度学习的理论与实践之间肯定存在差距。
这大致说明了深度为何有帮助。如果你输入像素,也许第一层进行边缘检测,第二层给出小眼睛、鼻子或耳朵,第三层及以上则给出整个物体。
总结一下,我们有这些深度神经网络,它们学习数据的分层表示。你可以用训练线性分类器的相同方式来训练它们,即使用梯度下降。
你定义损失函数,对损失求导,然后传播梯度,朝你认为有益的方向更新。这个优化问题很困难,因为它是非线性且非凸的。但总的来说,我们发现如果你投入大量数据和计算资源,总能设法训练好。
幻灯片顺序似乎有点乱。但基本上,回顾如何训练这些模型,总体上与线性预测器相同。你定义一个损失函数,例如均方误差损失:取真实输出与预测输出之差的平方。目标是最小化这个损失。
方法是:从训练数据中采样数据点,计算损失函数对参数的导数,然后朝梯度相反方向更新,希望这能让你在误差曲面上下降。
问题在于这是一个非凸优化问题。例如,线性分类器因为是线性的,误差曲面看起来像个碗。而这些模型由于非线性激活函数,最终会得到看起来非常混乱的误差曲面。
在21世纪之前,这是阻碍神经网络发展的首要问题,因为它们很难训练成功。基本上,改变现状的因素之一是更快的计算机。我们有了GPU,可以并行化操作,特别是那些大型矩阵乘法。其次,数据也更多了。
但这并不完全正确。我们还发现了许多其他技巧。

- 例如,拥有大量隐藏单元会有所帮助,因为它提供了优化上的灵活性。如果你的模型容量超过所需,那么你可以学习更灵活的函数。
- 我们有更好的优化器。SGD每次朝相同方向移动相同的步长,而像Adam这样的新优化器则能决定在选定方向后移动多远。
- 我们有Dropout,即对每个隐藏单元的输出添加噪声。这使模型对其自身错误更具鲁棒性,并防止过拟合。
- 有更好的初始化策略,例如Xavier初始化。
- 还有像在相关数据集上预训练模型,然后再转移到你真正关心的数据上的技巧。
- 以及像批归一化这样的技巧,它确保输入到神经网络单元的数据是正态分布的(均值为0,标准差为1)。这样做基本上允许你使用更大的步长。



这里的要点是,总的来说,你定义的优化问题和模型架构是紧密耦合的。要找到正确的平衡点有点像黑魔法,我们仍然不太擅长。
卷积神经网络 🖼️
现在我们来讨论卷积神经网络。它们处理图像。动机是:我们有一张图片,想对其做一些机器学习处理。我们拥有所需的所有工具。你可以说,每个像素都是一个大长向量中的一个元素,然后直接将其输入矩阵。
但问题是,这并没有真正利用图片中的空间结构。这个像素与那个像素的相似度,比与下面那个像素的相似度更高。但如果你将整个图片通过一个矩阵,那么每个像素都会被独特且不同地对待。因此,我们希望利用这种空间结构。

核心思想是卷积。卷积中有一个称为滤波器的东西,它是一些参数的集合。你做的就是在输入上滑动这个滤波器,以产生每个输出元素。


例如,这个滤波器应用于左上角时,产生输出的左上角。滤波器的应用有点像点积,你将所有数字相乘,然后求和。

产生这些输出的方法是:取你的滤波器,基本上在输入中滑动它,以在下一层获得输出。
这个例子更具体一些。这里展示的是一维卷积,因为我们有一个一维滤波器,并水平滑动它。
这种方法的优势之一是参数效率。在常规的全连接层中,每个隐藏单元都连接到每个输入单元,参数会形成一个庞大的矩阵。而进行卷积时,由于局部连接性的概念,每个隐藏层只连接到其感受野内的输入,并且参数是共享的,因为你在输入的不同位置使用相同的滑动窗口。
这提供了局部连接性,参数效率更高,并且对滤波器有很好的直观解释。总的来说,在实践中,输入和滤波器都是高维体积,滤波器是一个在输入空间中滑动的立方体。输出也是一个体积,因为你有多个滤波器。
人们做的另一件事是最大池化。这指的是在输入区域中寻找最大激活值,并将其传递到后续层。直观上,你是在输入区域中搜索模式。这也有助于降低维度,因为最终我们需要将数据压缩到很少的几个数字。
这些网络的工作方式相当直接。基本上,你只是组合层,将它们堆叠起来,加入一些池化,维度不断降低,直到最终得到可能标签上的分布。

这与之前提到的乐高积木类比有关,因为整个网络是由几种不同的乐高积木块构建而成,基本上只是将它们堆叠在一起,组合起来,形成一个图像分类器。
以下是三个CNN架构的案例研究:

- AlexNet:这是在ImageNet竞赛中表现出色,真正将CNN带入计算机视觉主流的网络。基本上就是一个非常大的神经网络。他们使用的一个技巧是用ReLU代替Sigmoid激活函数,在实践中发现ReLU更容易训练。
- VGGNet:几年后出现在ImageNet上。基本上类似,就是一个CNN。值得注意的是它非常均匀,有16层,里面没有什么花哨的东西,只是一堆乐高积木块堆叠起来。它开启了网络更深、更“瘦高”的趋势。
- ResNet(残差网络):将深度推向极致。残差网络的思想是,大多数时候你输入通过矩阵得到输出。如果你再次加入你的输入,这会非常有帮助,因为它使模型易于学习恒等函数。因此,你可以给模型提供一百层的能力,但如果你加入这些残差连接,它允许模型在认为最佳时跳过某一层。这也有助于反向传播训练。
总结一下,卷积神经网络通常应用于图像分类。关键思想是拥有这些在输入中滑动的滤波器,这实现了局部连接性的概念,并且参数是共享的。深度对这些网络确实很重要。
循环神经网络 🔁
现在我们来讨论循环神经网络。这里的想法是,你对输入序列进行建模。这可以是文本或句子,也可以是时间序列数据或金融数据。循环神经网络是一种将过去的输入反馈到自身的网络,因此它具有时间依赖性。
例如,我们有一个非常简单的循环神经网络。它是一个具有一个矩阵的函数,以过去的隐藏状态和当前输入作为参数,然后预测下一个隐藏状态。
大多数时候,人们从第三种视角讨论,即跨时间展开这个网络。在每个时间步,你有一个输入和一个状态,然后你的函数将你带到下一个状态。
一个更具体的例子是神经网络语言模型。这是一个负责读入句子并预测句子中最可能出现的下一个单词的模型。
我们称每个输入为 X,隐藏状态为 H。工作方式是:我们有一个函数,接收 X1 并将其编码到我们的隐藏状态中。然后我们有第二个函数,接收隐藏状态并将其解码为下一个输入。我们继续取下一个输入 X2 和之前的隐藏状态 H1,用它们创建一个新的隐藏编码,然后解码成我们的下一个输入。我们不断重复,每次取当前输入和之前的隐藏状态先创建编码,然后预测下一个输入。

需要注意的一点是,我们现在正在构建这些向量 H,这正是我们想要的。它是一个向量,以某种方式捕获了到该时间步为止我们输入的所有 X 的含义或摘要。

总的来说,循环神经网络存在一个问题。如果存在短依赖,即输出依赖于最近的输入,那么通过网络的路程很短,梯度很容易到达需要到达的地方以正确训练网络。但如果存在很长的依赖,梯度则难以完全传播。

梯度下降可以看作是一个信用分配问题。梯度在某种程度上表示:如果我稍微改变这个输入,输出会改变多少?但如果输入和输出相距甚远,则很难计算输入的小扰动会如何影响输出。
原因在于,要计算梯度,你必须追踪整个依赖路径,查看该路径上所有部分的导数,并将它们相乘。问题是,如果路径很长,你就在乘很多数字。如果数字小于1,乘积会迅速变得非常小;如果数字大于1,乘积会迅速爆炸。这是一个问题,因为这意味着你的梯度要么极小,没有学习信号;要么太大,会冲向某个疯狂的方向。
好消息是,对于梯度爆炸问题,有一个快速的解决方法:梯度裁剪。你指定一个范数,任何范数大于该值的梯度都会被截断。但对于梯度消失问题,有一个很酷的想法:长短期记忆单元。

LSTM类似于循环单元,但它有两个隐藏状态。重要的是,你在这里进行的是加法组合,将输入与先前的隐藏状态相加,这与ResNet中的残差连接非常相似。因为加入了先前的状态,这为梯度提供了一条轻松回溯时间的“高速公路”。
LSTM的另一个视角是,它有一个暴露给外部的隐藏状态 H,以及一个内部的隐藏状态 C。内部状态 C 在一个“恒定误差传送带”上循环,包含了对网络在许多时间步长内有用的长期信息。
人们使用循环网络的另一个很酷的想法是序列到序列模型,例如机器翻译。你有一个输入序列和一个输出序列,你想读入输入序列然后输出输出序列。你通过编码器-解码器范式来实现。

最近,还有基于注意力的模型,这在处理长序列时非常有帮助。注意力的思想是回顾输入。在解码时,你将当前的隐藏状态与编码器中所有的状态进行比较,计算一个分数来表示“我有多喜欢这个状态”。然后,你使用这些分数将它们转化为一个概率分布,并计算这些隐藏向量的加权平均,权重来自这个分布。

这有两个目的:首先,它提供了一些可解释性,你可以看到在每个时间步它关注输入的哪些部分;其次,它释放了模型必须将整个输入序列压缩到一个向量中的压力,现在它可以动态地回溯并检索所需的信息。
最近,还有所谓的Transformer模型,它完全摒弃了RNN部分,只使用注意力。在Transformer中,你取每个隐藏状态,将其与其他所有隐藏状态(包括自身)进行比较,得到一个分数,然后计算所有这些隐藏状态的加权平均,这成为你的下一层。
总结一下,循环神经网络可以处理序列并输出向量。直观上,它们像for循环一样顺序处理输入。但它们在训练上存在问题,梯度要么爆炸,要么变得非常小。LSTM是缓解此问题的一种方法,但它们并不完美,仍然需要将信息塞入一个向量中。因此,人们通过基于注意力的模型来解决这个问题,动态地根据需要回溯输入并检索信息。

无监督学习 🎯
现在我们来讨论无监督学习。如前所述,神经网络最近才得以良好运行,很大程度上是因为它们需要大量数据。但如果你是一个较小的实验室,或者没有足够的资金购买数据集,或者问题本身数据就很少,那么在很多情况下,没有足够的数据来训练这些拥有数百万甚至数十亿参数的巨大模型。

另一方面,周围有大量未标记的数据。你可以下载整个互联网。这有点类似于我们人类的灵感来源。我们从未被给予标记好的数据集来告诉我们什么食物可食,什么不可食。我们从世界中吸收经验,并用这些经验来指导未来的经验,从而能够进行推理和决策。
我们将要讨论的第一件事是自编码器。自编码器的思想是,如果你有一些信息,并尝试学习该信息的压缩表示,以便能够重建它,那么你可能就做了一些有用的事情。
在神经网络术语中,工作方式是:你给它某种向量,通过编码器得到隐藏向量,然后通过解码器重建你的输入。大多数情况下隐含的损失是,你希望重建的输入与原始输入非常相似。
为了说明这一点,主成分分析可以被视为一种编码器-解码器。PCA的思想是,你想提出一个矩阵 U,它是一个既可用于编码也可用于解码数据的向量。你将 x 乘以 U 得到一个隐藏向量或数据的新表示,但如果你转置 U 并将其乘以你的隐藏向量,那么应该得到尽可能接近原始数据的东西。
但这里有个问题。如果我们有一个包含许多单元的隐藏向量,它可能什么也学不到,只会学习如何将输入复制到输出。因此,许多关于自编码和无监督学习的研究都集中在如何控制复杂性并使模型足够鲁棒,以生成有用的表示,而不是仅仅复制。
第一种尝试可以是使用非线性变换。另一种方法是破坏输入,即对输入添加噪声,可能丢弃一些数字,或扰动一些数字,然后通过编码器和解码器传递这个被破坏的输入,最终的重建输出 x_hat 应该非常接近原始的未破坏输入。
另一种是变分自编码器,它具有很酷的概率解释。你可以将其视为一种贝叶斯网络。变分自编码器将输入映射到可能的 h 分布上,然后从这个分布中采样,通过解码器产生重建的输入。这样做的好处是,由于这是一个分布而不是一个向量,你在空间上强加了一些结构。因此,空间中接近的点应该映射到相似的 x_hat,并且当你在空间中移动时,应该能够逐渐从一个重建输入过渡到另一个。
我们将讨论的最后一种无监督学习方法是由一个特定任务激发的。有一个名为SQuAD的数据集,包含大约10万个例子,每个例子由一个段落和基于该段落的一系列多项选择题组成。这里的问题是只有10万个例子。

而这个任务试图获取的智能——阅读文本并理解它——是更普遍的,并且被比这10万


🎓 CS221 课程总结:第19讲 - 人工智能的回顾与展望


在本节课中,我们将回顾CS221课程的核心内容,总结我们所学到的建模、推理与学习范式。随后,我们将探讨人工智能的历史脉络、当前面临的挑战以及未来的研究方向,并为你提供一些深入学习相关领域的课程建议。

📚 课程内容总结
上一节我们介绍了本节课的总体安排,本节中我们来回顾一下贯穿整个课程的核心范式与主题。


我们以建模、推理与学习这一范式开启课程。面对一个现实世界的问题,我们首先进行建模,即对问题进行抽象。接着,我们通过推理来解决问题,例如寻找最短路径或进行某种优化。最后,学习部分则利用数据来完善我们的模型参数,因为模型通常无法完美刻画现实。
以下是我们在课程中探讨的四大主题,它们代表了不同层次的智能:
- 基于反射的模型:这是最简单的形式。推理过程就是模型的前向计算。学习则通过随机梯度下降等优化方法最小化损失函数。例如线性模型、神经网络和最近邻算法。
- 基于状态的模型:核心概念是状态,它是对过去所有行动的总结,足以指导未来的最优决策。我们研究了确定性系统(搜索问题)、随机系统(MDPs)以及对抗性环境(博弈)。推理算法包括统一代价搜索、A*搜索、动态规划、价值迭代和极小化极大算法。学习方面则涉及结构化感知器、Q学习和时序差分学习。
- 基于变量的模型:此时状态的顺序不再重要,关键是变量之间的关系。我们使用因子图来刻画变量间的条件独立性。主要模型包括约束满足问题和贝叶斯网络。推理算法有回溯法、前向-后向算法和束搜索。学习则通过最大似然估计和期望最大化算法进行。
- 逻辑:这是最高层次的抽象,使用逻辑公式来表达系统中有意义的约束。我们讨论了命题逻辑和一阶逻辑。推理方法包括模型检测、假言推理和归结原理。如何将学习与逻辑有效结合,目前仍是一个开放的研究问题。
CS221课程为我们提供了一套工具箱,让我们能够审视复杂的世界问题,选择合适的模型、问题表述方式以及推理算法来求解。
🧭 后续学习路径
在回顾了课程核心内容后,你可能会对某些领域产生更深的兴趣。以下是基于CS221视角,推荐的一些后续课程,可分为基础理论和应用领域两大类。
基础理论课程
如果你想在CS221涉及的基础概念上深入钻研,可以考虑以下课程:
- CS228:概率图模型 - 深入学习变量消除、置信传播、变分推断等更通用的推理算法,并探索如何从数据中学习模型结构。
- CS229 / CS229T:机器学习 / 统计学习理论 - CS229涵盖更广泛的模型(如核方法、决策树)和算法。CS229T则侧重学习算法的数学理论基础,如一致性、收敛性和遗憾界分析。
- CS231N:卷积神经网络与视觉识别 - 深入计算机视觉领域。
- CS234:强化学习 - 专注于基于状态模型的学习算法。
- 凸优化、不确定性下的决策等课程也值得关注。
应用领域课程
如果你希望将AI技术应用于具体领域,以下课程是不错的选择:
- 自然语言处理:如CS224N,研究机器翻译、文本摘要、对话系统等任务中离散符号与连续语义的匹配问题。
- 计算机视觉:如CS231系列,研究物体识别、检测、分割以及视频中的活动识别等任务。
- 机器人学:涉及操控、导航、抓取等,需处理物理系统的连续性、不确定性以及与运动学/控制的结合。例如《机器人学导论》或《机器人自主性》系列课程。
- 通用游戏:如果你对博弈论在游戏中的应用感兴趣。
交叉领域课程
此外,与AI密切相关的交叉学科也充满洞见:
- 计算认知科学:研究人类心智如何工作,常使用贝叶斯建模等计算工具。
- 计算神经科学:从硬件层面理解智能,探索现代神经网络与生物大脑的启发与联系。
⏳ 人工智能简史
了解了未来的学习方向后,让我们回溯过去,看看人工智能是如何发展到今天的。我们在第一讲曾简要提及,这里做一个回顾。
人工智能的诞生通常以1956年的达特茅斯夏季研讨会为标志。早期研究者对通用智能原理充满乐观,预言机器很快能完成任何人类工作,这推动了第一波AI热潮,其特点是基于逻辑和规则的问题求解系统。
然而,由于计算能力有限和信息(数据)匮乏,早期系统(如机器翻译)表现不佳,导致了第一次AI寒冬。尽管如此,该时期仍贡献了Lisp语言、垃圾回收等计算机科学基础思想,以及将建模与推理分离的关键范式。
70到80年代,随着专家系统的兴起,AI迎来第二波热潮。人们不再单纯追求通用智能,而是专注于构建能解决特定领域实际问题的有用系统。专家系统在医疗诊断、工业配置等领域取得了真实影响。
但专家系统难以处理不确定性,且构建和维护庞大的知识库需要巨大的人工成本,这导致了第二次AI寒冬。
90年代至今的现代AI浪潮,其兴起主要得益于两大因素:
- 概率的引入:以贝叶斯网络为代表,使AI能够建模和处理不确定性。
- 机器学习的崛起:从支持向量机到深度学习,利用海量数据自动学习模型参数。
人工智能是一个熔炉,它融合了概率论、逻辑学、统计学、神经科学、经济学、优化理论、控制论等多个领域的智慧。
⚠️ 当前挑战与未来方向
在领略了AI的成就与历史后,我们必须清醒地认识到当前面临的诸多挑战。随着AI系统越来越多地参与决策,我们必须审慎思考其可能带来的问题。
以下是当前AI领域面临的一些核心挑战:
- 偏见与公平性:算法会学习并可能放大训练数据中存在的社会偏见。例如,机器翻译系统可能将无性别语言中的职业词汇错误地对应为有性别语言的刻板印象。定义和实现算法公平性本身就是一个复杂且存在内在冲突的难题。
- 对抗性样本:对输入添加难以察觉的微小扰动,就能使高性能的图像分类器做出完全错误的判断。这对自动驾驶等安全关键型应用构成了严重的安全威胁。
- 可解释性与准确性权衡:像深度神经网络这样的高性能模型通常是“黑箱”,难以理解其内部决策逻辑。在医疗、航空等安全关键领域,我们是否愿意为了更高的统计准确性而牺牲透明度和可解释性?
- 目标对齐与奖励破解:为AI系统设计正确的目标函数非常困难。一个旨在“吸尘”的机器人可能会通过反复倾倒和吸入灰尘来“刷分”,或者直接弄坏灰尘传感器以“眼不见为净”。这引出了价值对齐问题:如何确保AI系统的目标与人类的真实意图一致?
- 社会影响与反馈循环:优化点击率的推荐算法可能会向用户推送越来越极端的内容,从而使用户观点极化,并产生更偏激的数据,形成恶性循环。AI生成虚假内容、自主武器系统的伦理问题也亟待讨论。
- 隐私:如何在利用数据训练模型的同时保护用户隐私?差分隐私和随机化响应是可能的技术方向。
- 因果关系:从观察数据中推断因果关系非常困难。例如,接受治疗的患者存活率更低,可能仅仅是因为病情更重的患者更倾向于接受治疗。
✅ 总结与责任
本节课我们一起回顾了CS221课程的核心知识体系——建模、推理与学习的范式,以及从反射模型到逻辑的四大智能层次。我们梳理了人工智能从诞生、寒冬到复兴的三次浪潮历史,并重点探讨了当前AI在偏见、安全、可解释性、伦理等方面面临的严峻挑战。
人工智能具有巨大的积极潜力,但正如各国政府和研究机构所强调的,我们必须重视其伦理、法律和社会影响。最终,是人类设计并部署了这些算法,因此人类必须为算法的后果负责。希望你在未来的学习和工作中,能够负责任地运用AI技术,创造积极的影响。


感谢大家共度这个精彩的学期!


课程 P2:机器学习 1 - 线性分类器与随机梯度下降 🧠
在本节课中,我们将学习机器学习的基础知识,特别是线性分类器。我们将从最简单的反射模型入手,探讨如何利用数据来调整模型参数,从而避免手动设计模型的复杂性。课程将分为三个主要部分:线性预测器、损失最小化以及随机梯度下降算法。
概述 📋
机器学习允许我们利用数据来调整模型参数。本节课将从最简单的反射模型——线性分类器开始,展示如何将机器学习应用于此类模型。我们将介绍线性预测器(包括分类和回归)、损失最小化(定义训练目标)以及随机梯度下降(实现优化的算法)。
第一部分:线性预测器
上一节我们概述了课程框架,本节中我们来看看具体的线性预测器。


预测器的目标是建立一个函数 f,将输入 x 映射到输出 y。例如,在垃圾邮件分类中,输入 x 是电子邮件,输出 y 是“垃圾邮件”或“非垃圾邮件”。这是一个二元分类问题,输出通常标记为 +1 或 -1。

机器学习的第一步是获取数据。一个样本是一个 (x, y) 对,它指定了给定输入 x 时应有的输出 y。训练集 是样本的集合,它部分地定义了模型应有的行为。
特征提取
线性预测的第一步是特征提取。我们需要思考输入 x 的哪些属性可能与预测输出 y 相关。特征提取器 φ 将输入 x 转换为一个特征向量,即一组(特征名,特征值)对。实际上,对于学习算法而言,特征向量就是一个数字列表。
例如,对于字符串 "abc@gmail.com",其特征向量可能包括:
- 长度 > 10: 1 (是)
- 字母数字字符比例: 0.85
- 包含 '@': 1 (是)
- 以 ".com" 结尾: 1 (是)
- 以 ".org" 结尾: 0 (否)
因此,特征向量 φ(x) 可以表示为 [1, 0.85, 1, 1, 0]。特征提取将复杂对象(如字符串、图像)提炼为数字列表,这是机器学习算法的通用语言。
公式:特征向量表示为 φ(x) ∈ ℝ^D,其中 D 是特征维度。其分量是 φ₁(x), φ₂(x), ..., φ_D(x)。


权重向量与得分
与特征向量对应的是**权重向量 w,它也是一个 D 维向量。权重 w_j 表示第 j 个特征对预测的贡献程度。权重可正可负,其大小表示该特征的重要性。
预测的得分是权重向量与特征向量的点积:
公式:score = w · φ(x) = Σ_{j=1}^{D} w_j * φ_j(x)
可以将每个特征视为一个“投票者”,权重决定了其投票的方向(正/负)和力度。
线性分类器
对于二元分类,线性分类器 f_w 根据得分的符号进行预测:
公式:f_w(x) = sign( w · φ(x) )
其中,sign(a) = +1 if a > 0, else -1。
得分是一个实数,其符号决定了分类结果。从几何角度看,权重向量 w 定义了一个决策边界(一个超平面),将特征空间划分为正负两个区域。决策边界是满足 w · φ(x) = 0 的所有点的集合。
第二部分:损失最小化
上一节我们定义了线性预测器,但尚未涉及如何从数据中学习。本节中我们来看看如何通过定义损失函数来指导学习。
损失函数 Loss(x, y, w) 衡量当使用权重 w 对应的预测器对样本 (x, y) 进行预测时,我们的“不满程度”。损失值高意味着预测效果差,损失值低(理想情况为0)意味着预测效果好。
分类损失:间隔与 0-1 损失
对于分类,我们引入间隔的概念。
公式:margin = (w · φ(x)) * y,其中 y ∈ {+1, -1}。
间隔衡量预测的正确程度。正间隔表示分类正确,且值越大表示越确信;负间隔表示分类错误。
最直接的损失函数是0-1损失,它只关心是否犯错:
公式:Loss_{0-1}(x, y, w) = 1 [ f_w(x) ≠ y ] = 1 [ margin ≤ 0 ]
其中 1[条件] 是指示函数,条件为真时值为1,否则为0。
然而,0-1损失在绝大多数点上的梯度为零,无法用基于梯度的方法进行优化。
回归损失:残差与平方损失
对于回归问题,预测值就是得分 ŷ = w · φ(x)。我们定义残差为预测值与真实值的差:residual = ŷ - y。
常用的损失函数是平方损失:
公式:Loss_{square}(x, y, w) = (ŷ - y)² = (w · φ(x) - y)²
平方损失对大的误差给予更重的惩罚。
训练损失
机器学习的目标不是完美拟合单个样本,而是用一组权重 w 同时拟合所有训练样本。因此,我们定义训练损失为所有样本损失的平均值:
公式:TrainLoss(w) = (1/|D_train|) * Σ_{(x,y)∈D_train} Loss(x, y, w)
学习算法的目标就是找到最小化训练损失的权重 w。
第三部分:优化与随机梯度下降
上一节我们定义了需要最小化的目标(训练损失),本节中我们来看看如何通过优化算法来求解。
梯度下降
梯度下降是一种迭代优化算法。从初始权重(如全零)开始,反复计算训练损失函数的梯度,并向梯度反方向更新权重,以减小损失值。
算法步骤:
- 初始化权重 w = 0。
- 循环多次迭代:
- 计算梯度 g = ∇_w TrainLoss(w)。
- 更新权重 w ← w - η * g,其中 η 是步长(学习率)。
对于平方损失,其梯度有一个直观形式:∇_w Loss_{square} = 2 * (ŷ - y) * φ(x)。梯度由残差驱动,如果预测正确(残差为0),则梯度为零,无需更新。
然而,梯度下降的缺点在于每次迭代都需要计算整个训练集上损失的平均梯度,当数据量很大时计算成本高昂。
随机梯度下降
随机梯度下降 的核心思想是:每次迭代只使用一个(或一小批)样本来估计梯度,并立即更新权重。
算法步骤:
- 初始化权重 w = 0。
- 循环遍历训练集(或随机采样样本):
- 对于样本 (x_i, y_i),计算其损失梯度 g_i = ∇_w Loss(x_i, y_i, w)。
- 更新权重 w ← w - η_i * g_i。
由于数据通常存在冗余,基于单个样本的更新方向虽然嘈杂,但平均来看是正确的,并且更新频率大大增加,使得SGD通常比标准的梯度下降收敛快得多。
步长 η 的选择很重要:步长太小收敛慢;步长太大可能不稳定。实践中常使用随时间衰减的步长,例如 η_t = 1 / t。
应用于分类:合页损失
由于0-1损失无法优化,我们为分类问题引入合页损失作为替代:
公式:Loss_{hinge}(x, y, w) = max(0, 1 - margin) = max(0, 1 - (w · φ(x)) * y)
当间隔大于等于1时,损失为0;当间隔小于1时,损失线性增长。合页损失是0-1损失的一个凸上界,且其梯度在多数区域非零。

其梯度为:
- 若
margin ≥ 1:∇_w Loss_{hinge} = 0 - 否则:
∇_w Loss_{hinge} = -φ(x) * y

这个梯度具有直观解释:如果分类正确且足够自信,则不更新;如果分类错误或自信不足,则沿着 φ(x) * y 的方向更新权重,以增大当前样本的间隔。
总结 🎯
本节课我们一起学习了机器学习的基础构建模块:
- 线性预测器:通过特征提取将输入转化为特征向量,利用权重向量计算得分,并通过符号函数(分类)或直接输出(回归)进行预测。
- 损失最小化:定义了0-1损失、合页损失、平方损失等函数,用以量化预测器在数据上的表现。训练目标是最小化平均训练损失。
- 随机梯度下降:一种高效的优化算法,通过使用单个或小批样本的梯度来近似整体梯度,从而快速找到最小化损失的模型参数。

通过将模型(线性预测器)、目标(损失最小化)和算法(SGD)分离,我们获得了一个灵活而强大的机器学习框架。下一节课,我们将深入探讨特征工程,并思考机器学习的真正目标是否仅仅是最小化训练损失。


机器学习课程 P3:特征与神经网络 🧠
在本节课中,我们将学习机器学习的两个核心概念:特征工程和神经网络。我们将探讨如何通过精心设计的特征使线性模型获得强大的非线性表达能力,并介绍神经网络如何自动学习特征。最后,我们会简要了解最近邻算法这一简单而强大的模型。


回顾:机器学习框架 📚
上一节我们介绍了机器学习的基本框架:将学习问题形式化为一个优化问题。其目标是找到一个预测器 F,该预测器能够将输入 X(例如一张图片)映射到输出 Y(例如“猫”或“卡车”的标签)。
这个优化问题通常是最小化训练损失。用符号表示,训练损失 L_train(W) 依赖于权重向量 W,它是所有训练样本上个体损失的平均值:
L_train(W) = (1/N) * Σ L(W; x_i, y_i)


我们的目标是找到使训练损失最小的 W。
损失函数的选择取决于任务类型:
- 回归任务:关注残差(模型预测值减去真实标签)。常用平方损失
(残差)^2或绝对偏差损失|残差|。 - 二分类任务:关注间隔(得分乘以标签 y,其中 y ∈ {+1, -1})。常用零一损失、合页损失
max(0, 1 - 间隔)或逻辑损失。
这个损失最小化框架非常通用,主成分分析、深度神经网络等各种学习算法都可以被视为某种形式的损失最小化。


特征工程:从数据中提取信息 🔧
现在,让我们将注意力从权重 W 转移到特征映射 φ(x) 上。特征提取器将原始输入(如字符串)转换为一组对预测有用的属性(特征值)。
特征模板与稀疏表示
为了有效组织特征,我们引入特征模板的概念。它是一个带有“空白”的特征名称,可以生成多个具体特征。
- 例如,模板“长度大于 _”可以具体化为“长度大于10”、“长度大于9”等特征。
- 另一个例子是“像素强度位于位置(_, _)”,它能生成与图像像素数量一样多的特征。



每个特征模板映射到一组特征。在实现时,如果特征向量是稀疏的(即大多数特征值为0),使用字典(键为特征名,值为特征值)来存储比使用长列表更高效。这在自然语言处理等涉及离散对象的领域很常见。



假设空间:特征决定可能性
每一个特征映射 φ 定义了一个假设空间 H_φ,即通过改变权重向量 W 所能得到的所有可能预测器的集合。
考虑两个例子:
- 若 φ(x) = x,则假设空间是所有穿过原点的直线。
- 若 φ(x) = [x, x^2],则假设空间是所有穿过原点的二次曲线(也包括直线)。
第二个假设空间比第一个更富有表现力,因为它能表示更多类型的函数。
我们可以这样理解整个机器学习流程:首先,通过选择特征映射(或模型架构)来定义一个假设空间(即所有可能预测器的集合)。然后,学习算法根据数据从这个集合中选出最佳的预测器。如果特征空间太小(假设空间受限),无论怎么学习都无法获得高精度。反之,如果优化不当,也无法找到假设空间中的最佳解。


线性模型的非线性魔力 ✨







我们一直谈论“线性”分类器。那么,什么是线性的?
- 得分函数 score = W · φ(x) 对于 W 是线性的,对于 φ(x) 也是线性的。
- 但对于原始输入 x,它不一定是线性的。实际上,当 x 是字符串时,这个问题没有意义。
关键在于:线性预测器可以产生关于原始输入 x 的非线性决策边界。从预测角度看,函数可能很复杂;但从学习角度看,算法只关心 φ(x),而损失函数关于 W 是线性的(通常是凸函数),这使得优化效率很高。
一个经典的例子是使用线性分类器学习圆形决策边界。假设原始数据点在二维平面上呈圆形分布。如果我们定义特征映射 φ([x1, x2]) = [1, x1, x2, x1² + x2²],那么在这个三维特征空间中,数据点变得线性可分。这个高维空间中的线性决策边界,投影回原始二维空间时,就形成了一个圆形边界。

神经网络:自动学习特征 🧠

特征工程需要大量领域知识。神经网络提供了一种自动学习有效特征表示的途径。
动机与结构
我们可以通过分解复杂问题来直观理解神经网络。例如,判断两车是否相撞,可以分解为“车1是否在车2右侧足够远”和“车2是否在车1右侧足够远”两个子问题,再将子问题的结果组合起来。


神经网络将这种思想形式化。一个单隐藏层神经网络的结构如下:
- 输入层:接收特征向量 φ(x)。
- 隐藏层:包含多个“神经元”(如两个)。每个神经元 h_j 计算
h_j = σ(V_j · φ(x)),其中 V_j 是权重向量,σ 是一个非线性激活函数(如逻辑函数,即Sigmoid函数)。每个神经元就像一个小型线性分类器,后接非线性变换。 - 输出层:将隐藏层的输出进行线性组合,得到最终得分
score = W · h。


这里,V 和 W 都是需要从数据中学习的参数。V 决定了学习哪些“子问题”(隐藏特征),W 决定了如何组合这些子问题的结果。
使用逻辑函数 σ(z) = 1 / (1 + e^{-z}) 而不是阶跃函数,是因为它处处可微,便于使用基于梯度的优化方法。现代神经网络更常用ReLU等激活函数。
反向传播:计算梯度

训练神经网络需要最小化关于 V 和 W 的损失函数。我们使用随机梯度下降法,这就需要计算损失函数关于所有参数的梯度。

反向传播是一种利用计算图高效计算梯度的算法。其核心思想是:
- 前向传播:从输入到输出计算图中每个节点的值。
- 反向传播:从输出到输入,利用链式法则计算损失相对于每个节点的梯度。
计算图由基本运算(加法、乘法、最大值、非线性函数等)构成。每个运算的局部梯度是已知的。通过将从输出端传回的梯度与局部梯度相乘,我们可以得到任何参数的梯度。
现代深度学习框架(如TensorFlow、PyTorch)自动实现了反向传播,使得模型开发更加便捷。

需要注意的是,神经网络的损失函数通常是非凸的,存在许多局部最优解。但在实践中,梯度下降法通常能找到足够好的解,这仍是当前研究的热点。



最近邻算法:一种简单替代 👥
现在,让我们暂时抛开线性模型和神经网络,看一个极其简单的方法:最近邻算法。

算法如下:
- 训练:存储所有训练数据
(x_i, y_i)。 - 预测:对于新输入
x',在训练集中找到与x'最接近的样本x_i,然后输出其对应的标签y_i。



其核心思想是“相似输入应有相似输出”。在二维空间中,该算法会形成一种称为Voronoi图的分区,每个区域的点都被赋予该区域“种子点”的标签。
最近邻模型是一种非参数模型,其模型复杂度随数据量增长而增长。它非常强大且易于理解,但预测速度较慢(需与所有训练样本比较),且需要存储全部数据。
总结与对比 🎯
本节课我们一起学习了:
- 特征工程:通过特征模板组织特征,理解特征映射如何定义假设空间,并认识到线性模型通过特征变换可以获得非线性决策边界。
- 神经网络:作为一种能够自动学习分层特征表示的模型。我们了解了其基本结构(输入层、隐藏层、输出层)和训练核心——反向传播算法。
- 最近邻算法:一种基于实例的简单而强大的非参数学习算法。


不同的模型在预测速度、训练效率和模型表达能力之间有不同的权衡:
- 线性模型:预测快,训练高效,但表达能力依赖于特征工程。
- 神经网络:预测快,表达能力强大,但训练复杂且需要大量数据。
- 最近邻算法:训练极其简单(仅存储数据),表达能力随数据量增长,但预测速度慢。



在实践中,通常建议从简单的模型(如线性模型)开始,逐步增加复杂度。


机器学习课程第四讲:泛化与K-means聚类 🧠
在本节课中,我们将要学习机器学习中的两个核心概念:泛化与无监督学习。我们将探讨如何避免模型在训练数据上“学得太好”而失去预测新数据的能力,并介绍一种经典的无监督学习方法——K-means聚类算法。
泛化:我们真正关心的是什么?🎯
上一节我们介绍了如何通过优化训练损失来学习模型。本节中我们来看看,仅仅最小化训练误差是否真的是我们的目标。
什么是机器学习的真正目标?是最小化未来未见数据的误差。我们训练模型,最终是为了将其部署到系统中,处理未来的、未见过的数据。
那么,训练误差、正则化和测试集在其中扮演什么角色呢?
过拟合的极端例子
如果我们真的只想最小化训练损失,可以设计一个算法:存储所有训练样本。当遇到训练集中见过的样本时,直接输出其标签;遇到未见过的样本时,则输出一个默认值或报错。这个算法在训练集上的误差为零,但它显然是一个糟糕的主意,因为它完全无法处理新数据。
这就是过拟合的极端例子。过拟合是指模型过于紧密地拟合训练数据(包括其中的噪声),而忽略了数据背后更一般的规律,导致在新数据上表现不佳。

如何评估预测器的好坏?
我们关心的是未来未见数据的误差,但无法直接优化它。通常的做法是收集一个测试集,它应该能代表未来可能遇到的数据类型。我们必须谨慎地保护测试集,避免在模型开发过程中过度使用它,否则它将失去作为未来数据“替身”的意义。

机器学习中有一个“信念的飞跃”:学习算法只在训练集上运行,但我们期望它在未见过的测试集上也能表现良好。为什么会这样呢?
假设空间与误差分解
我们可以从假设空间的角度来理解这种“飞跃”。假设 F* 是能永远给出正确答案的“真实预测器”。我们定义的模型(如特定的特征提取器或神经网络结构)实际上划定了一个假设类 F,这是我们愿意考虑的所有函数的集合。
学习的目标是在 F 中找到最好的函数 f。我们可以将总误差分解为两部分:
- 近似误差:
F中最好的函数g与真实预测器F*之间的误差。这衡量了你的假设类本身的表现力。 - 估计误差:你的学习算法实际找到的函数
f_hat与F中最好的函数g之间的误差。这衡量了基于有限数据,你的学习效果与假设类潜力之间的差距。
总误差可以公式化为:
误差(f_hat) - 误差(F*) = [误差(f_hat) - 误差(g)] + [误差(g) - 误差(F*)]
这个分解有助于我们理解其中的权衡。增大假设类(例如添加更多特征、增大神经网络)会降低近似误差(因为搜索空间更大,可能找到更好的解),但会增大估计误差(因为更复杂的模型需要更多数据来准确估计)。
控制假设类大小的方法
我们如何控制假设类的大小,从而在近似能力和估计难度之间取得平衡呢?以下是两种主要策略:
1. 控制维度 (Dimensionality)
对于线性分类器,预测器由权重向量 w 指定,它有 d 个维度。我们可以通过添加或删除特征来改变 d。减少维度相当于缩小了假设类的范围。
2. 控制权重向量的范数 (Norm)
同样对于线性预测器,我们可以限制权重向量 w 的长度(例如它的 L2 范数 ||w||)。限制范数意味着我们只考虑那些“更平滑”、“更简单”的函数(例如斜率较小的线性函数),这同样缩小了考虑的假设类范围。
实现:正则化与早停
我们如何在优化中实现“保持假设类较小”的理念呢?最流行的方法是正则化。
具体做法是在原始目标函数(训练损失)中添加一个惩罚项。例如,对于 L2 正则化(也称为权重衰减),新的目标函数是:
目标(w) = 训练损失(w) + λ * ||w||^2
其中 λ 是正则化强度,是一个正数。优化器现在需要同时尝试减小训练损失和权重向量的范数,这鼓励它找到能拟合数据但又不复杂的简单解。
另一种更直观但相对粗糙的策略是早停。我们不是一直训练到损失不再下降,而是在训练早期就停止迭代。直觉是,权重通常从接近零的小值开始增长,更少的更新迭代通常意味着更小的权重范数。
核心思想是:努力最小化训练误差,但不要过于努力。
超参数调优

学习算法中有许多需要预先设定的参数,如正则化强度 λ、迭代次数 T、学习率等,这些称为超参数。我们如何设置它们?

- 不能根据训练误差选择:这会导致过拟合(例如,将
λ设为 0)。 - 不能根据测试误差选择:这会使测试集失去作为未来数据估计的意义。
- 正确方法:使用验证集
我们从训练集中划出一部分(例如 10%-20%)作为验证集。测试集被严格保留,用于最终评估。我们使用验证集上的表现来指导超参数的选择和模型开发。
以下是选择超参数的典型流程:
for 每个超参数组合 (如 λ=0.01, 0.1, 1):
在(训练集 - 验证集)上训练模型
在验证集上评估模型性能
选择在验证集上性能最好的超参数组合
实践演练:命名实体识别示例 🔍
理论是基础,但机器学习的实践往往涉及不同的思考。让我们通过一个简化的命名实体识别(判断一个词是否为人名)问题,走一遍典型的开发流程。
核心流程如下:
- 观察数据:理解数据格式和内容。
- 划分数据:分为训练集、验证集、测试集。
- 迭代开发:
- 实现特征或改变模型结构。
- 设置超参数并运行学习算法。
- 观察训练和验证误差,判断是欠拟合还是过拟合。
- (对于线性模型)查看权重以理解模型。
- 查看模型的预测结果,进行错误分析。
- 基于分析 brainstorm 改进方法。
- 最终评估:在锁定的测试集上运行最终模型,报告结果。
特征工程示例(从简单到复杂):
- 初始:无特征,准确率很低(~72% 错误率)。
- 添加实体特征:
feature(“entity= Mauritius”)。训练误差很低,但验证误差仍高(~20%),因为无法泛化到未见过的实体。 - 添加上下文特征:
feature(“left= governor”),feature(“right= said”)。验证错误率下降(~17%)。 - 添加实体词特征:
feature(“entity-contains-word= Felix”)。验证错误率显著下降(~6%)。 - 添加词缀特征:
feature(“entity-contains-prefix= Curt”),feature(“entity-contains-suffix= is”)。验证错误率进一步下降(~4%)。
这个例子展示了一个“顺利”的路径。在实践中,更多时候新特征可能不会带来提升,甚至可能使性能下降。关键在于持续尝试、分析错误并调整思路。
无监督学习:K-means 聚类 📊
到目前为止,我们讨论的都是监督学习,即训练数据包含输入/输出对。然而,获取大量标注数据通常非常昂贵。无监督学习则利用没有标签的数据,这些数据往往更容易大量获取(如互联网文本、图片、视频)。
无监督学习的核心思想是:数据中蕴含着丰富的潜在结构,我们的目标是开发能自动发现这些结构的方法。聚类是其中一种主要技术。



聚类定义

给定一组点 {x1, ..., xn},聚类算法需要为每个点分配一个簇标签 {z1, ..., zn},其中 zi ∈ {1, ..., k},k 是预先设定的簇数量。
K-means 目标函数


K-means 算法的原理是:每个簇都与一个中心点(质心) 相关联。我们希望每个点都离它所属簇的质心尽可能近。
这转化为以下优化目标(重构损失):
最小化 Σ_i || x_i - μ_{z_i} ||^2
其中:
μ_k是第k个簇的质心(一个与数据点同维度的向量)。z_i是数据点x_i被分配到的簇的索引。
我们需要同时优化所有质心{μ_k}和所有分配{z_i}。


K-means 算法:交替最小化
这是一个“鸡生蛋蛋生鸡”的问题。解决方案是交替最小化:
- 分配步骤(固定质心):给定质心
{μ_1, ..., μ_k},将每个点x_i分配给离它最近的质心所在的簇。
z_i = argmin_j || x_i - μ_j ||^2 - 更新步骤(固定分配):给定簇分配
{z_i},将每个簇的质心μ_k更新为该簇所有点的平均值。
μ_k = (1 / |{i: z_i = k}|) * Σ_{i: z_i = k} x_i
完整算法流程:
- 随机初始化
k个质心{μ_1, ..., μ_k}。 - 重复以下步骤直到收敛(例如,分配不再变化或达到最大迭代次数):
- 执行分配步骤。
- 执行更新步骤。
K-means 的特性与注意事项

- 收敛性:K-means 保证收敛到一个局部最优解,但不一定是全局最优。不同的初始质心可能导致不同的结果。
- 初始化:实践中,常使用多次随机初始化并选择结果最好的一次。更高级的方法如 K-means++ 通过智能选择初始点来提升效果。
- 选择 K 值:簇的数量
k是一个超参数。可以通过绘制不同k值对应的重构损失曲线,寻找损失下降的“拐点”;也可以在验证集上评估聚类质量(如果下游任务有标签)来选择。

总结与展望 🌟
本节课中我们一起学习了:
- 泛化是机器学习的核心目标,即模型在未见数据上的表现。我们通过验证集来估计泛化能力并调优模型,同时严格保留测试集用于最终评估。
- 通过控制模型复杂度(如特征数量、权重范数)和使用正则化、早停等技术,可以在拟合训练数据和保持泛化能力之间取得平衡。
- 无监督学习利用未标注数据发现内在结构。K-means 聚类是一种经典方法,它通过交替优化数据点分配和簇中心位置,将数据划分为
k个簇。

机器学习不仅仅是优化训练损失,更是一门关于从经验中学习并泛化到新情况的科学。在接下来的课程中,我们将看到学习如何应用于更复杂的模型,如基于状态的模型和基于概率的模型。



课程5:搜索1 - 动态规划与一致代价搜索 🧭

在本节课中,我们将学习基于状态的模型,特别是搜索问题。我们将从搜索问题的基本概念开始,介绍几种树搜索算法,并深入探讨如何利用动态规划和一致代价搜索来高效解决这些问题。
什么是搜索问题?🤔
上一节我们介绍了基于反射的模型,本节中我们来看看基于状态的模型,特别是搜索问题。搜索问题涉及寻找一系列动作,以达到某个目标状态,同时需要考虑当前动作对未来状态的影响。
以下是几个搜索问题的例子:
- 路线规划:在地图上从A点前往B点,目标是找到最短、最快或风景最美的路径。答案是一系列动作指令(例如,直行、左转、右转)。
- 机器人运动规划:让机器人从A点移动到B点,目标可能是最快、最节能或最安全的方式。动作是机器人各个关节的平移和旋转。
- 游戏解谜:例如魔方或15拼图,目标是将混乱的方块排列成特定顺序。答案是一系列移动方块的动作。
- 机器翻译:将一种语言的句子翻译成英语。目标是将源语言的意思流畅、准确地转化为英语。动作是逐个添加单词到目标句子中。
搜索问题与反射模型的关键区别在于:在搜索问题中,输出的动作会直接影响未来的状态和后续决策,因此必须考虑动作的未来后果。
搜索问题的形式化定义 📝



为了系统地解决搜索问题,我们首先需要将其形式化。一个搜索问题通常由以下几个部分组成:

- 起始状态:
start - 动作函数:
actions(s),返回在状态s下所有可能的动作。 - 成本函数:
cost(s, a),返回在状态s下执行动作a所需的成本。 - 后继函数:
succ(s, a),返回在状态s下执行动作a后到达的新状态。 - 终止判断函数:
is_end(s),检查状态s是否是目标(终止)状态。
一个简单的例子:运输问题
假设有N个街区(1到N),我们从街区1出发,目标是到达街区N。有两种移动方式:
- 步行:从街区
s移动到s+1,耗时1分钟。cost = 1 - 乘坐电车:从街区
s移动到2*s,耗时2分钟。cost = 2
我们需要找到从1到N耗时最短的路径序列。

树搜索算法 🌳
在深入更高效的算法之前,我们先看看几种基础的树搜索算法。它们通过构建和探索“如果...那么...”树来寻找解决方案。

以下是几种树搜索算法的比较:
| 算法 | 允许的成本 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|---|
| 回溯搜索 | 任意成本 | O(b^d) |
O(d) |
探索所有可能的路径,返回最优解。需要记录当前路径的父节点。 |
| 深度优先搜索 | 零成本 | O(b^d) |
O(d) |
找到第一个解即停止,因为所有解成本相同(零)。 |
| 广度优先搜索 | 正常数成本 | O(b^d) |
O(b^d) |
逐层搜索,找到的第一个解即为最优(因成本恒定)。需要存储整层节点信息。 |
| 迭代加深DFS | 正常数成本 | O(b^d) |
O(d) |
结合BFS和DFS优点。逐层增加深度限制并运行DFS,空间需求小,适用于解在浅层的问题。 |
其中,
b是分支因子(每个状态的平均动作数),d是搜索树深度,d'是最浅解所在的深度。
这些树搜索算法在最坏情况下时间都是指数级的 O(b^d)。接下来,我们将介绍两种能将时间复杂度降至多项式级别的算法:动态规划和一致代价搜索。


动态规划 🧠
动态规划的核心思想是利用“状态”的概念,避免重复计算子问题,从而将指数级问题转化为多项式级问题。
状态:是过去所有动作的摘要,它包含了为未来做出最优决策所需的全部信息。
关键公式:动态规划通过以下递归关系计算从状态 s 出发的未来成本 future_cost(s):
future\_cost(s) = \begin{cases}
0 & \text{if } is\_end(s) \\
\min_{a \in actions(s)} [cost(s, a) + future\_cost(succ(s, a))] & \text{otherwise}
\end{cases}


实现要点:
- 记忆化:存储已计算过的
future_cost(s),避免重复计算。 - 无环假设:动态规划要求状态图是有向无环图,这样才能确定计算状态的顺序(例如,从目标状态倒推)。
状态空间的设计:动态规划的效率很大程度上取决于状态的定义。状态应尽可能小,但必须包含做出未来决策所需的所有历史信息。
- 示例:在“运输问题”中,状态只需是
当前街区。 - 增加约束:如果增加“不能连续访问三个奇数街区”的约束,状态就需要包含
当前街区和已连续访问的奇数街区计数。为了最小化状态空间,计数只需记录“0,1,2,≥3”四种情况即可。

一致代价搜索 ⚖️

动态规划不能处理带环的图。一致代价搜索(本质上是Dijkstra算法)可以解决这个问题,它适用于所有边成本非负的搜索问题。


核心思想:按照从起点到该状态的已知最小成本的递增顺序来探索状态。
算法维护三个集合:
- 已探索:我们已确定找到最优路径的状态。
- 边界:我们已发现但尚未确定其路径是否最优的状态。每个边界状态都有一个“临时成本”。
- 未探索:尚未被发现的状态。
算法步骤:
- 将起始状态放入边界,成本为0。
- 从边界中取出成本最小的状态
s。 - 将
s移至已探索集合。此时,到达s的成本已是最优。 - 对于从
s出发的每个动作,生成后继状态s'及其总成本(s的成本 + 动作成本)。- 如果
s'是未探索状态,将其加入边界。 - 如果
s'已在边界,且新路径成本更低,则更新其在边界中的成本。
- 如果
- 重复步骤2-4,直到目标状态被取出边界(加入已探索),或边界为空。

示例:寻找下图中从A到D的最短路径。
A --1--> B --100--> D
| |
100 1
| |
C --1--> D
- 首先探索A(成本0)。
- 然后探索B(成本1),更新C的成本为2(经B),D的成本为101(经B)。
- 接着探索C(成本2),发现经C到D的成本为3,优于之前的101,更新D。
- 最后探索D(成本3),找到最优路径 A->B->C->D。

总结 📚
本节课中我们一起学习了基于状态的模型中的搜索问题。
- 我们首先了解了搜索问题的定义和几个实例。
- 然后,我们探讨了几种基础的树搜索算法(回溯、DFS、BFS、迭代加深DFS),并分析了它们的时间和空间复杂度。
- 接着,我们引入了强大的动态规划方法,它通过定义“状态”和记忆化,将指数级搜索转化为多项式时间问题。我们重点讨论了状态设计的重要性。
- 最后,为了处理带环的图,我们介绍了一致代价搜索,它按照成本递增的顺序探索状态,能够保证找到最优解。


下节课我们将继续深入搜索问题的学习。
课程P6:搜索算法(二)🔍

在本节课中,我们将继续探讨搜索算法,完成上一讲未完成的内容,并深入一些更有趣的主题,例如学习算法。课程开始前,先发布一则通知:往期考试的解答现已上线,大家可以开始复习备考,查看这些题目会很有帮助。

由于网络连接问题,本次课程将无法进行在线问答或播放视频。现在,让我们正式开始关于搜索算法的内容。
搜索算法回顾 📚
上一讲我们介绍了搜索的基本概念。本节中,我们将首先回顾已讨论过的主题,以便更好地衔接新内容。
搜索算法的核心目标是:在一个可能的状态空间中,找到从初始状态到达目标状态的一条有效路径。这通常涉及对状态空间的系统化探索。
搜索问题形式化 🧩
一个搜索问题通常由以下几个核心部分组成:
- 状态(State):对当前世界配置的描述。
- 初始状态(State):搜索开始的起点。
- 目标测试(Goal Test):判断一个给定状态是否为目标状态的函数。
- 后继函数(Successor Function):给定一个状态,返回所有可能的后继状态及对应行动的集合。可描述为:
successors(s) = { (action, next_state, cost) ... } - 路径成本(Path Cost):评估一条路径优劣的数值,通常希望找到成本最低的路径。总成本可表示为:
总成本 = 从初始状态到当前状态的累积成本 + 从当前状态到目标状态的估计成本(启发式)
搜索算法性能评估 📊
评价一个搜索算法的好坏,我们主要关注以下四个维度:
以下是衡量标准:
- 完备性(Completeness):当解存在时,算法是否保证能找到解。
- 最优性(Optimality):算法找到的解是否保证是成本最低的。
- 时间复杂度(Time Complexity):算法运行需要花费多少时间,通常用生成的节点数量来衡量。
- 空间复杂度(Space Complexity):算法运行需要占用多少内存,通常用同时存储在内存中的节点最大数量来衡量。
无信息搜索策略 🔄

无信息搜索(又称盲目搜索)不利用问题领域的任何特定知识。上一节我们介绍了几种基础策略,本节我们来看看它们的详细比较。

以下是常见无信息搜索算法的特性对比:

| 算法 | 完备? | 最优? | 时间复杂度 | 空间复杂度 | 关键数据结构 |
|---|---|---|---|---|---|
| 广度优先(BFS) | 是(分支有限) | 是(成本一致) | O(b^d) |
O(b^d) |
队列(FIFO) |
| 深度优先(DFS) | 否(可能陷入循环) | 否 | O(b^m) |
O(b*m) |
栈(LIFO) |
| 深度受限搜索 | 是(若深度≥d) | 否 | O(b^l) |
O(b*l) |
栈 + 深度限制 |
| 迭代加深(IDS) | 是(分支有限) | 是(成本一致) | O(b^d) |
O(b*d) |
栈 + 递增深度限制 |
| 一致成本(UCS) | 是(成本≥ε>0) | 是 | O(b^(C*/ε)) |
O(b^(C*/ε)) |
优先队列(按g(n)排序) |

说明:
b:分支因子(每个状态的平均后继数)d:最浅解所在的深度m:状态空间的最大深度(可能无限)l:深度限制C*:最优解的成本g(n):从起始点到节点n的实际路径成本。


从对比可以看出,迭代加深搜索(IDS) 在空间复杂度上优势明显,而一致成本搜索(UCS) 是首个能保证找到最优解的通用算法。


有信息(启发式)搜索 🧠

有信息搜索利用问题领域的特定知识来指导搜索方向,通常通过启发式函数(Heuristic Function) h(n) 来实现。h(n) 估计从节点 n 到目标状态的最低成本。

贪心最佳优先搜索

贪心搜索试图扩展离目标估计最近的节点。它只使用启发式函数 h(n) 来指导搜索。

- 优点:在好的启发式函数下可能非常快。
- 缺点:不完备,也不最优,可能被错误的启发式信息误导。

A* 搜索

A* 搜索结合了实际成本 g(n) 和估计成本 h(n),通过评估函数 f(n) = g(n) + h(n) 来选择扩展节点。f(n) 表示通过节点 n 到达目标的估计总成本。


A* 搜索的核心思想是:在保证启发式函数 h(n) 可采纳(Admissible)(即永不高于真实成本)的前提下,它能保证找到最优解。如果 h(n) 还满足一致性(Consistency)(或称单调性),则A*在扩展节点时,其 f(n) 值是非递减的,效率更高。


启发式函数设计 💡

设计良好的启发式函数对A*搜索的效率至关重要。一个常用的方法是松弛问题法,即通过移除原问题的某些约束,得到一个更容易求解的问题,其最优解的成本可以作为原问题的启发式估计。

例如,在网格路径规划中:
- 曼哈顿距离:忽略障碍物,只允许沿网格线移动。
- 欧几里得距离:进一步允许直线移动。

通常,对原问题约束放松得越多,得到的启发式函数值越大(更接近真实成本),但计算也可能更复杂。关键在于在启发式的准确性和计算开销之间取得平衡。


总结 🎯

本节课我们一起学习了搜索算法的核心内容。我们回顾了搜索问题的形式化定义和算法评估标准,系统比较了各类无信息搜索策略的优缺点。接着,我们重点介绍了有信息的启发式搜索,特别是A*搜索算法,它通过结合实际路径成本 g(n) 和启发式估计 h(n),在保证最优性的前提下显著提高了搜索效率。最后,我们探讨了如何设计可采纳且一致的启发式函数,例如通过松弛问题的方法。

掌握这些搜索策略及其适用场景,是解决人工智能中许多规划与决策问题的基础。



课程 P7:马尔可夫决策过程与价值迭代 🧠
在本节课中,我们将学习马尔可夫决策过程的基本概念,并重点介绍价值迭代算法。我们将从确定性搜索问题过渡到包含不确定性的决策问题,理解如何通过定义策略和价值函数来寻找最优决策方案。
从搜索问题到MDP 🔄
上一节我们讨论了确定性的搜索问题。在本节中,我们将引入不确定性,进入马尔可夫决策过程的世界。
在搜索问题中,我们从状态 S 采取行动 A,会确定性地转移到新状态 S'。其解决方案是一条确定的行动路径。
然而,现实世界充满不确定性。例如,选择交通方式时,可能会遇到堵车、延误等意外情况。MDP 正是为了对这种不确定性进行建模。
在 MDP 中,从状态 S 采取行动 A 后,会以一定的转移概率 T(s, a, s') 随机进入多个可能的新状态 S' 之一。同时,每次转移会获得一个即时奖励 R(s, a, s')。
MDP 的形式化定义包含以下要素:
- 状态集合
S - 起始状态
s_start - 行动函数
Actions(s),返回在状态s下可采取的行动 - 转移概率
T(s, a, s'),表示在状态s采取行动a后转移到状态s'的概率 - 奖励函数
R(s, a, s'),表示上述转移获得的即时奖励 - 终止状态判断
IsEnd(s) - 折扣因子
γ(0 ≤ γ ≤ 1),用于权衡当前奖励与未来奖励的重要性
与搜索问题的核心区别在于,我们用概率性的转移和奖励取代了确定性的后继函数和成本。
MDP的解决方案:策略 📜
在确定性搜索中,解决方案是一条行动序列。但在MDP中,由于状态转移是随机的,我们无法预先确定一条固定路径。
MDP的解决方案是一个策略 π。策略是一个函数,它为每个状态 s 指定一个应采取的行动 a。
π(s) = a
策略定义了在任何可能遇到的情况下,智能体应该怎么做。
评估策略:策略评估 📊
在寻找最优策略之前,我们先学习如何评估一个给定策略的好坏。
当我们遵循一个策略 π 时,会产生许多随机的状态路径。每条路径会获得一个效用,即该路径上所有奖励的(折扣)总和。
Utility = R_1 + γ * R_2 + γ^2 * R_3 + ...
由于路径是随机的,效用也是一个随机变量。因此,我们更关心其期望值,即价值。
V^π(s) 表示从状态 s 开始,遵循策略 π 所能获得的期望效用。
我们还可以定义 Q 价值 Q^π(s, a),表示在状态 s 采取行动 a,然后遵循策略 π 所能获得的期望效用。
价值函数满足著名的 贝尔曼期望方程:
对于终止状态:
V^π(s) = 0,若 IsEnd(s) 为真。
对于非终止状态:
V^π(s) = Q^π(s, π(s))
Q^π(s, a) = Σ_{s'} T(s, a, s') * [ R(s, a, s') + γ * V^π(s') ]
合并后得到:
V^π(s) = Σ_{s'} T(s, π(s), s') * [ R(s, π(s), s') + γ * V^π(s') ]
这个方程表明,一个状态的价值等于“即时奖励的期望”加上“折扣后的未来状态价值的期望”。
我们可以通过迭代策略评估算法来求解 V^π(s):
- 将所有状态的价值
V(s)初始化为 0。 - 重复以下步骤直到收敛(例如,价值变化很小):
- 对于每个状态
s:- 如果
s是终止状态:V_new(s) = 0 - 否则:
V_new(s) = Σ_{s'} T(s, π(s), s') * [ R(s, π(s), s') + γ * V_old(s') ]
- 如果
- 对于每个状态
- 用
V_new更新V_old。
该算法会逐步将价值信息从终止状态向后传播,最终收敛到策略 π 的真实价值函数。
寻找最优策略:价值迭代 ⚡
上一节我们学会了如何评估一个给定策略。本节中,我们将主动寻找那个能获得最大期望效用的最优策略。
我们定义最优价值函数 V^*(s),它表示从状态 s 出发,所有可能策略中能获得的最大期望效用。
V^*(s) = max_π V^π(s)
相应地,定义最优 Q 价值函数:
Q^*(s, a) = Σ_{s'} T(s, a, s') * [ R(s, a, s') + γ * V^*(s') ]
最优价值函数满足 贝尔曼最优方程:
对于终止状态:
V^*(s) = 0,若 IsEnd(s) 为真。
对于非终止状态:
V^*(s) = max_{a ∈ Actions(s)} Q^*(s, a)
Q^*(s, a) = Σ_{s'} T(s, a, s') * [ R(s, a, s') + γ * V^*(s') ]
合并后得到:
V^*(s) = max_{a ∈ Actions(s)} { Σ_{s'} T(s, a, s') * [ R(s, a, s') + γ * V^*(s') ] }
一旦我们计算出 V^*(s),最优策略 π^*(s) 就是选择能最大化 Q 价值的行动:
π^*(s) = argmax_{a ∈ Actions(s)} Q^*(s, a)
价值迭代算法通过迭代方式求解贝尔曼最优方程:
- 将所有状态的价值
V(s)初始化为 0。 - 重复以下步骤直到收敛:
- 对于每个状态
s:- 如果
s是终止状态:V_new(s) = 0 - 否则:
V_new(s) = max_{a ∈ Actions(s)} { Σ_{s'} T(s, a, s') * [ R(s, a, s') + γ * V_old(s') ] }
- 如果
- 对于每个状态
- 用
V_new更新V_old。
算法收敛后,根据最优价值提取最优策略:
π^*(s) = argmax_{a ∈ Actions(s)} { Σ_{s'} T(s, a, s') * [ R(s, a, s') + γ * V(s') ] }
价值迭代的核心思想:通过不断迭代,将“未来最优可能回报”的信息从后往前传播,最终每个状态都能知晓选择哪个行动能导向期望回报最高的未来。
关于折扣因子与收敛性 ⚖️
折扣因子 γ 是一个介于 0 和 1 之间的数,它决定了我们对未来奖励的重视程度。
γ = 0:只关心即时奖励,完全“短视”。γ = 1:未来奖励与当前奖励同等重要。0 < γ < 1:未来奖励有价值,但距离越远,其现值越低。这是一种常见且合理的设定。
收敛性保证:
- 如果 MDP 的状态转移图是无环的,价值迭代保证收敛。
- 如果 MDP 包含循环,则需要折扣因子
γ < 1来保证价值迭代收敛。γ < 1可以防止无限循环中的奖励总和趋于无穷,确保计算稳定性。
总结 🎯
本节课中我们一起学习了:
- 马尔可夫决策过程:对具有不确定性的序列决策问题进行建模,核心要素是状态、行动、转移概率和奖励。
- 策略:MDP 的解决方案,是状态到行动的映射。
- 策略评估:计算给定策略的价值函数(期望效用)的迭代方法。
- 价值迭代:通过迭代求解贝尔曼最优方程,直接计算最优价值函数,并从中提取最优策略的算法。
我们从确定性搜索过渡到概率性决策,理解了在不确定性下如何通过衡量期望效用来做出理性选择。价值迭代为我们提供了一种计算最优策略的有效方法。
下一讲我们将进入强化学习,探讨当转移概率和奖励函数未知时,如何通过与环境的交互来学习最优策略。




🎓 课程 P8:强化学习入门


在本节课中,我们将学习强化学习的基本概念和核心算法。强化学习是机器学习的一个重要分支,它关注智能体如何在与环境的交互中,通过试错来学习最优策略,以最大化累积奖励。
🔍 强化学习概览
上一节课我们介绍了马尔可夫决策过程,它是一种建模框架。本节课我们将探讨如何学习这些模型,即强化学习。
强化学习与之前学习的模型不同,它不直接提供环境的完整模型(如转移概率和奖励函数),而是要求智能体通过与环境交互来学习。
📊 马尔可夫决策过程回顾
在深入强化学习之前,我们先回顾一下马尔可夫决策过程的核心概念。
一个MDP由以下部分组成:
- 状态集合:例如,在骰子游戏中,状态可以是“游戏中”或“结束”。
- 动作集合:从每个状态可以执行的动作,例如“继续”或“退出”。
- 转移概率:执行动作后,从一个状态转移到另一个状态的概率。
- 奖励函数:在状态转移过程中获得的即时奖励。
- 折扣因子:一个介于0和1之间的数,表示对未来奖励的重视程度,通常用
γ表示。
策略 π 是一个从状态到动作的映射,它告诉智能体在每个状态下应该采取什么行动。遵循一个策略会产生一个回合,即一系列状态、动作和奖励的序列。
我们关注两个核心价值函数:
- 状态价值函数
V^π(s):从状态s开始,遵循策略π所能获得的期望累积奖励。 - 动作价值函数
Q^π(s, a):从状态s开始,先执行动作a,然后遵循策略π所能获得的期望累积奖励。
它们之间的关系可以通过贝尔曼方程来描述:
V^π(s) = Q^π(s, π(s))
Q^π(s, a) = Σ_{s'} T(s, a, s') [ R(s, a, s') + γ * V^π(s') ]
🤖 强化学习范式
在强化学习中,智能体与环境不断交互:
- 智能体观察当前状态
s。 - 智能体根据某种策略选择一个动作
a并执行。 - 环境返回一个即时奖励
r和新的状态s'。 - 智能体根据这个经验
(s, a, r, s')更新其对世界的认知(模型或价值估计)。
这引出了两个核心问题:
- 行为策略:在当前状态下,我应该选择哪个动作?(探索与利用的权衡)
- 参数更新:如何根据新的经验更新我的模型或价值估计?
📈 强化学习算法
我们将介绍四类主要的强化学习算法,它们从不同角度解决学习问题。
1. 基于模型的蒙特卡洛方法
这种方法的核心思想是:通过交互数据直接估计MDP的模型参数(转移概率 T 和奖励 R),然后利用上节课的规划算法(如价值迭代)求解最优策略。
以下是具体步骤:
- 估计转移概率:对于每个
(s, a, s'),统计从(s, a)转移到s'的次数,除以执行(s, a)的总次数。
T̂(s, a, s') = Count(s, a, s') / Σ_{s''} Count(s, a, s'') - 估计奖励:对于每个
(s, a, s'),记录观察到的奖励,可以直接使用或取平均。 - 求解MDP:使用估计出的
T̂和R̂构建MDP,然后运行价值迭代等算法得到最优策略。
局限性:如果行为策略没有充分探索所有状态-动作对,那么某些部分的模型将永远无法被准确估计,可能导致错过潜在的高奖励区域。
2. 免模型的蒙特卡洛方法
我们不一定需要估计完整的MDP模型。如果我们能直接估计出最优策略的动作价值函数 Q*,那么最优策略就是选择每个状态下 Q* 值最大的动作。
作为热身,我们先学习如何估计一个给定策略 π 的动作价值函数 Q^π。免模型蒙特卡洛法的思想很简单:对于每个状态-动作对 (s, a),只考虑那些在回合中首次访问到 (s, a) 的时间点,然后计算从该时间点开始直到回合结束所获得的实际累积奖励(即回报 G_t),最后对所有这样的回报取平均值。

更新公式可以写作增量平均的形式:
Q^π(s, a) ← Q^π(s, a) + α * (G_t - Q^π(s, a))
其中 α 是学习率,G_t 是实际观测到的回报。
特点:
- 同策略:评估的策略就是产生数据的策略。
- 无偏:估计值收敛于真实的
Q^π。 - 高方差:因为依赖于单个回合的完整回报,波动可能很大。
- 必须等待回合结束:需要完整的轨迹才能计算
G_t。
3. 时序差分学习:Sarsa
为了降低方差并实现单步更新,我们引入自举的思想。Sarsa算法使用当前的估计值 Q^π 来构造更新目标,而不是等待完整的实际回报。
其更新基于五元组 (s, a, r, s', a'),其中 a' 是下一时间步根据当前策略 π 选择的动作。更新公式为:
Q^π(s, a) ← Q^π(s, a) + α * [ r + γ * Q^π(s', a') - Q^π(s, a) ]
目标值 r + γ * Q^π(s', a') 被称为时序差分目标。
与蒙特卡洛法的对比:
- 方差更低:目标值基于现有估计,而非单一路径的随机回报。
- 可在线更新:每得到一个
(s, a, r, s', a')就可以立即更新,无需等待回合结束。 - 有偏:因为目标值依赖于估计值
Q^π,而Q^π本身可能不准确。 - 同策略:评估和行动是同一个策略。
4. Q学习
Sarsa评估的是给定策略的价值,而Q学习直接学习最优动作价值函数 Q*。它是强化学习中最著名的算法之一。
Q学习的更新公式与Sarsa类似,但目标值的计算不同:
Q*(s, a) ← Q*(s, a) + α * [ r + γ * max_{a'} Q*(s', a') - Q*(s, a) ]
注意,这里我们使用了下一状态 s' 下所有可能动作的最大 Q* 值,而不是根据某个策略选出的具体动作 a' 的值。
与Sarsa的对比:
- 异策略:Q学习评估的是最优策略的价值,而用于生成数据的行动策略可以是任何探索性策略(如ε-贪心策略)。这使得它能够“离线”学习最优行为。
- 直接学习最优值:更新目标模拟了贝尔曼最优方程。
⚖️ 探索与利用的权衡
上述算法假设我们能够获得覆盖所有状态-动作对的数据。但在实践中,智能体必须自己决定如何行动以收集数据,这就引出了探索-利用困境。
- 纯利用:总是选择当前估计价值最高的动作。风险是可能陷入局部最优,永远发现不了真正更好的动作。
- 纯探索:总是随机选择动作。可以充分了解环境,但无法获得高累积奖励。
ε-贪心策略是一种简单有效的平衡方法:
- 以
1 - ε的概率选择当前认为最好的动作(利用)。 - 以
ε的概率随机选择一个动作(探索)。
通常,ε 会随着时间衰减,初期侧重探索,后期侧重利用。
🧠 大规模状态空间与函数近似
当状态空间非常庞大时(例如围棋棋盘状态、游戏像素画面),不可能遍历所有状态-动作对。此时,我们需要让智能体能够泛化,即对未见过但相似的状态做出合理估计。
解决方案是使用函数近似,例如线性函数或神经网络,来参数化 Q 函数:
Q(s, a; w) ≈ w · φ(s, a)
其中 φ(s, a) 是状态-动作对的特征向量,w 是权重参数。
以Q学习为例,更新规则变为对权重 w 的更新:
w ← w + α * [ r + γ * max_{a'} Q(s', a'; w) - Q(s, a; w) ] * ∇_w Q(s, a; w)
对于线性函数近似,∇_w Q(s, a; w) = φ(s, a),因此更新简化为:
w ← w + α * [ r + γ * max_{a'} Q(s', a'; w) - Q(s, a; w) ] * φ(s, a)
这非常类似于线性回归中的随机梯度下降。
📚 总结与拓展
本节课我们一起学习了强化学习的基础。我们从MDP的回顾开始,理解了强化学习智能体与环境交互的范式。接着,我们系统学习了四种核心算法:
- 基于模型的蒙特卡洛法:通过数据估计MDP,然后进行规划。
- 免模型蒙特卡洛法:直接通过平均回报来评估策略价值。
- Sarsa:使用时序差分自举进行同策略的策略评估。
- Q学习:使用时序差分自举进行异策略的最优价值函数学习。
我们还探讨了强化学习中的两大关键挑战:
- 探索与利用:通过ε-贪心等策略进行平衡。
- 大规模状态空间:通过函数近似(如线性模型、深度学习)实现泛化。
强化学习的核心思想可以概括为蒙特卡洛(从经验中平均学习)和自举(用自身估计更新自身)。它处于监督学习(全反馈、无状态)和更复杂序列决策问题的交叉点。深度强化学习(如DQN)将深度学习与Q学习结合,在Atari游戏、围棋等领域取得了突破性进展。其他高级方法还包括直接优化策略的策略梯度方法,以及结合价值与策略学习的Actor-Critic框架。
强化学习因其处理序列决策、延迟奖励和探索挑战的能力,成为人工智能迈向通用智能的关键路径之一。


🎮 课程9:游戏博弈1 - Minimax与Alpha-beta剪枝
在本节课中,我们将学习如何为双人、零和、回合制、完全可观察的游戏(如国际象棋)进行建模和求解。我们将介绍游戏树、Minimax算法及其变体,并探讨如何通过评估函数和Alpha-beta剪枝来提高计算效率。
📝 游戏的形式化定义
上一节我们通过一个“选桶”的例子引入了游戏的概念。本节中,我们将正式定义游戏所需的组件。
一个双人零和游戏可以形式化为以下元素:
- 玩家:包括智能体(我们控制的角色)和对手。
- 状态
S:包含游戏的所有信息,例如棋盘布局和当前轮到哪位玩家。 - 起始状态
START:游戏的初始状态。 - 动作函数
ACTIONS(s):在状态s下,当前玩家可以执行的所有合法动作。 - 后继函数
SUCCESSOR(s, a):执行动作a后到达的新状态。 - 终止判断
IS_END(s):检查状态s是否为游戏结束状态。 - 效用函数
UTILITY(s):在终止状态s下,智能体获得的收益(对手的收益是此值的相反数)。 - 玩家函数
PLAYER(s):返回在状态s下该行动的玩家。
以国际象棋为例:
- 状态
S编码了所有棋子的位置和当前回合的玩家。 - 动作是所有合法的走子。
- 终止状态是将军或和棋。
- 效用函数可以是:智能体(白方)赢为
+∞,和棋为0,输为-∞。
游戏有两个关键特征:
- 效用只在游戏终止时获得。
- 不同玩家在不同状态下拥有控制权。

🤖 策略与评估

在马尔可夫决策过程中,解决方案是一个策略。在游戏中,由于有两位玩家,我们需要为每位玩家定义策略。

策略 π 可以是确定性的,给定状态返回一个动作;也可以是随机性的,给定状态和动作返回执行该动作的概率。
当我们已知智能体和对手的策略时,我们可以评估从某个状态开始,遵循这些策略所能获得的期望效用。这类似于MDP中的策略评估。

以下是计算给定策略下状态价值 V_eval(s) 的递归公式:

if IS_END(s):
return UTILITY(s)
if PLAYER(s) == AGENT:
# 智能体按其策略的期望行动
return sum_over_actions( π_agent(s, a) * V_eval(SUCCESSOR(s, a)) )
else: # PLAYER(s) == OPPONENT
# 对手按其策略的期望行动
return sum_over_actions( π_opponent(s, a) * V_eval(SUCCESSOR(s, a)) )


⬆️ Expectimax:已知对手策略时的最优应对
然而,通常我们不知道对手的确切策略。一种假设是,我们知道对手会遵循某个随机策略 π_opp(例如,在“选桶”例子中以50%概率选择左边或右边的数字)。在这种情况下,作为智能体,我们应该选择能最大化自身期望效用的动作。
这引出了 Expectimax 算法。其状态价值 V_expectimax(s) 的计算如下:
if IS_END(s):
return UTILITY(s)
if PLAYER(s) == AGENT:
# 智能体选择最大化期望效用的动作
return max_over_actions( V_expectimax(SUCCESSOR(s, a)) )
else: # PLAYER(s) == OPPONENT
# 对手按其已知策略π_opp随机行动
return sum_over_actions( π_opp(s, a) * V_expectimax(SUCCESSOR(s, a)) )
在“选桶”例子中,若已知对手随机选择,则各桶的期望值分别为0、2、5。智能体会选择期望值最大的桶C,此时 V_expectimax(起始状态) = 5。

⬇️ Minimax:对抗性对手下的最优策略

更常见且保守的假设是,对手是对抗性的,总是试图最小化智能体的效用。这就是 Minimax 算法的核心思想。


在Minimax中,智能体(最大化方)和对手(最小化方)交替行动,各自优化自己的目标。其状态价值 V_minimax(s) 的递归定义为:
if IS_END(s):
return UTILITY(s)
if PLAYER(s) == AGENT:
# 智能体(Max方)选择最大化价值的动作
return max_over_actions( V_minimax(SUCCESSOR(s, a)) )
else: # PLAYER(s) == OPPONENT
# 对手(Min方)选择最小化价值的动作
return min_over_actions( V_minimax(SUCCESSOR(s, a)) )
智能体的最优策略 π_max(s) 就是达到 V_minimax(s) 最大值的动作:argmax_a V_minimax(SUCCESSOR(s, a))。
在“选桶”例子中,假设对手总是选择桶中最小的数字,则各桶的最小值分别为-50、1、-5。智能体会选择这些最小值中最大的那个,即桶B,此时 V_minimax(起始状态) = 1。
🔄 Minimax 与 Expectimax 的性质比较
我们可以比较在不同策略组合下,从起始状态获得的价值。用 π_max 表示智能体的Minimax策略,π_min 表示对手的Minimax(最小化)策略,π_七 表示某个其他策略(如随机策略)。
以下是几个重要性质(以“选桶”游戏数值为例):
- 上界性质:
V(π_max, π_min) >= V(π_expectimax(七), π_min)。即当对手确实是最小化者时,采用Minimax策略是最优的(例:1 >= -5)。 - 下界性质:
V(π_max, π_min) <= V(π_max, π_七)。即当对手并非最小化者时,采用Minimax策略获得的价值是一个保守下界(例:1 <= 2)。 - 先验知识优势:
V(π_max, π_七) <= V(π_expectimax(七), π_七)。即如果你知道对手的策略并据此优化(Expectimax),那么当对手确实遵循该策略时,你会获得更好的结果(例:2 <= 5)。
这些性质表明,如果你拥有关于对手行为的可靠知识,使用Expectimax通常比使用保守的Minimax更好。
🎲 引入随机性:Expectiminimax
游戏可能包含随机因素,例如掷骰子。我们可以引入“自然”作为第三方玩家,其策略是固定的(如50%概率)。这形成了 Expectiminimax 树,其中包含Max节点、Min节点和Chance(期望)节点。
算法只需在递归中增加对Chance节点的处理分支,计算其期望值即可。核心结构不变。
⚡ 提升计算效率
对于像国际象棋这样的游戏,博弈树的分支因子 B 很大(约35),深度 D 也很深(约50)。完整的Minimax搜索时间复杂度为 O(B^(2D)),这是不可行的。我们需要方法来加速。
方法一:评估函数
我们不搜索到终止状态,而是设置一个深度限制。当达到深度限制时,我们调用一个评估函数 EVAL(s) 来估计当前状态 s 的 V_minimax(s) 值。
评估函数利用领域知识,通过加权求和一组特征值来近似状态价值。例如,在国际象棋中,特征可能包括:
- 棋子数量差异(己方-对方)
- 棋子机动性差异
- 王的安全度
- 中心控制力
评估函数类似于搜索问题中的启发式函数,但它没有最优性保证。


方法二:Alpha-beta 剪枝
Alpha-beta剪枝是一种通过避免搜索不可能影响最终决策的分支来修剪博弈树的技术。
核心思想是维护两个值:
- α:对于Max节点,是当前搜索路径上已探索到的效用下界。Max节点至少能得到α。
- β:对于Min节点,是当前搜索路径上已探索到的效用上界。Min节点至多能得到β。
在搜索过程中,如果发现某个节点的 α >= β,就意味着从该节点出发的子树中,不存在任何一条路径的效用值能同时满足Max节点的下界和Min节点的上界,即这条路径不可能成为最优路径的一部分,因此可以剪枝——停止探索该节点的其余后继。
节点顺序至关重要。最优的节点排序(对于Max节点,按评估值降序探索;对于Min节点,按评估值升序探索)可以将搜索复杂度降至约 O(B^D),相当于搜索深度翻倍。即使随机排序,平均性能也远优于最坏情况。
📚 总结
本节课中我们一起学习了:
- 游戏的形式化:如何用状态、动作、玩家、效用等组件定义双人零和回合制游戏。
- 策略评估:在给定双方策略时,如何计算状态的期望效用。
- Expectimax算法:当已知对手策略时,智能体如何通过最大化期望效用来行动。
- Minimax算法:当假设对手对抗性时,智能体(Max)与对手(Min)交替优化,以及如何计算状态价值和最优策略。
- 算法性质:比较了不同策略假设下的价值边界,强调了利用对手先验知识的好处。
- 效率提升:面对巨大博弈树时,如何使用评估函数进行深度限制搜索,以及如何运用Alpha-beta剪枝技术来避免不必要的搜索,大幅提升效率。

理解这些基础算法是构建更复杂游戏AI的基石。在下节课中,我们将探讨游戏中的学习问题。


浙公网安备 33010602011771号