康奈尔大学-CS4780-智能系统机器学习笔记-全-
康奈尔大学 CS4780 智能系统机器学习笔记(全)
机器学习:001:监督学习设置 🎯
在本节课中,我们将要学习机器学习的基本概念,特别是监督学习的核心设置。我们将从宏观视角了解什么是机器学习,回顾其发展历史,并最终形式化地定义监督学习问题。
什么是机器学习?🤖
上一节我们介绍了课程背景,本节中我们来看看机器学习的核心思想。
传统计算机科学中,程序员编写程序来处理输入数据并生成输出。例如,编写一个MP3播放器程序,需要了解MP3文件格式并编写解码逻辑。
然而,机器学习处理的是另一类问题。例如,医生提供一张fMRI脑部扫描图,询问患者是否患有阿尔茨海默症。对于这类问题,没有现成的“维基百科”页面可以查阅如何编写程序。

解决这类问题的关键在于数据。我们可以收集过去的大量fMRI图像,并标注哪些患者后来确诊了阿尔茨海默症(标签为“是”),哪些没有(标签为“否”)。这样,我们就拥有了带标签的数据。

机器学习算法正是利用这些数据和期望的输出(标签),通过计算自动生成一个程序(或模型)。这个生成的程序,如果输入同样的数据,应该能产生我们期望的输出。这个过程称为训练。
训练完成后,我们就可以将这个程序应用于医生最初提供的、未知的新fMRI图像上,程序会生成一个预测结果。这个过程称为测试。
核心流程公式化描述:
训练阶段:算法 + (数据, 标签) -> 程序/模型
测试阶段:程序/模型 + 新数据 -> 预测结果
简而言之,机器学习是用数据和答案来生成程序,而不是直接由程序员编写程序。随着提供的数据越来越多,生成的程序性能会越来越好,这就是“学习”的含义。
机器学习简史 📜

上一节我们了解了机器学习的基本范式,本节中我们回顾一下它的发展历程。
- 1952年:塞缪尔的跳棋程序。这被认为是第一个能从经验中学习的算法。它通过存储对弈记录并不断优化策略来提升水*。
- 1957年:弗兰克·罗森布拉特与感知机。在康奈尔大学发明的感知机算法,是当今人工神经网络和深度学习的基石。其核心思想至今仍在广泛应用,当时的主要限制是计算能力。
- AI的繁荣与寒冬。感知机等成果引发了第一次AI热潮。然而,明斯基和帕佩特在其著作中指出,单层感知机连简单的“异或”(XOR)问题都无法解决。这导致人们对AI的期望破灭,研究资金大幅缩减,进入了“AI寒冬”。
- 机器学习的新生。从AI领域中分化出的“机器学习”更侧重于从数据中自底向上地学习,并大量借鉴统计学和优化理论来处理不确定性,而非纯粹的逻辑推理。这为领域带来了新的活力。
- 1994年:TD-Gammon。IBM的杰拉尔德·特索罗利用神经网络和强化学习(让程序自我对弈),开发出了西洋双陆棋程序TD-Gammon。它通过自我博弈学习,最终击败了人类世界冠军,甚至发现了新的开局策略,震撼了学界。
- 1997年:深蓝。IBM团队在此基础上挑战国际象棋,最终“深蓝”击败了世界冠军加里·卡斯帕罗夫(尽管深蓝更多使用了传统AI的搜索方法,但局面评估部分采用了学习技术)。
- 今日的机器学习。如今,机器学习已无处不在:搜索引擎排序、垃圾邮件过滤、新闻推荐、自动驾驶汽车等。它已成为生物学、化学等多个学科的分析工具。
机器学习的类型 🗂️
上一节我们走过了历史长廊,本节中我们正式看看机器学习的几种主要类型。
以下是三种主要的机器学习类型:
- 监督学习:本课程的核心。我们拥有带标签的数据集(即输入数据和对应的正确答案),目标是学习一个从输入到输出的映射函数。例如:垃圾邮件分类(输入:邮件,输出:垃圾/非垃圾)、房价预测。
- 无监督学习:我们只有数据,没有标签。目标是发现数据中隐藏的结构或模式。例如:客户分群、主题建模。
- 强化学习:智能体通过与环境交互,根据最终获得的奖励或惩罚(稀疏反馈)来学习策略。例如:TD-Gammon程序、机器人控制。
监督学习的形式化定义 📐
上一节我们区分了机器学习的类型,本节中我们将深入聚焦,形式化地定义监督学习。
监督学习的高级目标是从数据中做出预测。
数据与分布
我们被给予一个数据集 D,它包含 n 个数据点及其对应的标签:
D = {(x1, y1), (x2, y2), ..., (xn, yn)}
其中:
xi是第 i 个特征向量,代表输入数据。yi是第 i 个标签,代表我们期望的输出或答案。




这些数据点是从某个未知的真实分布 P 中独立同分布 地采样得到的。我们无法直接知晓这个分布,只能通过观测到的数据来窥探它。


学习目标
我们的目标是利用数据集 D,学习一个函数 h: X -> Y,使得对于从分布 P 中新采样的数据 (x, y),h(x) 能尽可能准确地预测出 y。
核心目标公式化描述:
给定: D = {(x_i, y_i)} ~ P(x, y)
目标: 学习函数 h,使得 h(x) ≈ y 对于 (x, y) ~ P 成立。


输入与输出空间
- 输入空间 X:通常是 D 维的实数向量空间
R^D。每个数据实例都被概括为一个包含 D 个数字的向量。例如,一封邮件可以转化为一个“词袋”向量。 - 输出空间 Y:取决于任务类型。主要有以下两种:
- 分类:预测离散类别。
- 二分类:
Y = {-1, +1}或{0, 1}。例如:垃圾邮件过滤、人脸检测。 - 多分类:
Y = {1, 2, ..., K}。例如:新闻文章分类(体育、政治、科技等)。
- 二分类:
- 回归:预测连续数值。
Y = R(实数集)。例如:房价预测、身高预测。
- 分类:预测离散类别。


特征向量示例




以下是特征向量 x 的构建示例:



- 患者数据预测再入院:
x = [性别(0/1), 年龄(岁), 身高(cm), 血压, 心率, ...]
标签y:是否在6周内再次入院(是=1,否=0)。 - 文本分类(词袋模型):
构建一个维度为词典大小的向量。每个维度对应一个单词,其值为该单词在文档中出现的次数。
x = [“a”出现次数, “apple”出现次数, ..., “zebra”出现次数]
这种方法忽略了词序,但通常效果很好。

总结 🎓

本节课中我们一起学习了机器学习的核心思想。我们了解到,机器学习通过数据和期望输出来自动生成程序,从而解决那些难以直接编程的问题。我们回顾了从感知机到深度学习的波澜壮阔的历史。最后,我们重点形式化地定义了监督学习的框架:即从独立同分布采样的带标签数据中,学习一个从特征空间到标签空间的映射函数,并区分了分类与回归两大任务类型。理解这个基础设置是学习后续所有具体算法的重要前提。
机器学习:002:监督学习设置(续)🎯













在本节课中,我们将继续学习监督学习的基本设置。我们将深入探讨数据表示、假设空间、损失函数以及机器学习中至关重要的“泛化”概念。理解这些基础是构建有效机器学习模型的关键。










数据与分布 📊
上一节我们介绍了机器学习的基本框架。本节中,我们来看看数据的具体表示及其背后的分布。




我们有一个数据集 D,它包含 n 个数据点。每个数据点是一个特征向量 x 和标签 y 的配对:
(x_i, y_i) for i = 1, ..., n
这些数据点来自一个我们无法直接获知的分布 P。特征向量 x 来自特征空间 𝒳,标签 y 来自标签空间 𝒴。


这个分布 P 是现实世界数据生成过程的抽象。例如,如果你想构建一个人脸分类器,P 就代表了你在校园里随机遇到并拍照的学生人脸的分布。如果你在北京做同样的事,P 就会不同。我们不知道 P 的具体形式,如果知道,预测就会变得非常简单。

一个关键点是,训练数据必须来自与你打算部署模型时相同的分布。一个著名的反面案例是诺基亚早期的面部识别系统。该系统在芬兰赫尔辛基(主要是白种人)的数据上训练,当销售到世界其他地区时,无法正确识别非白种人的面孔,导致了严重的泛化失败。





特征表示:稠密与稀疏 🔢

无论原始数据是什么(如患者记录、文本文档、图像),我们都需要将其表示为固定维度的向量 x。
以下是几种常见的数据类型及其向量化思路:
- 患者数据:向量可能包含年龄、血压、病史等数值。
- 文本文档(如邮件):常用“词袋”表示法,向量的每个维度对应词典中的一个词,值表示该词是否出现或出现的次数。
- 图像:一个6兆像素的图像,每个像素有红、绿、蓝三个通道值,可以展开成一个约1800万维的向量。虽然这种原始像素表示很高维,但现代方法(如卷积神经网络)能有效处理。







关于向量表示,一个重要区别是稠密向量和稀疏向量:
- 稠密向量:向量中大多数维度都有非零值。
- 稀疏向量:向量中绝大多数维度都是零,只有少数维度有值。文本文档的“词袋”表示就是典型的稀疏向量。稀疏表示可以节省大量存储和计算资源。



学习过程:假设空间与损失函数 🧠
现在,我们形式化机器学习的过程。目标是找到一个程序(函数)h,它能根据输入 x 预测输出 y。
训练阶段:我们将数据集 D(包含 x_i 和对应的真实 y_i)输入机器学习算法。算法输出一个函数 h,理想情况下,对于训练数据有 h(x_i) ≈ y_i。
测试阶段:对于一个未见过的、来自相同分布 P 的新实例 x,我们使用学到的函数 h 进行预测 h(x),希望它接*真实的 y。
我们并非学习任意函数,而是从一个预先定义的假设空间 ℋ 中选择。ℋ 是我们认为可能适用于当前问题的函数集合(例如,所有可能的决策树,或所有线性分类器)。选择 ℋ 是数据科学家的关键职责之一。
为了评估 ℋ 中哪个函数 h 更好,我们需要损失函数 L。损失函数衡量函数 h 在数据集 D 上的表现,损失值越低越好。
以下是几个常见的损失函数示例:
- 0-1损失:用于分类问题,计算错误预测的比例。
L_0-1(h, D) = (1/n) * Σ_i [h(x_i) ≠ y_i]
其中[ ]是指示函数,条件为真时值为1,否则为0。


-
*方损失:用于回归问题,惩罚预测值与真实值之间的较大差距。
L_square(h, D) = (1/n) * Σ_i (h(x_i) - y_i)^2 -
绝对损失:同样用于回归问题,对误差的惩罚是线性的。
L_absolute(h, D) = (1/n) * Σ_i |h(x_i) - y_i|
*方损失对大误差惩罚更重,有助于避免极端错误,但对异常值敏感。绝对损失对大误差的惩罚相对温和,对异常值更具鲁棒性。选择哪种损失取决于具体问题。
因此,学习就是寻找假设空间 ℋ 中那个在训练数据 D 上损失最小的函数 h 的过程。
泛化:机器学习的核心目标 🎯
仅仅在训练数据上表现好是不够的。考虑一个极端算法:它纯粹记忆训练数据。对于训练集中出现过的 x_i,它输出对应的 y_i;对于未出现过的 x,它总是输出 y_1。这个算法在训练集上的0-1损失为0,但它没有任何预测新数据的能力。这就是过拟合或缺乏泛化能力。
我们真正追求的是泛化能力。即,对于从真实分布 P 中抽取的任何(而不仅仅是训练集中的)样本 (x, y),我们都希望 h(x) ≈ y。与之对应的泛化损失是期望损失:
Generalization Loss = E_(x,y)~P [ L(h, (x,y)) ]
然而,我们无法直接计算它,因为我们不知道分布 P。

解决方案是使用训练-测试集分割。在收集数据后,立即将其随机分为两部分:
- 训练集:用于让机器学习算法寻找函数 h。
- 测试集:被严格保留,不参与训练过程。
当算法得到函数 h 后,我们在从未见过的测试集上计算损失。这个测试损失是对泛化损失的一个无偏估计。如果模型只在训练集上表现好(如记忆算法),在测试集上表现很差,我们就知道它泛化能力差。
本节课中我们一起学习了监督学习的关键概念:数据与分布的关系、特征表示方法、通过假设空间和损失函数形式化的学习过程,以及评估模型性能的核心——泛化能力与训练-测试集分割。理解这些基础是避免常见陷阱和构建实用机器学习系统的第一步。
机器学习:003:k-*邻算法











在本节课中,我们将要学习机器学习中的一个基础且直观的算法——k-*邻算法。我们将从回顾机器学习的基本框架开始,然后深入探讨如何评估模型性能,最后详细介绍k-*邻算法的原理、假设和应用。

回顾与模型评估

上一节我们介绍了机器学习的基本框架:我们拥有一个由特征向量和标签对组成的数据集 D,目标是找到一个从特征 X 预测标签 y 的函数 h。这个函数 h 是从一个假设类 H(例如所有可能的决策树)中选择出来的。我们通过最小化在训练数据上的损失函数 L 来学习这个函数。
然而,仅仅在训练数据上表现完美(例如记忆所有数据的“算法3”)是不够的,因为我们的真正目标是让模型在未见过的数据上也能表现良好,即具有良好的泛化能力。我们真正希望最小化的是在数据真实分布 P 上的期望损失。
由于我们不知道真实分布 P,我们通过将数据集分割为训练集和测试集来*似评估泛化性能。模型只在训练集上学习,其最终性能通过在从未见过的测试集上计算损失来评估。

以下是进行数据集分割时需要注意的关键点:
- 独立同分布数据:如果数据是独立同分布采集的,应随机打乱后进行分割。
- 时间序列数据:如果数据具有时间成分(如邮件、股价),必须按时间顺序分割,确保训练数据来自测试数据“之前”的时间段,避免信息泄露。
- 分组数据:如果数据来自多个个体(如多个病人的多次测量),应以个体为单位进行分割,确保同一个体的数据不会同时出现在训练集和测试集中。

为了进一步优化模型选择和避免过拟合测试集,实践中常采用训练集-验证集-测试集的三分法。验证集用于在多个模型或参数中选择表现最佳的一个,而测试集仅在最终评估中使用一次,以提供对泛化误差的无偏估计。
根据大数定律,当测试集样本量 N 趋向无穷大时,测试集上的*均损失会收敛于真实的期望损失。
没有免费的午餐定理
在介绍具体算法前,我们需要理解一个核心思想:不存在一个在所有问题上都表现最好的“万能”算法。这是因为任何学习算法都隐含着对数据规律的假设。例如,在之前的“派对游戏”中,大多数人假设数据点构成的函数是*滑的,但如果真实情况完全违背这个假设(比如是随机或对抗性的),基于*滑假设的预测就会失败。
因此,机器学习的关键在于:分析数据特性,理解不同算法所做的假设,并选择其假设与数据特性相匹配的算法。盲目偏爱单一算法(如深度学习)而不考虑其假设是否成立,是实践中常见的错误。
k-*邻算法详解
现在,我们来看第一个具体的机器学习算法——k-*邻算法。这是一种非常古老(1967年)且直观的算法。
核心思想与假设

k-*邻算法基于一个核心假设:在特征空间中,彼此接*(相似)的数据点,很可能具有相同的标签。这是一种基于“相似度”进行推断的方法。
算法步骤
- 给定:一个训练数据集 D,一个正整数 k(通常是奇数,如1, 3, 5),一个距离度量标准,以及一个待预测的测试点 x。
- 寻找邻居:在训练集 D 中,找到与测试点 x 距离最*的 k 个数据点,构成集合 S(x)。
- 投票决策:统计这 k 个邻居中每个类别标签出现的次数。
- 输出:将出现次数最多的类别标签作为测试点 x 的预测结果。



距离度量
算法的性能高度依赖于如何定义“距离”或“相似度”。最常用的距离度量家族是闵可夫斯基距离。

对于两个 d 维向量 x 和 z,其闵可夫斯基距离定义为:
distance(x, z) = ( Σ_{i=1}^{d} |x_i - z_i|^p )^(1/p)
其中 p 是一个参数。这个公式定义了一个距离家族:

- 当 p = 1 时,称为曼哈顿距离或L1距离。
distance = |x1 - z1| + |x2 - z2| + ... - 当 p = 2 时,称为欧几里得距离或L2距离。这是我们最熟悉的直线距离。
distance = sqrt((x1 - z1)^2 + (x2 - z2)^2 + ...) - 当 p → ∞ 时,距离由最大维度差决定,称为切比雪夫距离。
distance = max(|x1 - z1|, |x2 - z2|, ...)


选择合适的 p 值,本质上是在定义不同特征维度对“相似性”贡献的权重方式。

总结
本节课中我们一起学习了机器学习模型评估的正确方法,理解了“没有免费午餐定理”所揭示的算法假设重要性,并详细探讨了第一个机器学习算法——k-*邻算法。k-*邻算法以其简单直观著称,其核心在于利用距离度量寻找相似样本并进行投票决策。记住,它的有效性建立在“相似数据点具有相似标签”这一假设之上,并且距离度量的选择至关重要。下一节课,我们将通过演示来进一步观察k-*邻算法的实际行为。
机器学习:004:维度灾难与感知机

在本节课中,我们将要学习K*邻分类器的一个核心局限性——维度灾难,并介绍一种克服此问题的新算法:感知机。我们将探讨高维空间对距离计算的影响,以及感知机如何通过寻找一个分离超*面来进行分类。



维度灾难的回顾
上一节我们介绍了K*邻分类器及其理论基础。本节中我们来看看它在高维空间中面临的核心挑战。

K*邻分类器的基本假设是:相似的数据点具有相似的标签。对于一个测试点,算法会寻找训练集中与其最接*的K个点,并采用这些邻居的标签作为预测结果。理论上,当数据量趋于无穷时,K*邻分类器的错误率最多只是最优贝叶斯分类器的两倍。
然而,这个乐观结论有一个重要的前提,那就是“维度灾难”。让我们通过一个思想实验来理解它。

假设数据点均匀分布在一个D维的单位超立方体(每条边长度为1)中。对于其中任意一点,我们想找到一个能包含其K个最*邻的最小立方体,设其边长为L。
以下是推导过程:
- 该小立方体的体积是 ( L^D )。
- 由于数据均匀分布,小立方体包含的点数比例应大致等于其体积占整个超立方体体积的比例。整个超立方体体积为1,因此有:
[
L^D \approx \frac{K}{N}
] - 由此可以解出边长L:
[
L \approx \left( \frac{K}{N} \right)^{\frac{1}{D}}
]
现在,让我们代入具体数值看看。假设K=10,N=1000,那么 ( K/N = 0.01 )。我们计算不同维度D下的L值:
- 当 D=2 时,( L \approx 0.1 )。小立方体边长约为整体的十分之一。
- 当 D=10 时,( L \approx 0.63 )。小立方体已经覆盖了大部分空间。
- 当 D=100 时,( L \approx 0.955 )。
- 当 D=1000 时,( L \approx 0.995 )。
这意味着,在高维空间中,为了找到最*的10个邻居,我们需要的“邻域”几乎和整个数据空间一样大。这导致了两个严重问题:
- “最*”的邻居实际上并不*。所有数据点都大致均匀地分布在空间的边缘区域,彼此距离都很远,不存在真正意义上的“*邻”。
- K*邻的基本假设失效。既然没有数据点是真正“相*”的,那么“相*的点标签相似”这个前提就失去了意义。
为什么高维空间中的数据点会聚集在边缘?考虑一个简单的概率解释:在每一维上,一个点落在“内部”(比如距离边界ε以上)的概率是 ( 1 - 2\epsilon )。在D维空间中,一个点在所有维度上都落在内部的概率是 ( (1 - 2\epsilon)^D )。当D很大时,这个概率会迅速趋*于0。因此,几乎所有点都至少在某几个维度上靠*边界,从而成为“边缘点”。

应对维度灾难:低维内在结构
既然K*邻在高维均匀分布数据上失效,为什么它在处理像图片(像素维度很高)这样的数据时又能工作呢?
关键在于,真实数据(如图片)的分布不是均匀的。它们通常具有低维内在结构。具体表现为以下两种形式:
- 子空间:数据实际上分布在一个维度低得多的线性子空间中。例如,虽然图片有成千上万个像素(维度),但描述一张人脸可能只需要几十个特征(如脸型、五官位置等)。算法如主成分分析(PCA)可以帮助我们发现并投影到这样的子空间。
- 流形:数据分布在一个低维的非线性流形上。流形在局部类似于欧几里得空间(例如,地球表面局部看起来是*的),但全局结构复杂。在这种情况下,局部距离仍然有意义,因此K*邻在局部区域内可以工作。



因此,K*邻有效的关键前提是数据具有低的内在维度。在处理高维数据时,一个常用的预处理步骤就是使用PCA等降维方法,以揭示其内在的低维结构。
从K*邻到感知机


除了维度灾难,K*邻还有另一个实际缺点:测试阶段计算成本高。要对一个测试点进行分类,需要计算它与训练集中所有N个点的距离,时间复杂度为 ( O(N \cdot D) )。当数据量N极大时,这变得难以承受。


现在,我们介绍一种不同的算法——感知机。它由Frank Rosenblatt于1957年在康奈尔大学提出,被认为是第一个机器学习算法。感知机做出了一个与K*邻截然不同的、但同样直观的假设。
感知机假设:存在一个超*面,能够将不同类别的数据点完全分开。也就是说,所有正类点位于超*面的一侧,所有负类点位于另一侧。
在二维空间中,超*面就是一条直线;在三维空间中,它是一个*面;以此类推。数学上,一个超*面由权重向量 ( \mathbf{w} ) 和偏置 ( b ) 定义,是所有满足以下方程的点 ( \mathbf{x} ) 的集合:
[
\mathbf{w}^T \mathbf{x} + b = 0
]
分类时,对于一个新测试点 ( \mathbf{x}{test} ),我们只需计算:
[
\text{sign}(\mathbf{w}^T \mathbf{x} + b)
]
如果结果为正,则预测为一类;为负,则预测为另一类。这个计算非常快,与训练集大小N无关。
一个自然的疑问是:这个“数据线性可分”的假设是否太强?有趣的是,维度灾难从另一个角度提供了启示:在高维空间中,点与点之间距离很远,使得找到一个分离超*面反而更容易。事实上,我们后续会学到,通过将数据映射到更高维甚至无限维的空间,几乎总是可以找到一个分离超*面。
为了简化模型,我们可以通过一个技巧消除偏置项 ( b )。具体做法是:
- 给每个数据点 ( \mathbf{x}_i ) 增加一个值为1的维度,得到新的数据点 ( \mathbf{x}_i' = [\mathbf{x}_i; 1] )。
- 将权重向量也扩展一维,新权重为 ( \mathbf{w}' = [\mathbf{w}; b] )。
此时,决策函数变为:
[
\mathbf{w}'^T \mathbf{x}' = \mathbf{w}^T \mathbf{x} + b
]
这样,我们只需要学习一个扩展后的权重向量 ( \mathbf{w}' ),对应的超*面形式变为 ( \mathbf{w}'^T \mathbf{x}' = 0 ),这是一个必须穿过原点的超*面。从几何上看,这相当于将原始数据*面整体“抬升”到了高一维的空间中。

总结
本节课中我们一起学习了:
- 维度灾难:在高维空间中,数据点趋于分布在边缘,导致彼此距离都很远,这使得基于“邻*性”的K*邻算法基本假设失效。
- 低维内在结构:真实数据往往具有低维的子空间或流形结构,这是K*邻等算法在实践中仍能工作的关键。降维是处理高维数据的重要预处理步骤。
- 感知机算法:作为一种线性分类器,感知机假设数据是线性可分的,并通过寻找一个分离超*面来分类。它的测试阶段计算效率远高于K*邻,尤其适合处理高维数据。我们还学习了通过数据增广来简化模型表示的方法。
下一节课,我们将深入探讨感知机算法的具体训练过程,即如何从数据中自动找到那个分离超*面。
机器学习:005:感知机算法
在本节课中,我们将要学习感知机算法。这是一种用于二分类问题的线性分类器,其核心思想是找到一个能够将不同类别的数据点分开的超*面。我们将从算法原理、几何直观、具体步骤以及其局限性等方面进行探讨。

感知机算法原理
上一节我们介绍了K*邻算法及其面临的“维度灾难”问题。本节中,我们来看看感知机算法,它通过寻找一个线性决策边界来简化模型。
感知机算法基于一个核心假设:存在一个超*面能够完美地将两类数据分开。对于二维数据,这个超*面就是一条直线;对于更高维度的数据,则是一个*面或超*面。
核心公式:感知机的决策函数为:
f(x) = sign(w^T x + b)
其中,w 是权重向量,b 是偏置项,sign 是符号函数。如果结果为正,则预测为正类(+1);如果为负,则预测为负类(-1)。
为了简化推导和实现,我们通常进行一个技巧性变换:将偏置 b 并入权重向量。我们定义新的增广特征向量 x̄ = [x; 1] 和增广权重向量 w̄ = [w; b]。这样,决策函数就简化为:
f(x) = sign(w̄^T x̄)
感知机学习算法
感知机学习算法是一种在线错误驱动算法。其目标是通过迭代调整权重向量 w,使得所有训练样本都被正确分类。
以下是感知机算法的具体步骤:
- 初始化:将权重向量
w初始化为零向量(或小的随机值)。 - 迭代:遍历整个训练数据集。
- 预测与更新:对于每个样本
(x_i, y_i)(其中y_i ∈ {+1, -1}):- 计算当前预测:
ŷ = sign(w^T x_i)。 - 如果预测错误,即
y_i * (w^T x_i) ≤ 0,则更新权重向量:
w ← w + y_i * x_i
这个更新规则直观易懂:如果将一个正类样本误判为负类,就将该样本向量加到权重上,使权重向量更“靠*”正类方向;反之,则减去该样本向量。
- 计算当前预测:
- 终止条件:重复步骤2-3,直到在一次完整的遍历中,没有发生任何分类错误(即算法收敛)。
代码描述:
def perceptron_train(X, y):
w = np.zeros(X.shape[1]) # 初始化权重
while True:
mistakes = 0
for i in range(len(X)):
if y[i] * np.dot(w, X[i]) <= 0: # 分类错误
w = w + y[i] * X[i] # 更新权重
mistakes += 1
if mistakes == 0: # 没有错误,收敛
break
return w
算法演示与几何直观
为了帮助理解,我们可以可视化感知机的学习过程。想象在二维*面上,权重向量 w 定义了决策边界(一条垂直于 w 的直线)。
- 初始状态:
w为零向量,没有明确的决策边界。 - 遇到错误:当遇到一个被错误分类的正样本
x时,我们执行更新w = w + x。这相当于将w向x的方向旋转,使得新的决策边界更有可能将该样本划到正侧。 - 反复修正:算法会持续遍历数据,每次遇到错误分类的样本就微调
w,直到所有样本都被正确分类。
一个关键问题是:算法会永远循环下去吗?答案是否定的。只要数据是线性可分的(即存在一个完美的超*面),感知机算法保证在有限步内收敛。这个结论由著名的感知机收敛定理保证。
收敛定理简述
感知机收敛定理是算法有效性的理论基石。其核心思想是:如果存在一个完美的分隔超*面(记其权重为 w*),那么感知机算法学到的权重 w 会随着更新越来越“接*”这个理想的 w*。

定理的简化论证基于以下观察:每次权重更新,w 与 w* 的内积都会增加,而 w 的范数增长是有限的。这共同意味着错误更新的次数存在一个上界。因此,算法不可能无限地更新下去,必然会在有限步后停止(即找到分隔超*面)。
注意:收敛定理的前提是数据必须线性可分。如果数据不是线性可分的(例如异或问题),感知机算法将永远不会停止(陷入无限循环)。
感知机的特点与局限性
感知机是神经网络和支持向量机等现代算法的重要先驱。理解其特点与局限至关重要。
优点:
- 简单高效:算法思想简单,易于实现。
- 理论保证:对于线性可分数据,保证收敛。
- 在线学习:可以逐个样本进行更新,适合流式数据。
局限性:
- 线性可分假设:仅适用于线性可分数据,现实问题中这一假设往往不成立。
- 找到任意解:收敛定理只保证找到一个分隔超*面,但不保证是最优的(如间隔最大化的那个)。后来的支持向量机算法解决了这个问题。
- 对噪声敏感:如果数据中存在噪声或异常点,算法可能无法收敛或找到的边界不理想。
与K*邻算法相比,感知机一旦训练完成,只需存储权重向量 w,预测速度极快(只需计算一次内积),而K*邻需要存储全部数据并计算与所有样本的距离。这是模型复杂度与计算效率之间的典型权衡。
本节课中我们一起学习了感知机算法的基本原理、更新规则、几何解释以及其收敛性。感知机是理解线性分类和后续更复杂模型(如神经网络)的基础。其核心思想——通过错误来驱动学习并调整模型参数——在机器学习中影响深远。请务必通过课后练习和阅读收敛定理的完整证明来加深理解。
机器学习:006:感知机收敛性证明 🧠


在本节课中,我们将学习感知机算法的收敛性证明。感知机是一个简单而强大的线性分类器,但它的有效性依赖于一个关键假设:数据必须是线性可分的。我们将一步步证明,如果存在一个能将数据完美分开的超*面,那么感知机算法一定能在有限步内找到这样一个超*面。

上一节我们介绍了感知机算法的基本流程。本节中,我们来看看如何从数学上证明它的收敛性。
问题设定与假设
感知机算法假设存在一个超*面能将所有数据点正确分类。形式化地说,我们假设存在一个权重向量 W*,使得对于数据集 D 中的每一个样本 (x, y)(其中标签 y ∈ {+1, -1}),都满足:
y (W*ᵀ x) > 0
这意味着所有正类样本都落在超*面的一侧,所有负类样本都落在另一侧。
为了简化证明,我们可以对数据和权重向量进行归一化,而不改变问题的本质。
以下是两个关键的归一化步骤:
- 归一化权重向量:由于如果 W* 是一个解,那么任何正数乘以 W* 也是一个解。因此,我们可以选择那个范数为1的 W,即 **||W|| = 1**。
- 归一化数据点:我们可以将所有数据点 x 除以数据集中最大的范数,从而保证所有数据点的范数不超过1,即 ||x|| ≤ 1。

经过这些处理,我们的数据点都落在一个单位球内,而我们要寻找的解向量 W* 位于单位球面上。
证明的核心思路


证明的核心在于追踪两个量在每次权重更新后的变化:
- 当前权重 W 与理想权重 W* 的内积 WᵀW*。
- 当前权重 W 自身的范数*方 WᵀW。


直观上,如果 WᵀW* 增长得很快,而 WᵀW 增长得很慢,那就意味着 W 不仅在变长,更是在方向上朝着 W* 靠*。我们将证明,在每次错误分类并更新后:
- WᵀW* 至少增加一个固定值 γ(间隔)。
- WᵀW 至多增加 1。
这两个不等式将共同迫使更新次数 M 存在一个上界。
证明推导
1. 内积 WᵀW* 的下界
感知机在发现一个分类错误的样本 (x, y) 时会进行更新,更新规则为:
W ← W + y x
此时,我们知道该样本被错误分类,因此有:
y (Wᵀ x) ≤ 0

现在考虑更新后内积的变化:
新 WᵀW = (W + y x)ᵀ W = WᵀW* + y (xᵀ W*)**
根据我们的假设,理想权重 W* 能正确分类所有样本。我们定义 间隔 (margin) γ 为所有样本中到超*面 W* 的最小“距离”:
γ = min_(x,y)∈D y (xᵀ W*) > 0
因此,对于任何样本,都有 y (xᵀ W*) ≥ γ。将其代入上式,我们得到:
新 WᵀW ≥ WᵀW + γ**
结论:每次更新,W 与 W* 的内积至少增加 γ。
2. 范数*方 WᵀW 的上界




现在考虑权重向量自身长度的变化:
新 WᵀW = (W + y x)ᵀ (W + y x) = WᵀW + 2y (Wᵀ x) + y² (xᵀ x)
我们来分析每一项:
- WᵀW:更新前的范数*方。
- 2y (Wᵀ x):由于这是导致更新的错误样本,所以 y (Wᵀ x) ≤ 0,因此这一项 ≤ 0。
- y² (xᵀ x):因为 y ∈ {+1, -1},所以 y² = 1。又因为数据已归一化,||x|| ≤ 1,所以 xᵀ x ≤ 1。
综合以上,我们可以得到:
新 WᵀW ≤ WᵀW + 1
结论:每次更新,W 的范数*方至多增加 1。
3. 推导更新次数的上界
假设算法运行中总共进行了 M 次更新。

根据内积下界的结论,经过 M 次更新后(初始 W=0,所以 WᵀW = 0):
WᵀW ≥ Mγ ... (1)
根据范数上界的结论,经过 M 次更新后(初始 W=0,所以 WᵀW = 0):
WᵀW ≤ M ... (2)
现在,我们利用柯西-施瓦茨不等式将 (1) 和 (2) 联系起来。该不等式指出:
|WᵀW| ≤ ||W|| ||W||
因为 WᵀW ≥ 0,且 ||W*|| = 1,所以有:
WᵀW ≤ ||W||



而 ||W|| = √(WᵀW)。结合 (1) 和 (2),我们得到:
Mγ ≤ WᵀW ≤ ||W|| = √(WᵀW) ≤ √M*
于是我们得到了关于 M 的关键不等式:
Mγ ≤ √M

两边*方并整理:
M²γ² ≤ M => M ≤ 1/γ²
结论与意义
最终结论:感知机算法的权重更新次数 M 不会超过 1/γ²。其中 γ 是数据相对于某个(可能不是最优的)分隔超*面的最小间隔。
这意味着:
- 有限步收敛:只要数据是线性可分的(γ > 0),感知机算法必然在有限步内停止,并找到一个能正确分类所有训练样本的超*面。
- 收敛速度:收敛所需的步数上界与间隔 γ 的*方成反比。数据越容易分开(间隔越大),算法收敛得越快;数据点靠得越*(间隔越小),收敛可能需要更多步数。
本节课中我们一起学习了感知机收敛定理的完整证明。我们看到了如何通过分析权重向量与理想解的内积及其自身范数的变化,来严格地论证算法在有限步内必然收敛。这个简洁而优美的证明是机器学习理论中的一个经典结果。
机器学习:第7讲:从数据中估计概率:最大似然估计 📊





在本节课中,我们将学习如何从观测到的数据中估计概率分布。我们将从一个简单的抛硬币例子开始,引出最大似然估计的核心思想,并探讨其局限性。接着,我们将介绍最大后验估计,这是一种结合了先验知识的贝叶斯方法。最后,我们会比较这两种统计学思想流派的异同。




回顾感知机算法 🤖


上一节我们介绍了感知机算法。该算法假设数据是线性可分的,并通过迭代更新权重向量来寻找一个分离超*面。我们证明了在数据线性可分的条件下,感知机的更新次数存在一个上界,这意味着算法最终会收敛。

从数据到概率分布 🎲



今天,我们将回到机器学习的根源。我们的数据来源于某个未知的联合概率分布 P(x, y)。如果我们能知道这个分布,就可以使用贝叶斯最优分类器,即对于给定的特征向量 x,选择后验概率 P(y | x) 最大的那个类别 y。这理论上是最优的分类器。
然而,我们无法直接获得真实的分布。一个自然的想法是:我们可以从数据中*似估计这个分布。一旦我们有了分布的估计,预测就变得简单了。这本质上是许多机器学习算法的目标。
两种学习范式
在估计概率时,主要有两种思路:
- 判别式学习:直接建模条件概率 P(y | x)。我们试图从 x 预测 y。
- 生成式学习:建模联合概率 P(x, y)。这通常通过分解为 P(x | y) * P(y) 来实现。我们试图为每个类别 y 建模其特征 x 的分布。
本节课我们将重点放在生成式学习的思路上,即先估计分布,再进行预测。





为什么需要概率?🚗


在某些应用中,输出概率值而不仅仅是类别标签至关重要。例如:
- 自动驾驶汽车:需要综合视觉、雷达等多个传感器的概率输出,并结合不同错误决策(撞到松鼠 vs. 撞到行人)的代价,做出最优决策。
- 语音识别:需要结合声学模型(给定声音,某个音素出现的概率)和语言模型(给定上文,某个词出现的概率),通过概率进行整合。


最大似然估计:一个抛硬币的例子 🪙



让我们从一个最简单的分布估计问题开始:估计一枚硬币抛出正面的概率 θ。




假设我们进行了 N 次独立抛掷,观察到 N_H 次正面和 N_T 次反面。一个直观的估计是:
θ_hat = N_H / (N_H + N_T)





最大似然估计为这个直观估计提供了理论依据。其核心思想是:寻找那个能使观测到的数据出现概率最大的参数 θ。
用数学公式表达为:
θ_MLE = argmax_θ P(Data | θ)
其中,P(Data | θ) 称为似然函数。对于抛硬币这个二项分布问题,似然函数是:
P(Data | θ) = C(N_H+N_T, N_H) * θ^(N_H) * (1-θ)^(N_T)
为了求解方便,我们通常最大化其对数似然(log-likelihood):
log P(Data | θ) = log C(...) + N_H * log(θ) + N_T * log(1-θ)
通过对 θ 求导并令导数为零,我们可以得到最大值点:
d/dθ [log P(Data | θ)] = N_H/θ - N_T/(1-θ) = 0

解这个方程,最终得到:
θ_MLE = N_H / (N_H + N_T)
这验证了我们最初的直观估计。

MLE 的局限性与小数据问题 ⚠️
然而,最大似然估计有一个明显的缺陷:它对数据过于信任,当数据量很少时,估计可能非常极端且不合理。

例如,如果我们只抛了3次硬币并且都是反面,MLE会估计 θ = 0,即认为硬币永远不可能出现正面。这显然不是我们想要的。
*滑技术:一种实用的解决方案
为了解决小数据问题,一个常见技巧是进行*滑,例如“加一*滑”。其思想是:在开始实验之前,我们“幻想”自己已经看到过一些抛掷结果。
具体操作是,在计数时加上一个小的常数:
θ_smooth = (N_H + α) / (N_H + N_T + α + β)
当 α = β = 1 时,这就是“加一*滑”:
θ_smooth = (N_H + 1) / (N_H + N_T + 2)
这样,即使 N_H = 0,估计值也不会是 0,而是 1/(N_T+2),从而避免了极端估计。
贝叶斯视角:最大后验估计 🔮
*滑技术实际上可以从贝叶斯统计的角度优雅地推导出来,这引出了最大后验估计。
贝叶斯学派与频率学派(MLE属于频率学派)的一个根本区别在于:贝叶斯学派将模型参数 θ 本身视为一个随机变量,而频率学派认为 θ 是一个固定的未知常数。
既然 θ 是随机变量,我们就可以谈论它的先验分布 P(θ),这代表了我们在看到数据之前对 θ 的信念。例如,对于硬币,我们可能认为 θ 接* 0.5 的概率更大。

在观察到数据 D 后,我们根据贝叶斯规则更新对 θ 的认知,得到后验分布 P(θ | D):
P(θ | D) ∝ P(D | θ) * P(θ)
(其中 ∝ 表示“正比于”,忽略了归一化常数 P(D))
最大后验估计就是寻找使后验概率最大的 θ:
θ_MAP = argmax_θ P(θ | D) = argmax_θ [P(D | θ) * P(θ)]

例子:Beta 先验分布
对于抛硬币问题,一个常用的先验分布是 Beta 分布,其概率密度函数为:
P(θ; α, β) ∝ θ^(α-1) * (1-θ)^(β-1),其中 θ ∈ [0, 1]
参数 α 和 β 可以控制分布的形状。当我们把二项分布的似然 P(D|θ) ∝ θ^(N_H)*(1-θ)^(N_T) 与 Beta 先验相乘时,后验分布恰好是另一个 Beta 分布:
P(θ | D) ∝ θ^(N_H+α-1) * (1-θ)^(N_T+β-1)
最大化这个后验分布,得到的 MAP 估计为:
θ_MAP = (N_H + α - 1) / (N_H + N_T + α + β - 2)
当选择 α = β = 2 时(这对应一个以 0.5 为中心的合理先验),MAP 估计就变成了:
θ_MAP = (N_H + 1) / (N_H + N_T + 2)
这正是我们之前提到的“加一*滑”!因此,*滑操作可以理解为引入了一个合理的先验知识。
频率学派 vs. 贝叶斯学派 🤝

尽管历史上两派争论激烈,但从实践角度看,它们常常通过不同的路径达到相似的结果(如 MLE 加*滑 与 MAP)。
- 频率学派 (MLE):主张参数固定,通过优化似然函数 P(D|θ) 来估计。
- 贝叶斯学派 (MAP):主张参数随机,通过结合似然 P(D|θ) 和先验 P(θ),优化后验 P(θ|D) 来估计。
贝叶斯方法的核心优势在于它提供了一种系统性地将先验知识融入模型的框架。

纯贝叶斯推断:积分掉参数 🧠
真正的贝叶斯主义者并不满足于只找一个最可能的 θ (MAP)。更纯粹的做法是进行贝叶斯推断:在预测时,考虑所有可能的 θ,并将它们积分(或求和)掉。
例如,预测下一次抛掷为正面的概率为:
P(Heads | D) = ∫ P(Heads | θ) * P(θ | D) dθ
这个公式非常优美:我的预测不再依赖于任何一个单一的模型参数,而是对所有可能模型的预测进行了加权*均,权重正是该模型在给定数据下的后验概率。这体现了贝叶斯方法的完整性和一致性。
总结 📝
本节课我们一起学习了从数据中估计概率的基本方法:
- 最大似然估计:通过最大化似然函数 P(Data|θ) 来寻找最可能产生观测数据的参数。它简单直观,但在数据量少时可能过拟合。
- 最大后验估计:通过最大化后验概率 P(θ|Data) 来估计参数,它通过引入先验分布 P(θ) 将领域知识融入估计过程,能有效缓解小数据问题。
- *滑技术(如加一*滑)是应对 MLE 小数据问题的实用技巧,可以从 MAP 的角度(使用 Beta 先验)得到理论解释。
- 我们比较了频率学派和贝叶斯学派在参数认知上的根本差异,并指出了贝叶斯方法在理论上的灵活性。
理解这些概率估计的基本思想,是后续学习更复杂机器学习模型(如朴素贝叶斯分类器、高斯混合模型等)的重要基础。
机器学习:008:从数据中估计概率:朴素贝叶斯 🎯


在本节课中,我们将要学习如何从观测数据中估计概率分布,并介绍朴素贝叶斯分类器。我们将从回顾最大似然估计和最大后验估计开始,然后探讨如何将这些方法应用于更复杂的、包含特征和标签的联合分布。最后,我们将引入朴素贝叶斯假设,它通过一个关键的简化,使得在高维数据上进行概率估计变得可行。
回顾:参数估计方法 📊
上一节我们介绍了从数据中估计概率分布的基本思想。我们有一个从某个未知分布 P(X, y) 中独立同分布抽取得到的数据集 D,包含 n 个数据点。我们的目标是找到一个带参数 θ 的已知分布 P_θ,使其尽可能接*这个未知的真实分布。
我们讨论了两种主要的参数估计方法:
以下是两种核心的估计方法:



-
最大似然估计:我们寻找参数 θ,使得观测到当前数据的概率最大。其目标是:
θ_MLE = argmax_θ P_θ(D)
这是一种频率学派的观点,将参数视为固定的未知量。 -
最大后验估计:这是一种贝叶斯学派的观点,将参数 θ 本身视为随机变量。我们寻找在给定观测数据 D 的条件下,最可能的参数值。其目标是:
θ_MAP = argmax_θ P(θ | D) = argmax_θ P(D | θ) P(θ)
其中 P(θ) 是我们对参数先验知识的编码,称为先验分布。
这两种方法在数据量充足时通常会收敛到相似的结果,但在数据稀缺时,MAP估计会受到先验分布的显著影响。
从简单案例到复杂问题 🔄
我们从一个最简单的案例开始:估计一个硬币抛出正面的概率 P(X=正面)。通过MLE,我们得到估计值为数据中正面朝上的次数除以总抛掷次数。
现在,我们考虑一个更有趣且更贴*机器学习实际的问题:估计联合分布 P(X, y) 的条件概率 P(y | X),其中 X 是特征,y 是标签。
根据MLE的思想和条件概率的定义,我们可以推导出 P(y | X) 的估计方法:
以下是估计步骤:
- 在数据集中,找出所有满足 X_i = x 的数据点(即特征与给定值相同的点)。
- 在这个子集中,计算标签 y 等于特定值 y 的数据点数量。
- P(y | X=x) 的MLE估计值就是这个数量除以第一步中找到的数据点总数。
用公式表示即为:
P_MLE(y | X=x) = (Σ_i I[X_i = x 且 y_i = y]) / (Σ_i I[X_i = x])
其中 I[·] 是指示函数,条件成立时值为1,否则为0。
然而,这种方法存在一个严重问题:当特征维度很高或特征取值空间很大时,我们几乎不可能在训练集中找到与测试点 X 完全一致 的样本。这会导致我们用于估计的数据子集为空或非常小,从而无法做出可靠的预测。






朴素贝叶斯假设:关键的简化 🛠️
为了解决上述“维度灾难”问题,朴素贝叶斯方法采用了一个关键的策略:利用贝叶斯定理转换问题,并做出一个强有力的简化假设。

首先,根据贝叶斯定理,分类时我们关心的是:
P(y | X) ∝ P(X | y) * P(y)
其中 P(y) 是类先验概率,容易估计。难题在于估计似然 P(X | y),即在给定标签的条件下,观察到整个特征向量 X 的概率。


朴素贝叶斯做出了一个“朴素”的假设:在给定类别标签 y 的条件下,所有特征 X_1, X_2, ..., X_d 都是相互独立的。这意味着:
P(X | y) = Π_{α=1}^{d} P(X_α | y)



这个假设虽然在实际中很少严格成立(例如,一篇文章中的单词并非完全独立),但它带来了巨大的计算便利性。现在,我们只需要为每个特征 X_α 估计一维的条件分布 P(X_α | y),这变得非常容易。尽管假设很强,但朴素贝叶斯在许多实际任务(如文本分类、垃圾邮件过滤)中表现出了惊人的效果。






朴素贝叶斯分类器 🧠

结合贝叶斯定理和朴素独立性假设,我们得到了朴素贝叶斯分类器的决策规则。对于一个输入特征向量 X,我们预测其标签 ŷ 为:
ŷ = argmax_y P(y) * Π_{α=1}^{d} P(X_α | y)
在实际计算中,我们通常对等式右边取对数,将连乘转化为连加,以避免数值下溢并简化计算:
ŷ = argmax_y [ log P(y) + Σ_{α=1}^{d} log P(X_α | y) ]
至此,构建一个朴素贝叶斯分类器就简化为以下步骤:
以下是模型训练步骤:
- 从训练数据中估计每个类别的先验概率 P(y)。
- 对于每个特征维度 α 和每个类别 y,估计条件概率 P(X_α | y)。对于离散特征,这通常是通过计算该特征值在属于类别 y 的样本中出现的频率来实现的。

总结 📝
本节课我们一起学习了从数据中估计概率的核心思想。我们从参数估计的两种基本方法(MLE和MAP)出发,揭示了直接估计高维条件概率 P(y|X) 的困难。朴素贝叶斯分类器通过结合贝叶斯定理和特征条件独立性假设,巧妙地规避了“维度灾难”问题,将复杂的联合概率估计分解为一系列简单的一维概率估计任务。尽管其“朴素”的假设在现实中往往不成立,但这种在计算可行性与模型准确性之间的折衷,使其成为机器学习中一个强大且广泛应用的基线模型。
机器学习:009:朴素贝叶斯(续)🔍
在本节课中,我们将继续学习朴素贝叶斯分类器。我们将通过一个具体的例子来巩固对朴素贝叶斯公式和拉普拉斯*滑的理解,并探讨该算法的核心假设在何种情况下会失效。最后,我们将介绍朴素贝叶斯在处理不同类型数据(如分类数据和文本数据)时的具体应用形式。
课程公告与项目分享 📢
在深入课程内容之前,有几个公告。
项目1现已结束。观察排行榜上团队排名的变化非常有趣。以下是排名靠前团队分享的秘诀:
以下是排名前列团队采用的方法:
- 特征加权:团队“Steve Nash and Carl Sagan”为每个特征计算了不同的权重,并在计算距离时应用这些权重。他们尝试了不同的加权函数,例如高斯加权。这实质上是度量学习的第一步,即通过学习一个优化的距离度量来提升K*邻分类器的性能。
- 数据增强:团队“Ha Ha Ha Witty Kitty”采用了另一种完全不同的方法。他们通过轻微修改训练样本(例如,将数字图像稍微*移或旋转)来人工增加训练数据量,同时确保标签不变。这种方法被称为数据增强,在实践中被广泛使用以提升模型鲁棒性。



这些方法可以结合使用,并且都是对分类器合理且有效的改进。





此外,下周将有三场关于机器学习的精彩讲座,涉及机器人学、医疗保健和核心机器学习等领域,详细信息将发布在Piazza上。








朴素贝叶斯实例演练 🧮




现在,我们通过一个具体例子来演练朴素贝叶斯分类器的计算过程。假设苏西(Susie)根据历史约会数据训练一个朴素贝叶斯模型,来判断约会对象是“好人”还是“坏人”。数据特征包括是否穿披风(C)、是否戴面具(M)以及是否把内裤外穿(U)。


首先,我们根据提供的训练数据表进行计算。

1. 先验概率 P(Y)
在不考虑任何特征的情况下,一个人是“好人”的先验概率是多少?根据数据表,Y的分布是均匀的。因此:
P(Y=好人) = 1/2
2. 条件概率估计(不使用*滑)
接下来,我们估计条件概率表(CPT)。例如:
P(C=无披风 | Y=好人):在好人群中,不穿披风的比例。从表中可知,3个好人中有1个不穿披风。
P(C=无披风 | Y=好人) = 1/3P(M=无面具 | Y=好人):同理,3个好人中有1个不戴面具。
P(M=无面具 | Y=好人) = 1/3
3. 使用拉普拉斯*滑(+1*滑)估计条件概率
拉普拉斯*滑通过在每个类别的计数上加1来避免零概率问题。对于二值特征,相当于添加了两次“抛硬币”实验(一次成功,一次失败)。
P(C=无披风 | Y=好人) = (1 + 1) / (3 + 2) = 2/5
这里,分子加1是因为观察到1次“无披风”,分母加2是因为为“披风”和“无披风”两个类别各加了1次虚拟计数。

4. 进行预测推断
现在,苏西遇到一个约会对象,他没有穿披风(C=无),也没有戴面具(M=无)。我们需要计算在此条件下,他是好人的后验概率 P(Y=好人 | C=无, M=无)。
根据贝叶斯定理:
P(Y | C, M) = P(C, M | Y) * P(Y) / P(C, M)
由于特征C和M在给定Y的条件下被假设为独立的(朴素贝叶斯核心假设),我们可以分解:
P(C, M | Y) = P(C | Y) * P(M | Y)
分母 P(C, M) 可以通过全概率公式计算:
P(C, M) = P(C, M | Y=好人)P(Y=好人) + P(C, M | Y=坏人)P(Y=坏人)






将具体数值(使用未*滑的1/3估计值)和先验概率1/2代入公式:
P(Y=好人 | C=无, M=无) = ( (1/3)*(1/3)*(1/2) ) / ( (1/3)*(1/3)*(1/2) + (2/3)*(2/3)*(1/2) ) = (1/18) / (1/18 + 4/18) = 1/5




因此,苏西的朴素贝叶斯分类器预测此人是好人的概率为 1/5。


关于数据代表性的讨论
一个关键点是,机器学习模型假设训练数据和测试数据来自同一分布。如果苏西的训练数据全是超级英雄,而她实际约会的是普通人,那么模型可能不适用。这是机器学习普遍存在的问题,而非朴素贝叶斯特有的缺陷。





深入理解朴素贝叶斯假设 🤔



上一节课末尾,有几个关于朴素贝叶斯核心假设的重要问题。



1. 如果条件独立假设成立,朴素贝叶斯是最优分类器吗?
是的。朴素贝叶斯所做的唯一“*似”就是条件独立假设。如果数据确实满足该假设,那么朴素贝叶斯等价于贝叶斯最优分类器,能够做出理论上最准确的预测。





2. 条件独立假设何时会失效?能否举例说明?
该假设经常不成立。分解联合概率 P(X|Y) 为 ∏ P(X_α|Y) 可能导致对真实概率的高估或低估。





以下是几个例子:
- 高估的例子(特征互斥):在垃圾邮件分类中,“伟哥”和“尼日利亚”这两个词单独出现在垃圾邮件中的概率都很高。但同一封垃圾邮件同时包含这两个词的概率极低(因为它们是不同类型的垃圾邮件)。朴素贝叶斯会将其概率计算为
P(伟哥|垃圾邮件) * P(尼日利亚|垃圾邮件),从而高估了同时出现的概率。 - 低估的例子(特征强相关):在扑克牌中,判断一手牌是否为“满堂红”。定义两个特征:“是否有三张K”和“是否有两张Q”。如果两个特征同时为真,则一定是满堂红,概率为1。但朴素贝叶斯会将其计算为两个独立概率的乘积,可能低估了这个概率。



这些例子表明,在实际应用中,需要警惕特征间存在强依赖关系的情况。

朴素贝叶斯的不同变体 📊
朴素贝叶斯的框架可以灵活地适配不同类型的数据分布 P(X|Y)。下面介绍两种常见变体。
1. 类别分布(Categorical Features)
当每个特征 X_α 是分类变量,可取K个离散值(如性别:男/女;婚姻状况:已婚/未婚/离异等)时,我们使用类别分布。
- 模型:对于每个特征维度α和每个类别c,我们估计一个参数
θ_{α, j, c},它表示在类别c下,特征α取第j个值的概率。这就像一个具有K个面的骰子。
P(X_α = j | Y = c) = θ_{α, j, c}
并且对于固定的α和c,所有j的概率之和为1:∑_j θ_{α, j, c} = 1 - 参数估计:使用最大似然估计(MLE)或最大后验估计(MAP),与之前估计硬币参数的方法相同。例如,MLE估计为:
θ_{α, j, c} = (数据中特征α取值为j且类别为c的样本数) / (数据中类别为c的样本数)
可以加入拉普拉斯*滑以避免零概率。
2. 多项分布(Text Data - 文本数据)
这是文本分类(如垃圾邮件过滤)中最常用的变体。我们将一封有M个词的邮件,看作从某个“词袋”分布中重复抽样M次(每次独立)的结果。

- 模型:特征向量
X的维度等于词汇表大小V。X_α表示词汇表中第α个词在邮件中出现的次数。所有特征值之和等于邮件总词数M。 - 概率计算:给定邮件类别c,生成这封邮件的概率为:
P(X | Y=c) = [ M! / (∏_α X_α!) ] * ∏_α (θ_{α, c})^{X_α}- 第一部分是多项式系数,计算在忽略单词顺序的情况下,能组成当前词频分布的排列数。
- 第二部分是每个词按其出现次数出现的概率连乘,其中
θ_{α, c}是类别c下生成第α个词的概率。
- 核心:不同类别(如垃圾邮件/非垃圾邮件)对应不同的词分布
θ_c。训练过程就是从数据中估计这些分布。

在实践中,由于特征向量极度稀疏(大部分词出现次数为0),会采用高效的数据结构存储非零特征。
总结 📝
本节课我们深入探讨了朴素贝叶斯分类器。
- 我们通过一个完整的例子,演练了从计算先验概率、条件概率,到应用贝叶斯定理和朴素假设进行预测的全过程,并复习了拉普拉斯*滑的重要性。
- 我们深入分析了朴素贝叶斯的条件独立假设,理解了当该假设成立时,模型是最优的;同时通过实例(如垃圾邮件过滤)看到了该假设失效时可能导致概率高估或低估的情况。
- 最后,我们介绍了朴素贝叶斯如何适配不同类型的数据,重点讲解了处理分类特征的类别分布变体和处理文本数据的多项分布变体,后者是当前许多垃圾邮件过滤系统的基础。
朴素贝叶斯因其简单、高效且易于实现的特点,在实践中仍有广泛的应用,尤其是在文本分类领域。理解其假设和局限性是正确使用该模型的关键。
机器学习:010:朴素贝叶斯(续)🔍













在本节课中,我们将继续学习朴素贝叶斯分类器。我们将深入探讨如何处理多项式分布和连续特征,并分析朴素贝叶斯分类器的决策边界特性。最后,我们会通过一个实际项目示例来巩固理解。




上一节我们介绍了朴素贝叶斯的基本思想,它是一种生成式算法。本节中,我们来看看如何具体处理不同类型的特征数据。





特征建模方法 📊



朴素贝叶斯的核心是估计条件概率 P(x|y)。根据特征类型的不同,我们采用不同的分布模型进行估计。


多项式分布 📝






在处理文本分类等计数型特征时,我们通常使用多项式分布模型。其数据生成过程可以想象为:从一个词袋中,根据概率分布 θ 重复抽取词语,直到生成一封完整的邮件。
概率公式如下:
P(x | y=c) = ( M! / (∏ x_α!) ) * ∏ (θ_{α, c})^{x_α}
其中:
- M 是文档总词数。
- x_α 是特征 α(例如某个词)出现的次数。
- θ_{α, c} 是在类别 c 下抽取到词 α 的概率。
参数估计采用最大似然估计,计算公式为:
θ_{α, c} (估计值) = (∑_{i: y_i=c} x_iα) / (∑_{i: y_i=c} ∑_{β} x_iβ)

简单来说,就是统计在类别 c 的所有文档中,词 α 出现的总次数,然后除以该类别的所有词语出现的总次数。


*滑处理:为了避免未登录词(训练集中未出现的词)导致概率为零,我们通常采用加一*滑(拉普拉斯*滑)。

连续特征与高斯分布 📈


当特征是连续值时,一个常见且简单的假设是每个特征在给定类别下服从高斯(正态)分布。

概率公式如下:


P(x_α | y=c) = N(x_α; μ_{α,c}, σ_{α,c}^2)

参数估计同样直接:
- 均值 μ_{α, c} 的估计是类别 c 下所有样本第 α 个特征值的*均值。
- 方差 σ_{α, c}^2 的估计是类别 c 下所有样本第 α 个特征值与其均值之差的*方的*均。



在学习了如何为不同特征建模后,我们来看看这些模型如何共同作用,形成一个分类器。


决策边界与分类器特性 ⚖️


朴素贝叶斯分类器通过比较新样本 x 更可能来自哪个类别的分布来进行预测。决策边界就是这两个类别后验概率相等的地方。



一个重要的结论是:当特征条件概率服从高斯分布且方差相同时,朴素贝叶斯分类器会产生一个线性决策边界。

以下是一个直观的例子,展示了高斯朴素贝叶斯在二维数据上产生的线性决策边界:
# 假设有两个类别,每个特征独立且服从高斯分布
# 决策函数基于对数概率比
决策规则: 如果 log(P(y=1|x)) - log(P(y=0|x)) > 0,则预测为类别1,否则为类别0。
# 在高斯假设下,此表达式可简化为一个关于 x 的线性函数。

然而,朴素贝叶斯并不保证总能完美分类线性可分的数据。如果数据的真实分布严重违背了特征独立或分布假设(例如存在离群点,或真实分布不是单峰高斯),那么朴素贝叶斯可能会在训练集上就产生错误分类,而感知机算法则可能找到完美的分离超*面。这体现了模型假设对最终性能的关键影响。



最后,让我们通过一个实际应用来整合本节课的知识。
实战示例:婴儿姓名分类 👶

本节课提到的项目任务是构建一个朴素贝叶斯分类器,根据名字判断其更可能属于男孩还是女孩。
基本步骤如下:
- 特征提取:从名字字符串中提取特征,例如:
- 名字的长度。
- 最后一个字母。
- 是否包含特定字母或音节。
- 等等。
- 模型训练:根据提取的特征类型(如类别型末字母、数值型长度),选择合适的分布(如伯努利分布、高斯分布)进行参数估计。
- 预测:对新输入的名字提取相同特征,使用训练好的朴素贝叶斯模型计算其属于“男孩”和“女孩”类别的概率,并选择概率更高的类别作为预测结果。
这种方法简单高效,是文本分类和许多简单判别任务的强大基线模型。



总结:本节课我们一起深入学习了朴素贝叶斯分类器。我们掌握了如何处理多项式分布和连续特征,理解了其决策边界在常见设定下是线性的,同时也认识到模型假设对性能的限制。最后,我们通过一个姓名分类项目了解了朴素贝叶斯的实际应用流程。
机器学习:011:逻辑回归

在本节课中,我们将从朴素贝叶斯分类器过渡到逻辑回归,并介绍经验风险最小化的概念。我们将看到,逻辑回归可以被视为朴素贝叶斯的判别式对应方法,它直接对条件概率 P(y|x) 进行建模,而不是像朴素贝叶斯那样先建模 P(x|y)。
从朴素贝叶斯到线性分类器
上一节我们介绍了朴素贝叶斯分类器。其核心思想是利用贝叶斯定理,通过 P(x|y) 和 P(y) 来估计 P(y|x)。对于二分类问题(标签为 +1 和 -1),最优分类器会预测概率更大的那个类别。
具体来说,当满足以下条件时,分类器预测为 +1:
P(y=+1|x) > P(y=-1|x)

根据贝叶斯定理,这等价于:
P(x|y=+1) * P(y=+1) > P(x|y=-1) * P(y=-1)
在多项式朴素贝叶斯模型中,我们假设特征服从多项式分布。将分布公式代入上述不等式,并移除两边相同的常数项(如阶乘项),我们得到:
P(y=+1) * ∏ (θ_α^(+1))^(x_α) > P(y=-1) * ∏ (θ_α^(-1))^(x_α)
其中,θ_α^(y) 表示在类别 y 下第 α 个特征的概率,x_α 是该特征的值。
推导决策边界
为了简化计算,我们对不等式两边取对数(因为对数函数是单调递增的)。这是处理概率乘积的常用技巧。
取对数后,不等式变为:
log P(y=+1) + Σ [x_α * log(θ_α^(+1))] > log P(y=-1) + Σ [x_α * log(θ_α^(-1))]
接下来,我们将所有项移到不等式的一侧:
[log P(y=+1) - log P(y=-1)] + Σ [x_α * (log(θ_α^(+1)) - log(θ_α^(-1)))] > 0
现在,我们可以定义两个关键部分:
- 令常数项
b = log P(y=+1) - log P(y=-1) - 令权重向量
w_α = log(θ_α^(+1)) - log(θ_α^(-1))
于是,决策规则简化为:
Σ [w_α * x_α] + b > 0
或者写成向量形式:
w^T x + b > 0
结论:在多项式朴素贝叶斯假设下,最终的分类器是一个线性分类器,其权重 w 和偏置 b 由估计的类别先验 P(y) 和特征概率 θ 决定。这与感知机的形式相同,但参数是通过概率模型估计得到的,而非迭代更新。
生成式与判别式模型的对比
朴素贝叶斯是一种生成式模型,它通过建模 P(x|y) 来间接得到 P(y|x)。它的工作流程如下:

- 为每个类别拟合一个概率分布(如高斯分布、多项式分布)。
- 用拟合出的分布来代表原始数据。
- 找到能最佳分离这两个分布的超*面。
这种方法有其优缺点:
- 优点:训练速度快(无需迭代),天然能输出概率,易于处理小样本数据。
- 缺点:如果对数据分布的假设(如“朴素”独立性假设或选定的分布族)不正确,那么学到的决策边界可能不是最优的,因为它分离的是模型而非原始数据。例如,对于非线性可分的数据,感知机会永远无法收敛,而朴素贝叶斯总会给出一个答案,但这个答案可能牺牲了某些离群点。
感知机是一种判别式模型,它直接试图找到一个分离数据的超*面。但如果数据本身不是线性可分的,感知机算法将无法收敛。
逻辑回归的引入
那么,是否存在一种结合两者优点的判别式方法呢?答案是逻辑回归。
我们观察到,在高斯朴素贝叶斯模型中,最终推导出的条件概率具有一个特定的形式:
P(y=+1|x) = 1 / (1 + exp(-(w^T x + b)))
其中 w 和 b 是由高斯分布参数计算得到的。
逻辑回归的核心思想是:我们直接假设 P(y|x) 就服从上述形式,然后跳过对 P(x|y) 的建模,直接利用数据来估计最优的参数 w 和 b。
这个函数被称为 Sigmoid 函数 或 Logistic 函数。它的输出范围在 0 到 1 之间,非常适合表示概率。
- 当
w^T x + b为正无穷大时,函数值趋*于 1。 - 当
w^T x + b为负无穷大时,函数值趋*于 0。 - 当
w^T x + b = 0时,函数值等于 0.5。
通过最大似然估计拟合参数
我们的目标是找到参数 w 和 b,使得观测到的数据标签的似然性最大。对于包含 N 个独立样本的数据集,我们希望最大化:
∏ P(y_i | x_i; w, b)
代入我们的逻辑函数模型,并取对数得到对数似然函数:
∑ log P(y_i | x_i; w, b) = ∑ log [1 / (1 + exp(-y_i * (w^T x_i + b)))]
这里利用了 y ∈ {+1, -1} 的性质来简化表达式。
简化后,我们需要最大化:
∑ -log(1 + exp(-y_i * (w^T x_i + b)))
等价于最小化:
∑ log(1 + exp(-y_i * (w^T x_i + b)))
与朴素贝叶斯中能得出闭合解不同,这个最小化问题没有解析解。然而,这个目标函数是凸函数,这意味着我们可以使用梯度下降等优化算法,从一个初始的 w 和 b 开始,沿着函数下降的方向迭代,最终找到全局最优解。
从最大似然估计到最大后验估计
我们也可以使用最大后验估计(MAP)来引入先验知识。MAP 估计最大化的是 P(w, b | 数据),根据贝叶斯定理,这正比于 P(数据 | w, b) * P(w, b)。
P(数据 | w, b)就是我们的(对数)似然函数。P(w, b)是参数的先验分布。一个常见的选择是假设w服从均值为 0 的正态分布,这体现了我们偏好“简单”模型(权重值较小)的倾向。
加入这个先验项后,我们的优化目标变为最小化:
∑ log(1 + exp(-y_i * (w^T x_i + b))) + λ * w^T w
其中 λ 是控制正则化强度的超参数。这项 λ * w^T w 被称为 L2 正则化项,它惩罚大的权重值,有助于防止过拟合。虽然 MAP 估计引入了正则化,但优化问题本身仍然需要通过数值方法(如梯度下降)求解。
总结

本节课我们一起学习了逻辑回归的核心内容。
- 我们首先回顾了朴素贝叶斯分类器,并展示了在特定分布假设下,它可以推导出一个线性决策边界。
- 接着,我们对比了生成式模型(如朴素贝叶斯)和判别式模型(如感知机)的差异与优劣。
- 然后,我们引入了逻辑回归。它作为一种判别式模型,直接对条件概率
P(y|x)进行建模,其形式来源于朴素贝叶斯的推导结果,即 Sigmoid 函数。 - 我们介绍了如何通过最大似然估计来拟合逻辑回归的参数,并指出这是一个没有闭合解但可以通过凸优化求解的问题。
- 最后,我们简要提到了可以通过最大后验估计加入正则化项,以获得更稳健的模型。

逻辑回归巧妙地连接了概率解释和线性分类,是机器学习中一个非常重要且基础的工具。在下一讲中,我们将深入探讨如何优化逻辑回归的目标函数。
机器学习:012:梯度下降与牛顿法



在本节课中,我们将学习如何优化逻辑回归的损失函数。我们将介绍两种核心的优化算法:梯度下降法和牛顿法,并讨论它们各自的优缺点以及在实际应用中的选择策略。

上一节我们介绍了逻辑回归,并推导出其最大似然估计的损失函数。本节中,我们将探讨如何找到这个损失函数的最小值点。

损失函数与优化问题
逻辑回归的损失函数可以表示为:


L(w) = Σ log(1 + exp(-wᵀxᵢ yᵢ))




我们的目标是找到参数向量 w,使得 L(w) 最小化。这个函数是连续、可微且凸的,这意味着它只有一个全局最小值点,并且其形状像一个“碗”。



梯度下降法

梯度下降法是最基础的优化算法。其核心思想是:从一个初始猜测 w₀ 开始,沿着函数值下降最快的方向(即负梯度方向)移动一小步,并重复此过程。

算法原理

给定当前点 w,我们计算损失函数的梯度 g(w) = ∇L(w)。更新规则为:






w ← w - α * g(w)


其中,α 是一个称为学习率的正数,它控制着每一步的步长。
为什么梯度下降有效?
利用泰勒展开的一阶*似,我们可以证明,只要学习率 α 足够小,每次更新都会使损失函数值减小。因为凸函数的性质,这个过程最终会收敛到全局最小值点。
选择学习率 α




学习率的选择至关重要:
- α 太小:收敛速度极慢。
- α 太大:可能越过最小值点,导致震荡甚至发散。




以下是几种常见策略:
- 固定衰减:设置 α = 常数 / t,其中 t 是迭代次数。这能保证最终收敛,但速度可能较慢。
- 自适应学习率 (如 AdaGrad):为每个参数维度设置独立的学习率。对于历史上梯度较大的参数,给予较小的学习率;对于梯度较小的参数,给予较大的学习率。其更新规则为:
- 初始化累加向量 s = 0。
- 每次迭代计算梯度 g。
- s ← s + g ⊙ g (按元素*方并累加)。
- w ← w - (α / (√s + ε)) ⊙ g (按元素进行缩放)。
这种方法在实践中非常有效,能自动调整步长。

停止条件
由于梯度在最小值点趋*于零,更新步长会越来越小。通常,当参数的变化量 ||w_{t+1} - w_t|| 小于一个预设的阈值 δ 时,即可停止迭代。在机器学习中,我们通常不追求极高的数值精度,只要模型预测性能稳定即可。
上一节我们介绍了利用一阶导数信息的梯度下降法。本节中我们来看看利用二阶导数信息、收敛速度更快的牛顿法。
牛顿法
牛顿法利用了损失函数的二阶泰勒展开(抛物线*似),试图直接跳到当前*似的极小值点。
算法原理
在点 w 处,损失函数的二阶泰勒*似为:
L(w + s) ≈ L(w) + g(w)ᵀ s + (1/2) sᵀ H(w) s
其中,H(w) 是海森矩阵(Hessian Matrix),其元素 Hᵢⱼ 是损失函数对参数 wᵢ 和 wⱼ 的二阶偏导。
为了最小化这个关于 s 的二次函数,我们令其梯度为零:
g(w) + H(w) s = 0

求解得到更新步长:
s = -H(w)⁻¹ g(w)
因此,牛顿法的更新规则为:
w ← w - H(w)⁻¹ g(w)
牛顿法的优缺点
- 优点:收敛速度极快(二次收敛)。在最小值点附*,通常只需几步迭代就能达到很高的精度。
- 缺点:
- 需要计算并存储海森矩阵 H(w) 及其逆矩阵,计算和存储成本很高,尤其在高维问题中。
- 仅当初始点足够靠*最小值点时,二阶*似才准确。如果初始点不好,牛顿步长可能过大,导致算法发散。
实践建议与总结
本节课中我们一起学习了两种核心的优化算法。
- 梯度下降法:通用、稳定,是大多数机器学习优化的首选起点。推荐使用自适应学习率变体(如 AdaGrad)来简化调参。
- 牛顿法:在接*最优解时收敛极快,但对初始位置敏感,且计算开销大。
一个常用的混合策略是:
- 前期:使用梯度下降法(或自适应梯度法)进行大量迭代,快速靠*最小值区域。
- 后期:当参数变化很小时,切换为牛顿法进行少数几次迭代,以快速达到高精度解。
通过结合两种方法的优点,我们可以在实践中高效、稳定地训练逻辑回归等机器学习模型。
机器学习:013:线性回归与岭回归 📈

















在本节课中,我们将学习线性回归,这是一种用于预测连续值(如房价)的经典机器学习算法。我们将从逻辑回归的回顾开始,然后深入探讨线性回归的模型假设、损失函数推导以及两种参数估计方法:最大似然估计和最大后验估计。












上一节我们介绍了逻辑回归及其损失函数的优化方法。本节中,我们来看看另一种基础且重要的算法——线性回归。




从逻辑回归到线性回归





逻辑回归本质上是对条件概率 P(y|x) 建模,其形式为:




P(y|x) = 1 / (1 + exp(-w^T x * y))









我们通过最小化一个凸的、可微的损失函数来找到最佳参数 w。这个损失函数是对“0-1损失”(即计算错误分类的样本数)的一种可微*似。当分类正确时,损失趋*于0;当分类错误时,损失会线性增长,错误越严重(即样本点离决策边界越远且在错误一侧),损失越大。






然而,逻辑回归是一个分类算法。当我们的标签 y 是连续值时(例如预测房价),我们需要使用回归算法。今天,我们将讨论最基础的回归算法:线性回归,也称为普通最小二乘法。





线性回归的模型假设




建立线性回归模型需要做出两个关键假设。





1. 线性关系假设
我们假设特征 x 与连续标签 y 之间存在线性关系。即,存在一个权重向量 w,使得 y 大致等于 w^T x。在二维空间中,这表现为一条试图穿过所有数据点的直线。







2. 噪声模型假设
数据点通常不会精确地落在直线上。因此,我们假设观测值 y 是线性预测值加上一个随机噪声:




y_i = w^T x_i + ε_i






其中,噪声项 ε_i 服从均值为0、方差为 σ^2 的高斯(正态)分布。这意味着,对于给定的 x_i,其对应的 y_i 服从一个以 w^T x_i 为均值的高斯分布:





y_i | x_i, w ~ N(w^T x_i, σ^2)








选择高斯噪声的原因是其数学处理简便,并且根据中心极限定理,许多独立随机效应的总和往往*似服从高斯分布。



参数估计:最大似然估计




在给定数据和上述假设后,如何找到最优的 w?一种经典方法是最大似然估计:寻找能使观测到的数据出现概率最大的参数 w。




以下是推导MLE损失函数的步骤:





- 写出数据的似然函数:假设数据点独立同分布,整个数据集的概率是每个数据点概率的乘积。
- 取对数简化计算:乘积取对数变为求和,便于求导优化。
- 代入高斯分布公式:将
P(y_i | x_i, w)的具体形式代入。 - 忽略常数项:在优化过程中,与
w无关的常数项(如1/√(2πσ^2))不影响最优解的位置,可以忽略。 - 转换为最小化问题:将对数似然的最大化问题,等价转换为最小化其负值的问题。
- 得到均方误差损失:经过化简,我们得到最终要最小化的目标函数,即均方误差:


L(w) = (1/n) * Σ_{i=1}^{n} (w^T x_i - y_i)^2



这个损失函数非常友好,它是一个关于 w 的二次函数(抛物线),是凸的、可微的,并且存在解析解(可以通过求导直接得到最优解)。(1/n) 使得损失值具有了“*均每个样本的误差*方”的可解释性。




参数估计:最大后验估计

MLE 可能会遇到过拟合问题,特别是当数据量较少或特征维度很高时。最大后验估计 通过引入参数的先验分布来缓解这个问题。
MAP 的目标是找到在给定数据下最可能的参数值:argmax_w P(w | D)。根据贝叶斯定理:
P(w | D) ∝ P(D | w) * P(w)
其中 P(D | w) 就是 MLE 中的似然函数,而 P(w) 是先验分布,代表我们在看到数据之前对参数 w 的信念。一个常见的选择是均值为0的高斯先验:w ~ N(0, τ^2 I)。这表达了我们认为参数值不太可能偏离0太远的倾向。
以下是推导MAP损失函数的步骤:
- 应用贝叶斯定理。
- 代入似然和先验:似然部分与MLE相同,先验部分为高斯分布。
- 取对数并化简。
- 得到正则化损失函数:经过与MLE类似的推导,我们得到一个新的目标函数:
L_ridge(w) = (1/n) * Σ_{i=1}^{n} (w^T x_i - y_i)^2 + λ * ||w||^2
其中 λ = σ^2 / (n * τ^2) 是一个超参数,控制正则化的强度。这个额外的项 ||w||^2(权重的L2范数*方)被称为L2正则化项或权重衰减。它惩罚过大的权重值,鼓励模型找到更简单、权重更小的解,从而降低过拟合风险。这个带有L2正则化的线性回归模型,也称为岭回归。
本节课中我们一起学习了线性回归的核心思想。我们从分类问题过渡到回归问题,建立了线性模型与高斯噪声的假设。通过最大似然估计,我们推导出了均方误差损失函数。为了控制模型复杂度、防止过拟合,我们引入了贝叶斯视角的最大后验估计,并得到了带有L2正则化的岭回归损失函数。下一节课,我们将通过实际演示来观察这些方法的效果。
机器学习:014:线性支持向量机



在本节课中,我们将要学习一种非常强大且流行的机器学习算法——支持向量机。我们将从回顾线性回归的闭式解开始,然后深入探讨支持向量机的核心思想:寻找具有最大间隔的分类超*面。
回顾:线性回归的闭式解
上一节我们介绍了线性回归和*方损失。*方损失函数最终可以表示为:
公式: L(w) = Σ_i (w^T x_i - y_i)^2

在矩阵形式下,这可以写作 L(w) = (Xw - y)^T (Xw - y)。这是一个关于 w 的抛物线(二次函数),因此存在闭式解。通过求导并令导数为零,我们可以得到最优解:
公式: w = (X^T X)^(-1) X^T y
然而,这个闭式解需要计算矩阵 X^T X 的逆,其空间复杂度为 O(d^2),计算复杂度为 O(d^3)。当特征维度 d 非常大时(例如在文本处理中可能有数百万维),这种计算会变得非常昂贵甚至不可行。因此,在实践中,我们更常使用梯度下降等迭代优化方法。
从分类到最大间隔
现在,让我们回到分类问题。在分类中,我们的标签 y_i 是 +1 或 -1。我们假设数据是线性可分的,即存在一个超*面能将正负样本分开。
感知机算法可以找到一个这样的超*面,但它无法保证找到的是哪一个,因为存在无数个可能的分离超*面。那么,哪一个才是最好的呢?
支持向量机的核心直觉是:最好的超*面是那个具有最大“间隔”的超*面。间隔定义为超*面到最*数据点的距离。一个具有较大间隔的超*面,对于训练数据中的小扰动或未见过的测试数据具有更好的鲁棒性。
定义间隔
首先,我们需要形式化地定义“点到超*面的距离”。
我们的超*面由方程 w^T x + b = 0 定义。给定一个数据点 x,我们想计算它到这个超*面的距离。我们可以将点 x 投影到超*面上得到点 x_p,那么距离就是向量 d = x - x_p 的长度。

通过几何推导(利用 d *行于 w 且 x_p 在超*面上这两个条件),我们可以得到点 x 到超*面的距离公式:

公式: distance = |w^T x + b| / ||w||
其中 ||w|| 是向量 w 的范数。
那么,一个分类器(由 w 和 b 定义)的间隔 γ,就是所有数据点中距离超*面的最小距离:
公式: γ = min_i ( |w^T x_i + b| / ||w|| )
支持向量机的优化问题
支持向量机的目标是找到能使间隔 γ 最大化的参数 w 和 b。也就是说,我们希望:
目标: max_{w,b} γ = max_{w,b} [ min_i ( |w^T x_i + b| / ||w|| ) ]

但这带来了一个问题:如果我们不施加任何约束,简单地最大化距离,我们可以通过让 w 和 b 趋于无穷大来使间隔任意大,但这显然不是我们想要的分类超*面。
我们需要约束这个超*面必须正确分类所有数据。这个约束可以写为:对于所有数据点 i,有 y_i (w^T x_i + b) > 0。这确保了每个点都被分类到正确的一侧。
因此,我们的优化问题变成了一个带约束的最大化问题。
简化优化问题
上述问题(最大化一个最小值)看起来很复杂。我们可以通过一系列巧妙的变换来简化它。
-
尺度不变性:超*面
w^T x + b = 0与(αw)^T x + (αb) = 0定义的是同一个超*面(α > 0)。这意味着w和b的尺度可以自由缩放,而不改变超*面本身。我们可以利用这个自由度来简化问题。 -
固定尺度:我们特意选择缩放
w和b,使得距离超*面最*的那些点满足|w^T x_i + b| = 1。也就是说,我们令最小间隔的绝对值等于1。通过这种缩放,我们的间隔公式简化为γ = 1 / ||w||。 -
转换目标:最大化
γ = 1 / ||w||等价于最小化||w||。为了数学处理的方便,我们通常最小化(1/2) ||w||^2(乘以1/2是为了后续求导时形式更整洁)。 -
重写约束:在我们固定的尺度下(最*点距离为1),并且要求所有点都被正确分类,原来的约束
y_i (w^T x_i + b) > 0可以加强为y_i (w^T x_i + b) >= 1。可以证明,在最小化||w||的目标下,最优解一定会使这个等号对至少一些点成立(这些点就是“支持向量”)。
经过这些变换,我们得到了支持向量机标准形式的优化问题:
优化问题:
min_{w,b} (1/2) ||w||^2
subject to: y_i (w^T x_i + b) >= 1, for all i
这是一个凸二次规划问题。目标函数是 w 的二次函数(凸抛物线),约束是 w 和 b 的线性函数。这类问题在数学优化领域被研究得非常透彻,存在许多高效且可靠的求解算法(称为QP求解器)。
总结
本节课我们一起学习了线性支持向量机的核心思想与数学形式化过程。
- 我们从寻找“最好”的分类超*面出发,引入了最大间隔的概念。
- 我们推导了点到超*面的距离公式,并定义了分类器的间隔。
- 我们通过利用超*面的尺度不变性,巧妙地缩放参数,将复杂的“最大化最小距离”问题,转化成了一个简洁的凸二次规划问题。
- 最终的标准形式是:最小化
(1/2)||w||^2,并满足所有y_i (w^T x_i + b) >= 1的约束。
支持向量机的优雅之处在于,它将一个机器学习问题转化成了一个具有坚实理论基础的优化问题,并且可以通过现成的优化工具直接求解。在下一节课中,我们将探讨如何求解这个优化问题,并介绍“支持向量”这一关键概念。
机器学习:015:支持向量机(续)与损失函数概述

在本节课中,我们将继续学习支持向量机(SVM),特别是如何处理线性不可分的数据。我们将引入松弛变量的概念,并探讨如何将SVM的优化问题转化为一个带有正则项的损失函数最小化问题。最后,我们将概述几种常见的机器学习损失函数,并比较它们的特性。

支持向量机与最大间隔
上一节我们介绍了支持向量机(SVM)的核心思想是寻找一个具有最大间隔的超*面来分隔两类数据。间隔被定义为超*面到最*数据点的距离。
对于一个能正确分类所有训练数据的超*面,我们希望最大化这个间隔。数学上,这可以表述为以下优化问题:在满足所有数据点都被正确分类且距离超*面至少为1的约束下,最小化权重向量 W 的范数*方。
其公式化的约束优化问题如下:
最小化: (1/2) * ||W||^2
约束条件: y_i * (W^T * x_i + b) >= 1, 对于所有 i
其中,y_i 是数据点 x_i 的标签(+1或-1),b 是偏置项。
处理线性不可分数据:松弛变量

然而,现实中的数据往往是线性不可分的。如果严格遵循上述约束,优化问题可能无解。为了解决这个问题,我们引入了松弛变量。

其核心思想是:我们允许某些数据点违反“间隔至少为1”的约束,但需要为此付出代价。我们为每个数据点 i 引入一个非负的松弛变量 ξ_i。新的优化问题变为:
最小化: (1/2) * ||W||^2 + C * Σ ξ_i
约束条件: y_i * (W^T * x_i + b) >= 1 - ξ_i, 对于所有 i
ξ_i >= 0, 对于所有 i
这里的参数 C 是一个超参数,它控制着我们对分类错误的容忍度。
- C 值很大:意味着我们非常不希望出现分类错误(即
ξ_i很大),优化会倾向于选择一个间隔较小但能正确分类更多点的超*面(接*硬间隔SVM)。 - C 值很小:意味着我们允许较多的分类错误,优化会倾向于选择一个间隔更大但可能误分类一些点的超*面。
参数C的选择没有固定规则,通常需要通过交叉验证等技术,在验证集上测试不同C值的效果来确定。

转化为损失函数形式

我们可以进一步将带有松弛变量的SVM优化问题改写为一个更通用的形式。观察约束条件,在最优解中,松弛变量 ξ_i 实际上等于 max(0, 1 - y_i * (W^T * x_i + b))。将其代入目标函数,我们得到:
最小化: Σ max(0, 1 - y_i * f(x_i)) + λ * ||W||^2
其中 f(x_i) = W^T * x_i + b 是我们的预测函数,λ = 1/C。
这个形式非常具有启发性,它揭示了许多机器学习算法的通用框架:
最小化: 损失函数(预测, 真实标签) + 正则化项(模型参数)
- 损失函数:衡量模型在训练数据上的预测错误程度。在上式中是
Σ max(0, 1 - y_i * f(x_i)),这被称为合页损失。 - 正则化项:惩罚模型复杂度,防止过拟合,鼓励更简单、泛化能力更强的模型。在上式中是
λ * ||W||^2,即L2正则化。

常见损失函数比较
以下是一些在机器学习中常用的损失函数(设 z = y_i * f(x_i),z 越大表示分类越正确):
-
0-1损失:
L_{0-1} = I(z < 0) # I是指示函数,当条件为真时值为1,否则为0- 最直观,直接计算错误分类的数目。
- 非凸、不连续,难以直接优化。
-
合页损失:
L_{hinge} = max(0, 1 - z)- SVM使用的损失函数。
- 当
z >= 1时损失为0,鼓励“间隔”内的点也被正确分类。 - 是0-1损失的一个凸上界,对异常值相对鲁棒。
-
逻辑损失(对数损失):
L_{log} = log(1 + exp(-z))- 逻辑回归使用的损失函数。
- 处处光滑可导。
- 能给出样本属于某类的概率估计。
- 不是0-1损失的上界。

- 指数损失:
L_{exp} = exp(-z)- AdaBoost算法使用的损失函数。
- 对误分类样本惩罚极其严厉,会迫使模型重点关注最难分类的样本。
- 对噪声数据非常敏感。
为了直观理解,我们可以画出这些损失函数随 z 变化的曲线:
- 0-1损失:在
z=0处有一个从0到1的跳跃。 - 合页损失:在
z=1处有一个“拐角”,之后线性上升。 - 逻辑损失:一条*滑下降的曲线,从
z很负时的*似线性,过渡到z很大时的接*0。 - 指数损失:一条下降速度极快的曲线,
z为负时值非常大。


合页损失和指数损失都是0-1损失的凸上界。当 z 趋向负无穷(即严重误分类)时,合页损失线性增长,而逻辑损失*似线性增长,这使得它们对异常值都不像指数损失那样敏感。

总结
本节课中我们一起学习了:
- 线性不可分SVM:通过引入松弛变量和超参数 C,使SVM能够处理有噪声或线性不可分的数据集。
- 优化视角转换:将SVM的约束优化问题转化为损失函数+正则化项的最小化问题,这揭示了机器学习中经验风险最小化的通用框架。
- 损失函数概览:我们介绍并比较了0-1损失、合页损失、逻辑损失和指数损失。理解不同损失函数的性质(如是否为0-1损失的上界、对异常值的敏感性、是否光滑等)对于为特定任务选择合适的模型至关重要。


这种“损失函数+正则化”的框架是理解许多现代机器学习算法的基础,在后续课程中我们会不断遇到它的各种变体。
机器学习:016:经验风险最小化



在本节课中,我们将要学习经验风险最小化(ERM)框架,这是机器学习算法的核心范式。我们将回顾其基本形式,并深入探讨回归问题中常用的几种损失函数,最后解释正则化的作用及其几何直观理解。

回顾:经验风险最小化框架


上一节我们介绍了经验风险最小化的基本思想。本节中,我们来看看其标准数学形式。
在机器学习中,我们通常将学习算法表述为寻找一组参数(通常称为权重 W)的过程。我们的目标是最小化一个由两部分组成的函数:



公式:
min_W [ Σ_i L( h_W(x_i), y_i ) + λ * R(W) ]
在这个公式中:
h_W(x_i)是模型对数据点x_i的预测。y_i是真实标签。L是损失函数,用于衡量预测值与真实值之间的差异。R(W)是正则化项,用于惩罚过于复杂的模型,防止过拟合。λ是一个超参数,用于控制正则化的强度。

我们之前讨论了几种经典的分类损失函数,包括合页损失(Hinge Loss)、逻辑损失(Logistic Loss)、0-1损失和指数损失。
回归问题中的损失函数



今天,我们将重点转向回归问题。在回归中,我们的目标是预测一个连续值,例如预测房价、温度或人的身高。
与分类问题类似,回归也有多种常用的损失函数。理解这些函数有助于我们根据数据特性做出合适的选择。以下是几种常见的回归损失函数:
*方损失
*方损失是我们最熟悉的损失函数之一,在普通最小二乘法和岭回归中都有应用。
公式:
L( h_W(x_i), y_i ) = ( h_W(x_i) - y_i )^2

*方损失的性质:
- 它总是非负的。
- 它对预测值过高或过低的惩罚是对称的。
- 由于是*方项,它对异常值(Outliers) 非常敏感。误差越大,惩罚呈二次方增长,这会使模型极力去拟合那些异常点。
- 如果模型忽略特征
x,仅输出一个常数来最小化*方损失,那么这个最优常数就是所有标签y_i的*均值(Mean)。 - *方损失处处可微,易于使用梯度下降等优化方法。

绝对损失


绝对损失是另一种直观的损失函数。

公式:
L( h_W(x_i), y_i ) = | h_W(x_i) - y_i |
绝对损失的性质:
- 它对误差的惩罚是线性的,因此对异常值不如*方损失敏感。
- 如果模型忽略特征
x,仅输出一个常数来最小化绝对损失,那么这个最优常数是标签y_i的中位数(Median)。 - 它在误差为0处不可微,这给优化带来了一些困难。

Huber损失


Huber损失结合了*方损失和绝对损失的优点,是两者的一种折中方案。
公式:
L_δ(a) = {
0.5 * a^2, if |a| ≤ δ
δ * |a| - 0.5 * δ^2, if |a| > δ
}
其中 a = h_W(x_i) - y_i。
Huber损失的性质:
- 当误差
a较小时(|a| ≤ δ),它表现为*方损失,具有良好的可微性。 - 当误差
a较大时(|a| > δ),它表现为绝对损失,对异常值不敏感。 - 超参数
δ决定了从“二次”区域切换到“线性”区域的阈值。δ越小,模型对异常值越鲁棒;δ越大,模型越接**方损失的行为。 - 它在
|a| = δ处不可微,但通常不影响优化。
Log-Cosh损失
Log-Cosh损失是另一种光滑且对异常值相对鲁棒的损失函数。
公式:
L( h_W(x_i), y_i ) = log( cosh( h_W(x_i) - y_i ) )
其中 cosh(x) = (e^x + e^{-x}) / 2。
Log-Cosh损失的性质:
- 它处处二次可微,优化性质良好。
- 对于小误差,其行为*似于*方损失;对于大误差,其行为*似于绝对损失。
- 计算
cosh和log函数的开销比*方或绝对损失要大。
损失函数对比与选择
为了直观理解不同损失函数的行为,我们可以绘制它们的图像。以下是关键点:
- *方损失:曲线为抛物线,对小误差惩罚小,对大误差惩罚急剧增大。
- 绝对损失:曲线为V字形折线,惩罚与误差成线性关系。
- Huber损失:在原点附*是抛物线,在远处过渡为两条直线。
- Log-Cosh损失:是一条光滑曲线,形状与Huber损失非常相似。
选择哪种损失函数取决于具体问题和数据特性:
- 如果数据中几乎没有异常值,且希望得到均值预测,*方损失是标准选择。
- 如果数据中包含显著异常值,且希望得到中位数预测或更鲁棒的模型,绝对损失、Huber损失或Log-Cosh损失更合适。
- Huber损失通常是一个很好的折中选择,因为它兼具可微性和鲁棒性。
正则化的几何解释
现在,让我们回到经验风险最小化公式中的正则化项 R(W)。我们最常用的是L2正则化,即 R(W) = W^T W。
从优化理论的角度看,带正则化的最小化问题等价于一个带约束的最小化问题:
等价形式:
min_W Σ_i L( h_W(x_i), y_i )
s.t. R(W) ≤ B
对于每一个正则化强度 λ,都存在一个对应的约束边界 B,使得两个问题的解是等价的。
以L2正则化 R(W) = ||W||^2 为例,约束 ||W||^2 ≤ B 意味着参数向量 W 必须位于一个高维球体(或圆) 内部。
几何直观:
- 想象损失函数
Σ_i L(...)在参数空间W中形成了一个“山谷”,谷底是无正则化时的最优解。 - L2正则化约束
||W||^2 ≤ B定义了一个以原点为中心、半径为sqrt(B)的球。 - 我们的优化目标是找到这个球内部使得损失函数最小的点。
- 这个点通常位于球边界与损失函数等高线相切的位置。
- 当
B很大(即λ很小)时,球很大,约束可能不起作用,解接*原始最优解。 - 当
B很小(即λ很大)时,球很小,解会被“拉向”原点,从而得到参数值更小、更简单的模型。
这种“约束球”的图像清晰地说明了正则化如何通过限制参数的大小来偏好更简单、更*滑的模型,从而有助于提高模型的泛化能力,防止过拟合。
总结
本节课中我们一起学习了经验风险最小化框架在回归问题中的应用。我们详细介绍了*方损失、绝对损失、Huber损失和Log-Cosh损失等回归损失函数,分析了它们各自的特性和适用场景。最后,我们从约束优化的角度深入探讨了L2正则化的几何意义,理解了它如何通过将参数限制在一个球体内来促使模型选择更简单的解,这是控制模型复杂度和提高泛化性能的关键机制。
机器学习:017:正则化与复习 🎯


在本节课中,我们将学习正则化的核心概念,特别是L1和L2正则化的原理、区别与应用。我们还将通过一个简短的问答环节,回顾课程前半部分的关键知识点。
正则化回顾 📝
上一节我们介绍了正则化的基本思想,即通过向损失函数中添加一个惩罚项来限制模型复杂度,从而避免过拟合。本节中,我们将深入探讨两种最流行的正则化方法:L2正则化和L1正则化。
L2正则化(岭回归)
L2正则化在损失函数中添加了权重向量 w 的L2范数*方项,其公式如下:
损失函数 = 原始损失 + λ * ||w||₂²
其中,λ 是控制正则化强度的超参数。
从几何角度看,L2正则化相当于在参数空间中施加了一个球体约束。它要求最优解必须位于一个以原点为中心、半径为某个值的球体内。这迫使所有权重值向零收缩,从而得到一个更“*滑”、更简单的解,通常能提高模型的泛化能力。




L1正则化(套索回归)
L1正则化则添加了权重向量 w 的L1范数项,其公式如下:
损失函数 = 原始损失 + λ * ||w||₁
从几何角度看,L1正则化的约束区域是一个菱形(在高维空间中是超立方体),它有尖锐的“角”。
以下是L1正则化的关键特性:
- 稀疏性:由于约束区域的尖角特性,最优解往往会落在这些角上,导致许多特征的权重精确为零。这实现了特征选择,生成了一个稀疏的模型。
- 可解释性:在科学领域(如生物信息学),知道哪些特征的权重为零至关重要,因为这有助于理解模型做出预测的依据。
- 非严格凸性:L1正则化不是严格凸的。如果存在两个完全相同的特征,优化问题可能有多个等价的最优解(例如,所有权重分配给特征A,或全部给特征B,或各分配一半)。这可能导致结果的不确定性。




弹性网络



为了结合L2和L1正则化的优点,人们提出了弹性网络。它在损失函数中同时加入L1和L2惩罚项:


损失函数 = 原始损失 + λ₁ * ||w||₁ + λ₂ * ||w||₂²


其中,λ₂ 通常设置得非常小。弹性网络既鼓励稀疏性(来自L1),又因为L2项的存在而保持了严格凸性,从而确保了唯一解,并提高了模型在特征高度相关时的稳定性。



正则化的实践演示
通过一个生物学数据集的Lasso(L1正则化 + *方损失)路径图演示,我们可以看到:
- 当正则化强度λ很大时,所有权重为零。
- 随着λ减小,最重要的特征权重首先变为非零。
- 测试误差会先下降后上升,存在一个最优的λ值(对应特定数量的非零特征),此时模型泛化能力最佳。这有助于研究者识别出真正有预测力的关键特征。
课程知识点复习问答 🧠
为了帮助大家准备期中考试,我们进行了一个简短的问答环节,回顾了前半课程的核心概念。
以下是涉及的部分问题与核心答案:
- K*邻的误差界:随着样本数N趋于无穷,K*邻分类器的误差最多是最优贝叶斯分类器误差的两倍。
- 朴素贝叶斯与逻辑回归的决策边界:当数据特征在给定类别下服从高斯分布且方差相同时,两者的决策边界是相同的。
- SVM中偏置项的处理:在SVM中,不能简单地将偏置项b作为常数1特征并入权重向量w,因为SVM的目标是最大化间隔,这仅涉及最小化 ||w||²,而不应最小化b²。将b吸收进w会无意中惩罚b,偏离了SVM的原始目标。
- K*邻用于回归:可以通过计算K个最*邻标签的(加权)*均值来进行回归预测。权重可以根据距离的倒数或指数衰减函数来设置。
- 各算法的数据假设:
- K*邻:相*的点具有相似的标签。
- 朴素贝叶斯:特征在给定类别下条件独立。
- 逻辑回归:数据(或特征的某种函数)适合于用Sigmoid函数建模(例如,属于指数族分布)。
- SVM:数据*似线性可分,且最大化间隔能带来更好的泛化。
- 损失函数与决策边界:通过观察决策边界形状,可以判断使用的是强正则化的*方合页损失、标准合页损失还是指数损失。
- SVM间隔公式:间隔之所以等于 1 / ||w||,是因为在推导SVM优化问题时,我们通过缩放权重和偏置,将函数间隔固定为1,从而简化了问题。
- 牛顿法的限制:除了收敛性问题,无法使用牛顿法的情况还包括:1)损失函数不是二阶可微的;2)数据集维度太高,计算或存储海森矩阵(Hessian)不可行;3)海森矩阵不可逆。
- 拉普拉斯*滑:在具有C个类别、每个特征有K个类别的分类朴素贝叶斯中,使用加1*滑(拉普拉斯*滑)的MAP估计,等价于为每个(类别,特征值)组合添加了1个“幻觉”样本,总计添加了 C × K 个样本。
- 算法选择场景:
- 文本分类(高维、稀疏):线性SVM通常表现更好。
- 患者生命体征预测(低维、非线性):K*邻可能更优。
- 手写数字识别(像素空间):K*邻通常能捕捉非线性关系,可能优于线性SVM。
- K*邻的计算复杂度:对于有N个训练样本、D维的数据集,如果K=N(即使用所有邻居),则预测时只需返回训练集中的多数类,时间复杂度并非O(ND),而是O(1)的查表操作。该问题强调了K值对计算的影响。
总结 📚


本节课中我们一起深入学习了正则化技术。我们明确了L2正则化通过权重收缩来获得*滑解,而L1正则化则能产生稀疏解,有助于特征选择和模型解释。弹性网络结合了二者的优点。通过实际演示,我们看到了正则化如何帮助控制模型复杂度并提升泛化性能。在随后的复习环节,我们回顾了K*邻、朴素贝叶斯、逻辑回归、支持向量机等核心算法的原理、假设与应用场景,为理解和应用这些机器学习基础模型巩固了基础。
机器学习:018:复习讲座 II 🎓
在本节课中,我们将回顾课程前半部分的核心概念,涵盖从机器学习基础框架到具体算法的关键知识点。我们将确保每一句话的含义都被准确传达,并以清晰、直白的方式组织成教程。
概述 📋
本节课我们将回顾监督学习的基本框架、几种核心算法(如K*邻、感知机、朴素贝叶斯、逻辑回归、线性回归和支持向量机)及其背后的原理,包括参数估计、优化方法和模型评估。
机器学习的一般框架 🏗️
在课程开始时,我们讨论了监督学习的一般设置。其核心思想是:我们有一个从某个分布 P 中独立同分布(i.i.d.)抽取的数据集 D,包含样本 (X₁, Y₁), ..., (Xₙ, Yₙ)。典型目标是给定 X 预测 Y。
为了评估和训练算法,我们通常将数据集 D 分为三部分:
- 训练集:用于训练算法。
- 验证集:用于估计模型在未见数据上的误差,以调整超参数。
- 测试集:仅在最终评估时使用一次,以提供对真实泛化误差的无偏估计。
验证集和测试集都是对真实期望误差(即泛化误差)的估计。当数据集足够大时,测试误差会接*真实的泛化误差。
训练误差是模型在训练集上的误差,通常远低于测试误差。例如,对于线性可分数据,SVM总能找到一个训练误差为0的超*面,但这并不意味着其泛化性能最佳。
算法分类:判别式 vs. 生成式,参数化 vs. 非参数化 📊
上一节我们介绍了评估框架,本节中我们来看看如何对学习算法本身进行分类。机器学习算法可以从不同角度分类。
判别式模型直接对条件概率 P(Y|X) 或决策函数 f(X) 进行建模。其目标是找到给定输入 X 时最可能的输出 Y。公式表示为:
f(X) = argmax_Y P(Y|X)
生成式模型则对联合概率 P(X, Y) 建模,通常通过估计似然 P(X|Y) 和先验 P(Y),再利用贝叶斯规则得到 P(Y|X)。公式为:
P(Y|X) ∝ P(X|Y) * P(Y)
判别式模型(如感知机、SVM)直接学习输入到输出的映射;生成式模型(如朴素贝叶斯)则学习数据是如何生成的。
另一种分类方式是参数化与非参数化:
- 参数化算法学习固定数量的参数,模型大小不随数据量增长。例如:感知机、逻辑回归、线性回归。
- 非参数化算法的模型复杂度或存储需求随数据量增长。例如:K*邻(需要存储全部训练数据)。
以下是主要算法的分类总结:
- K*邻:判别式,非参数化。
- 感知机:判别式,参数化。
- 支持向量机 (SVM):判别式,参数化。
- 朴素贝叶斯:生成式,参数化。
- 逻辑回归:判别式,参数化。
- 线性回归:判别式,参数化。
通常,参数化算法更快,而非参数化算法更灵活但需要更多存储和计算资源。
K*邻算法 👥
了解了算法分类后,我们来看第一个具体算法。K*邻是一种简单直观的非参数算法。它对一个新点进行分类时,基于其K个最*邻的标签进行多数投票。
K*邻的核心假设是:相似的点具有相似的标签。因此,距离度量的质量至关重要。如果度量不能反映标签的相似性,算法性能会下降。
关于K*邻的理论保证需要了解:在特定条件下,其误差上界是贝叶斯最优误差的两倍。此外,还存在维数灾难问题:在高维空间中,所有点都可能彼此远离,使得“最*邻”的概念变得模糊,需要指数级的数据量才能保持局部相似性。然而,在实际图像等数据上它仍能工作,因为数据本质上是低维流形嵌入在高维空间中,而非均匀充满高维空间。
感知机算法 ⚙️
从基于实例的K*邻转向参数化模型,我们来看感知机。感知机是一种简单的线性分类算法,其重要前提是假设数据是线性可分的。
感知机的更新规则很直观:一次查看一个数据点。如果分类正确,则不做任何操作;如果分类错误,则更新权重向量 W。对于正类误分类样本,将其特征向量加到 W 上;对于负类误分类样本,则从 W 中减去。公式化表示为,若 y_i * (W·X_i + b) <= 0,则更新 W = W + y_i * X_i。
感知机算法会在有限步内收敛(如果数据线性可分),并且可以证明其收敛步数的上界。两个实用技巧是:1) 通过添加一个值恒为1的维度,将偏置项 b 吸收进权重向量 W;2) 算法具有尺度不变性,可以缩放数据集以简化证明。

参数估计:最大似然估计与最大后验估计 📈
在学习了具体的分类算法后,我们回到概率建模的基础。许多生成式模型需要从数据中估计概率分布。两种核心方法是最大似然估计 和最大后验估计。
MLE 寻找能使观测数据 D 出现概率最大的参数 θ。即最大化似然函数 P(D|θ)。似然描述已发生事件的可能性,而概率描述未发生事件的可能性。
MAP 则寻找在给定数据下最可能的参数。即最大化后验概率 P(θ|D)。通过贝叶斯规则,P(θ|D) ∝ P(D|θ) * P(θ)。与MLE相比,MAP多了一项关于参数先验 P(θ) 的项,这通常等价于在目标函数中增加了正则化项。
理想的贝叶斯方法不是选一个最可能的参数,而是对所有可能的参数模型进行加权*均积分:P(Y|X, D) = ∫ P(Y|X, θ) P(θ|D) dθ。但这通常难以计算,因此MAP是一种实用的*似。
朴素贝叶斯算法 🎭
掌握了参数估计方法,我们就可以构建具体的生成式分类器。朴素贝叶斯的目标是估计 P(Y|X)。直接估计 P(Y|X) 需要大量数据,因为需要为每个具体的 X 组合观察足够多的样本。
因此,朴素贝叶斯转而利用贝叶斯规则:P(Y|X) ∝ P(X|Y) * P(Y)。先验 P(Y) 很容易从类频率估计。关键步骤是对似然 P(X|Y) 做出条件独立性的朴素假设,即假设在给定类别 Y 时,特征 X 的各个维度是独立的:
P(X|Y) = ∏_j P(X_j | Y)
这样,我们只需为每个特征维度单独估计一个简单的分布(如高斯分布、多项分布)。
尽管条件独立性假设在现实中很少完全成立,但朴素贝叶斯在实践中往往表现良好,尤其是在数据量较少时。这是因为引入分布形式假设(如高斯)相当于加入了先验知识,有助于防止过拟合。当数据量很大时,逻辑回归这类更灵活的判别式模型可能表现更好。
逻辑回归与优化方法 🔄
从生成式模型回到判别式模型,逻辑回归直接对条件概率 P(Y|X) 进行建模,其形式为:
P(Y=1|X, W) = 1 / (1 + exp(-W·X))
这通过最大化数据的对数似然(即最小化负对数似然损失)来拟合参数 W。
逻辑回归的损失函数是连续、可微且凸的,但没有闭合解,因此需要迭代优化。以下是两种主要方法:
梯度下降:使用损失函数的一阶泰勒展开(梯度)。沿负梯度方向以小步长迭代更新参数。简单稳定,但收敛可能较慢。
W_new = W_old - η * ∇L(W_old)
牛顿法:使用损失函数的二阶泰勒展开(包含海森矩阵)。通过求解二次*似的最小值来更新参数,步长更大。收敛速度更快(所需迭代次数少),但计算海森矩阵及其逆矩阵开销大(O(D³)),且在大步长下可能发散。
选择取决于数据维度 D 和样本量 N。对于低维数据,牛顿法可能更高效;对于高维数据,梯度下降或仅使用海森矩阵对角线的*似牛顿法更可行。自适应梯度方法(如AdaGrad)则为每个参数维度自动设置不同的学习率。
逻辑回归相比SVM的一个优势是它直接输出具有良好校准意义的概率 P(Y|X),这对于需要不确定性度量的决策场景很重要。SVM则专注于寻找最大间隔分类面,其原始输出是符号函数,不直接提供概率。
线性回归与支持向量机 📉
最后,我们回顾两种重要的线性模型。线性回归用于预测连续值。假设噪声服从高斯分布,通过MLE推导出的目标函数是*方损失;若使用MAP并假设参数先验为高斯分布,则得到带L2正则化的*方损失。
支持向量机 的目标是找到具有最大间隔的分离超*面。可以证明,间隔大小与权重向量的范数 ||W|| 成反比。因此,SVM的优化问题是:
最小化 (1/2)||W||²
约束条件:y_i (W·X_i + b) >= 1, 对于所有 i
这被称为硬间隔SVM。为了处理线性不可分数据,引入松弛变量 ξ_i,得到软间隔SVM:
最小化 (1/2)||W||² + C * Σ ξ_i
约束条件:y_i (W·X_i + b) >= 1 - ξ_i, 且 ξ_i >= 0
其中,C 是控制间隔大小与分类错误惩罚之间权衡的超参数。
总结 🎯
本节课我们一起回顾了机器学习的基础框架和多种核心算法。我们从监督学习的一般设置出发,了解了模型评估中训练集、验证集和测试集的作用。然后,我们学习了算法的不同分类方式(判别式/生成式、参数化/非参数化)。接着,我们深入探讨了K*邻、感知机、朴素贝叶斯、逻辑回归、线性回归和支持向量机等具体算法的原理、假设、优化方法及其优缺点。最后,我们简要回顾了逻辑回归和SVM中使用的优化技术(梯度下降、牛顿法)。理解这些基础概念和联系,对于掌握机器学习至关重要。
机器学习:019:偏差-方差分解 🎯


在本节课中,我们将要学习机器学习中一个极其重要的概念——偏差-方差分解。理解这个概念将彻底改变你思考数据科学的方式,帮助你诊断模型问题并做出更明智的算法选择。我们将从理论推导开始,最终得到一个清晰、实用的误差分解框架。









课程概述与背景






上一节我们介绍了模型评估的基础,本节中我们来看看泛化误差的根源。首先,课程开始前有一个简短的公告:来自亚马逊机器人部门的Darren将于5月20日晚上举办一场技术讲座,介绍为机器人系统设计软件时面临的实际挑战,并寻找合作实习生,感兴趣的同学可以参加。

现在,让我们进入正题。理解偏差-方差权衡是区分机器学习初学者与专家的关键。此外,即将发布的新项目也完全围绕本讲内容,认真理解将使项目完成起来非常轻松。


问题设定与符号定义

我们的设定与往常一样。我们有一个数据集 D,包含 N 个数据点:(x1, y1), (x2, y2), ..., (xN, yN)。为了推导简便,我们将在回归场景下进行讨论,即假设 yi ∈ R(例如预测房价)。
这些数据点是从某个未知的联合分布 P(x, y) 中独立同分布(i.i.d.)地采样得到的。这意味着,对于同一个特征向量 x,其对应的标签 y 可能并不唯一,而是服从一个条件分布 P(y|x)。例如,两套特征完全相同的房子,最终售价也可能不同。







期望标签




对于一个给定的 x,我们应该预测哪个 y 值呢?一个合理的做法是预测期望标签,记为 ȳ(x)。其定义如下:







ȳ(x) = E[y|x] = ∫ y * P(y|x) dy




这表示,对于特定的 x,我们预测所有可能 y 值的加权*均,权重为其出现的概率。

学习算法与假设

作为机器学习从业者,我们会使用某个学习算法 A。该算法接收训练集 D 作为输入,并输出一个假设(或称模型)h_D。这是一个从 x 映射到预测值 ŷ 的函数。
h_D = A(D)
例如,A 可以是感知机、支持向量机等算法,而 h_D 就是该算法学到的具体分类器或回归器。
泛化误差与期望误差
我们通常关心的是泛化误差,即模型在未见过的数据上的表现,而不是在训练集上的误差。
对于一个给定的、固定的分类器 h_D,其期望测试误差(使用*方损失)定义为:
Err(h_D) = E_(x,y)~P [ (h_D(x) - y)^2 ]
然而,h_D 本身是随机的,因为它依赖于随机采样的训练集 D。因此,更有意义的是评估学习算法 A 本身的期望性能。我们考虑算法在所有可能训练集上的*均表现:
Err(A) = E_D~P^N [ E_(x,y)~P [ (h_D(x) - y)^2 ] ]
这个公式的含义是:首先随机采样一个大小为 N 的训练集 D,用算法 A 训练得到 h_D;然后随机采样一个测试样本 (x, y),计算*方误差;最后对所有可能的 D 和 (x, y) 取期望。这就是算法 A 的期望泛化误差,也是我们分解的对象。
偏差-方差-噪声分解
现在,我们对 Err(A) 进行分解。核心技巧是引入“期望假设” h̄(x),它是在所有可能训练集上得到的假设的*均:
h̄(x) = E_D~P^N [ h_D(x) ]
我们可以通过从分布中采样许多不同的训练集,训练出多个模型,然后对它们的预测取*均来*似 h̄。
分解过程分为两步,主要运用了增加减去同一项和利用期望线性性质两个技巧。以下是推导后的最终结果:
Err(A) = E_x [ Var_D(h_D(x)) ] + E_x [ (h̄(x) - ȳ(x))^2 ] + E_(x,y) [ (ȳ(x) - y)^2 ]
让我们逐一审视这三项:
以下是误差的三个组成部分:
-
方差 (Variance):
E_x [ Var_D(h_D(x)) ]- 含义:衡量模型本身的稳定性。它表示由于训练数据的随机性,学习到的模型 h_D 与*均模型 h̄ 之间的差异程度。
- 高方差表现:模型对训练数据的小变动非常敏感,容易过拟合。在训练集上表现很好,但在测试集上表现波动大、差。
-
偏差*方 (Bias^2):
E_x [ (h̄(x) - ȳ(x))^2 ]- 含义:衡量模型族的拟合能力。它表示*均模型 h̄ 的预测与最优预测(期望标签 ȳ)之间的系统性误差。
- 高偏差表现:模型过于简单,无法捕捉数据中的潜在规律,导致欠拟合。无论在训练集还是测试集上,表现都不佳。
-
噪声 (Noise):
E_(x,y) [ (ȳ(x) - y)^2 ]- 含义:衡量问题本身的难度。它表示数据中固有的、不可约的随机波动,即最优预测 ȳ 与实际观测值 y 之间的差异。
- 高噪声表现:数据本身存在大量不确定性,任何模型能达到的最佳错误率都有一个下限。
直观理解:飞镖比喻 🎯
为了更直观地理解偏差和方差,可以想象一个向靶心投掷飞镖的游戏:
- 低偏差,低方差:飞镖都紧密地扎在靶心。这是理想情况。
- 低偏差,高方差:飞镖分散在靶心周围。*均落点在靶心,但每次投掷很不稳定。对应过拟合。
- 高偏差,低方差:飞镖都紧密地扎在同一个点,但这个点偏离了靶心。稳定地犯错。对应欠拟合。
- 高偏差,高方差:飞镖既分散,*均落点又偏离靶心。这是最糟糕的情况。
噪声则像是靶子本身在轻微晃动,增加了命中的固有难度。
总结与应用
本节课中我们一起学习了机器学习核心的偏差-方差分解。我们将算法的期望泛化误差清晰地分解为方差、偏差*方和噪声三部分之和。
理解这一分解具有重大实践意义:
- 诊断模型问题:当模型表现不佳时,你可以分析是方差大(过拟合)、偏差大(欠拟合)还是数据噪声高。
- 指导模型改进:
- 高方差?需要降低模型复杂度、使用正则化、获取更多数据、使用集成方法。
- 高偏差?需要增加模型复杂度、添加更多特征、减少正则化强度。
- 高噪声?需要尝试清洗数据、收集更精确的数据,或接受其作为误差下限。
在接下来的课程中,我们将从偏差-方差权衡的视角,深入探讨各种具体的技术(如正则化、模型选择、集成学习)是如何作用于这三个部分,从而提升模型泛化性能的。掌握这个框架,你将能更有目的性地进行机器学习实践。
机器学习:020:模型选择、正则化与过拟合 🎯
在本节课中,我们将要学习机器学习中一个核心概念:偏差-方差权衡。我们将深入探讨模型选择、正则化以及过拟合问题,并学习如何通过交叉验证等技术来找到模型的最佳配置。
偏差-方差分解回顾 📊


上一节我们介绍了偏差-方差分解,这是机器学习和数据科学中最重要的主题之一。本节中,我们来看看这个分解的具体含义。
我们考察算法A的期望测试误差,其中我们积分掉所有可能的训练数据D,并观察一个测试点(x, y)。其公式如下:
E_D, x, y [ (h_D(x) - y)^2 ]
这个*方误差项可以分解为三个可解释的部分:
- 方差:衡量不同训练集训练出的分类器之间的差异程度。公式为 E_x [ Var_D( h_D(x) ) ]。
- 噪声:衡量数据本身的固有不确定性。即使分类器完美预测了*均标签,仍然存在的误差。公式为 E_x, y [ (y - E[y|x])^2 ]。
- 偏差:衡量*均分类器的预测与真实*均标签之间的差距。它反映了模型假设与数据真实情况的不匹配。公式为 E_x [ (E_D[ h_D(x) ] - E[y|x])^2 ]。
这三个二次项的和恰好等于总的期望*方误差。理解每一项有助于我们在实践中改进机器学习模型。


偏差-方差权衡的实践演示 🎮
为了直观理解偏差-方差权衡,我们来看一个具体的演示。以下是演示的关键设置:


- 我们从已知的分布P中生成数据,这让我们可以精确计算偏差、方差和噪声。
- 我们使用一个带有核技巧的线性分类器,并通过改变正则化强度λ来观察效果。
以下是随着正则化强度λ变化,各项误差的变化趋势:
- 训练误差:随着λ增大(正则化增强),训练误差单调上升。
- 测试误差:呈现一个U形曲线。
- 当λ很小时,模型过拟合,测试误差高,主要由高方差导致。
- 当λ很大时,模型欠拟合,测试误差也高,主要由高偏差导致。
- 存在一个“最佳点”,使得测试误差最小,此时偏差和方差达到*衡。
- 噪声:通常与λ无关,是数据分布固有的常数项。
作为数据科学家,我们的目标就是通过调整模型(如改变λ)来找到这个最佳*衡点。
模型选择与交叉验证 🔍
既然我们知道了存在过拟合和欠拟合的风险,那么如何为模型选择最佳的超参数(如λ)呢?最常用的方法是交叉验证。





网格搜索
最简单的方法是网格搜索。以下是其基本步骤:
- 将数据集划分为训练集和验证集。
- 预设一组待尝试的超参数值(例如,λ = [0.001, 0.01, 0.1, 1, 10])。
- 对于每一个λ值,用训练集训练模型,并在验证集上计算误差。
- 选择在验证集上误差最小的那个λ值。

为了提高效率,通常先进行粗粒度的对数尺度搜索(如10的幂次),定位大致范围后再在该范围内进行细粒度搜索。
K折交叉验证
简单的单次划分验证集存在风险:可能会因为验证集本身的随机性而“过拟合”验证集。更稳健的方法是K折交叉验证。
以下是K折交叉验证的步骤:
- 将训练数据随机均匀分成K份(或“折”)。
- 进行K次循环。在第i次循环中:
- 将第i份数据作为验证集。
- 将剩余的K-1份数据合并作为训练集。
- 用该训练集训练模型,并在该验证集上计算误差。
- 对于每个超参数设置,我们得到K个验证误差,取其*均值作为该设置的性能估计。同时,我们还可以计算误差的标准差,以评估性能的稳定性。
K值越大(如留一法交叉验证,即K等于样本数),估计越准确,但计算成本也越高。通常根据数据量大小和计算资源在5到10之间选择K值。
重要提示:测试集应仅在最终模型评估时使用一次,以报告无偏的性能估计。在模型选择和调参过程中,只使用训练集和验证集。
正则化与早停法 ⏱️
控制过拟合的另一个重要技术是早停法。它应用于优化过程(如梯度下降)中。
在标准训练中,我们持续优化直到损失函数收敛。而早停法则是在训练完全收敛之前就停止迭代。这相当于在参数空间中找到的解决方案的范数较小。
早停法与L2正则化有深刻的联系:
- L2正则化:在损失函数中增加权重范数的惩罚项,相当于在参数空间限制了一个“球”,优化器不能超出这个球的范围。
- 早停法:从初始点(通常是接*零向量的点)开始梯度下降。早期迭代产生的参数范数很小。随着迭代增加,参数范数增长。提前停止迭代,相当于隐式地限制了一个参数范数的上限。





因此,更多的训练迭代相当于更弱的正则化。早停法的误差曲线与正则化类似:随着迭代次数增加,训练误差持续下降,而测试误差先下降后上升,同样存在一个最佳停止点。

总结 📝
本节课中我们一起学习了机器学习模型的核心权衡——偏差-方差分解。我们了解到总误差可以分解为偏差、方差和噪声三部分,而模型复杂度的选择(通过正则化强度λ或训练迭代次数体现)直接影响偏差和方差的*衡。

- 过拟合对应高方差、低训练误差、高测试误差。
- 欠拟合对应高偏差、高训练误差、高测试误差。
为了找到最佳模型,我们介绍了网格搜索和K折交叉验证来稳健地选择超参数。此外,我们还探讨了早停法作为一种隐式的正则化技术,及其与显式正则化的内在联系。掌握这些概念和方法,是构建泛化性能良好模型的关键。
机器学习:021:模型选择与核方法

在本节课中,我们将要学习如何诊断和解决机器学习模型中的偏差与方差问题,并介绍一种通过特征变换来提升模型表达能力的重要技术——核方法。
考试情况回顾
上一节我们介绍了偏差-方差分解,本节我们来看看如何应用它来调试模型。但在开始之前,先简要回顾一下期中考试的情况。
考试总分为90分,整体情况良好。虽然没有人获得满分,但有两位同学获得了88分的高分。分数分布非常*滑。


上图是按分数排序的学生成绩分布,每个条形代表一名学生。得分在60到88分之间的同学表现不错。得分低于50分的同学需要引起注意,因为期末考试占总成绩的50%,如果期末成绩没有显著提升,最终成绩可能会不理想。如果你决定继续学习本课程,请务必参加答疑时间,我们一起分析问题所在。
考试答案已发布在课程网站上。由于助教们加班加点批改,部分晚交的试卷可能尚未完成评分,但大家可以通过参考答案预估自己的成绩。
关于作业截止日期,课程网站上Homework 4的截止日期有误,它实际上是在春假前一天截止。我们会在Piazza上发布更正通知。
总体而言,大家对第一道题的掌握非常好,中位数得分是满分。出乎意料的是,朴素贝叶斯部分对很多同学来说反而是最难的。
偏差-方差权衡回顾
两个讲座之前,我们展示了如何将误差(以最小化*方损失为例,但结论具有一般性)分解为三个可解释的部分。
误差 = 方差 + 偏差² + 噪声
我们观察了不同情况下的误差曲线。上一次我们看了早停法,其曲线大致如下所示。

随着优化迭代次数的增加,训练误差不断下降。测试误差先下降,到达一个“最佳点”后再次上升。在迭代次数较少时,测试误差过高,这是因为模型欠拟合,尚未充分学习数据。在迭代次数过多时,测试误差上升,这是因为模型过拟合,过度记忆训练数据而丧失了泛化能力。
在实践中,调整正则化强度参数 λ 和调整优化迭代次数 n 的效果非常相似。但早停法(调整 n)有一个显著优势:它通常更快。这是为什么呢?
想象你在优化一个权重向量 w。早停法从 0 开始,沿着优化路径前进,但在到达全局最优点之前就停止。L2正则化则是限制 w 必须在一个半径为 R 的球内(由 λ 控制)。为了找到最佳的正则化强度,我们需要进行交叉验证。
以下是交叉验证的步骤:
- 将训练集分成K份。
- 对于每个候选的 λ 值,用K-1份数据训练模型,用剩下的1份数据验证。
- 重复K次,计算*均验证误差。
- 选择验证误差最小的 λ 值。

这个方法的问题在于,对于每个 λ,你都需要重新训练模型直到收敛,这非常耗时。而早停法只需要训练模型一次:在训练过程中,每隔几次迭代就记录一次模型在验证集上的误差。训练结束后,回顾所有记录,选择验证误差最低时对应的模型参数即可。因此,对于像神经网络这样训练成本高的模型,早停法是更高效的选择。
需要注意的是,早停法并非适用于所有优化算法,例如对于直接调用二次规划求解器的SVM,就没有“迭代次数”的概念。
机器学习调试实战
现在,让我们扮演数据科学家的角色。假设你的老板交给你一个任务:训练一个垃圾邮件分类系统,并要求测试错误率低于 ε(例如1%)。你训练了模型,但错误率高于 ε,这时你该怎么办?
这就是机器学习调试。关键是要找出总误差中哪一部分过高。总误差由方差、偏差*方和噪声相加而成。如果知道哪一部分最大,就能对症下药,高效地降低总误差。
那么,如何诊断呢?这里有一个简单实用的技巧。
你需要绘制一张图。横轴是使用的训练数据量(从数据集中随机抽取的子集大小),纵轴是误差。
首先,绘制训练误差曲线。当训练数据极少(例如只有1个样本)时,任何像样的算法都能完美拟合,训练误差为 0。随着训练数据增加,问题变难,训练误差会逐渐上升并趋于*稳。
接着,绘制测试(或验证)误差曲线。当训练数据极少时,测试误差会非常高。随着数据增加,测试误差会下降。重要的是,测试误差永远不会低于训练误差,训练误差是测试误差的下界。

根据图像,我们可以区分两种需要调试的情况:
情况一:高偏差
特征:
- 训练误差高于目标误差 ε。
- 测试误差仅略高于训练误差(两者差距小)。
含义:
模型过于简单,无法捕捉数据中的基本模式。即使在训练数据上表现也很差。
解决方案:
- 增加模型复杂度:例如,使用核方法(即将介绍)。
- 添加更多特征:提供更多信息给模型。
- 使用集成方法:如Boosting(后续课程介绍)。
重要提示: 在高偏差情况下,增加更多训练数据通常没有帮助。因为训练误差本身已经高于 ε,且只会随着数据增加而上升,测试误差无法突破这个下限。
情况二:高方差
特征:
- 训练误差低于目标误差 ε。
- 测试误差远高于训练误差(两者差距大)。
含义:
模型过于复杂,对训练数据中的噪声也进行了学习,导致泛化能力差。
解决方案:
- 增加训练数据:这是最有效的方法之一,可以缩小训练误差和测试误差之间的差距。
- 降低模型复杂度:例如,使用更简单的模型。
- 增加正则化强度:增大 λ。
- 使用集成方法:如Bagging(后续课程介绍)。
调试过程可能是一个权衡过程。当你解决了高偏差问题后,可能会引入高方差问题,反之亦然。需要反复调整,直到训练误差和测试误差都低于目标误差 ε。
如果噪声本身已经大于 ε,那么可能需要检查数据质量、进行数据清洗或添加更能解释问题的特征。
特征变换与核方法引入
现在,我们来看一个具体的例子,学习如何通过特征变换来解决高偏差问题。

假设我们有一个二维数据集,分布如下图所示。圆圈(O)分布在一个圆形区域内,叉号(X)分布在原点右侧的一个小高斯分布中。

你的任务是分类。如果你使用线性分类器(如线性SVM),决策边界可能是一条直线,效果很差(错误率接*50%)。这显然是一个高偏差问题:线性模型太简单,无法刻画圆形的决策边界。
我们不想放弃高效的线性模型框架。一个古老的技巧是进行特征变换:将原始特征 x 映射到一个更高维的空间 φ(x),使得在新空间中数据是线性可分的。
例如,对于这个二维数据,我们可以添加一个新特征:点到原点的距离(即 x₁² + x₂²)。这样,数据就从二维 (x₁, x₂) 变成了三维 (x₁, x₂, 距离)。在新空间中,一个*面就能完美地将两类数据分开。将这个*面决策边界映射回原始二维空间,就得到了我们想要的圆形边界。

在实际问题中,我们很难像这个例子一样直观地知道该添加什么特征。一个大胆的想法是:添加所有可能的多项式组合特征。
假设原始特征为 x₁ 到 x_D。我们可以构造如下变换:
- 添加偏置项 1。
- 保留所有原始特征 x₁ ... x_D。
- 添加所有二阶特征组合:x₁x₂, x₁x₃, ..., x_{D-1}x_D。
- 添加所有三阶特征组合,依此类推,直到 D 阶组合 x₁x₂...x_D。
这样,我们就得到了一个极其高维的特征空间。这个空间的维度是多少呢?对于每个原始特征,在新的多项式特征中,它可以选择“出现”或“不出现”(在0次到多次之间)。这实际上有 2^D 种可能(考虑所有子集的特征乘积,虽然有些组合如 x₁² 是重复的,但数量级相似)。当 D 很大时,这个维度是灾难性的,直接计算 φ(x) 并存储变得不可能。
这就引出了下一节的核心——核技巧。核技巧允许我们在不显式计算高维特征 φ(x) 的情况下,直接在高维空间中计算样本间的相似度(点积),从而高效地训练线性模型。我们将在下节课详细探讨。

总结

本节课我们一起学习了:
- 模型调试:通过绘制训练/测试误差随数据量变化的曲线,可以诊断模型处于高偏差还是高方差状态。
- 解决方案:
- 高偏差:增加模型复杂度、添加特征、使用更强大的模型(如核方法、Boosting)。
- 高方差:增加训练数据、降低模型复杂度、加强正则化、使用Bagging。
- 特征变换:通过将数据映射到更高维空间,可以使原本线性不可分的数据变得线性可分,从而利用高效的线性模型。
- 核方法引入:为了应对显式特征变换带来的维度灾难,我们引入了核技巧的概念,它将在下一节课详细展开。
掌握这些调试技巧和核心思想,对于在实际工作中有效应用机器学习模型至关重要。
机器学习:第22讲:更多关于核函数的内容


在本节课中,我们将学习如何利用核函数这一强大工具,来克服机器学习模型中的高偏差问题。我们将看到,通过将数据映射到极高维甚至无限维的空间,线性分类器可以学习极其复杂的非线性决策边界,而计算开销却可以保持可控。

上一节我们介绍了如何通过诊断训练误差和测试误差之间的差距来识别高偏差或高方差问题。本节中,我们来看看如何具体解决高偏差问题。


解决高偏差:增加特征

高偏差问题的核心是模型过于简单,无法捕捉数据中的复杂模式。一个直观的解决方案是增加特征,以增强模型的表达能力。

例如,对于一个二维数据集,其中正例呈环形分布,负例分布在周围,线性分类器无法将其分开。但如果我们添加特征,例如 x1^2 和 x2^2,数据在新的三维空间中就变得线性可分了。
以下是增加特征的一种系统化方法:考虑所有特征之间的可能交互项。
- 常数项:1
- 一次项:
x1, x2, ..., xd - 二次项(两两交互):
x1*x2, x1*x3, ..., xd-1*xd - 三次项:
x1*x2*x3, ... - 依此类推,直到 d 次项:
x1*x2*...*xd


这种方法虽然能有效降低偏差,但会带来一个严重问题:特征维度爆炸。对于 d 个原始特征,这种扩展会产生 2^d 个新特征。对于 d=1000 这样的常见情况,2^1000 是一个天文数字,无法实际计算和存储。

第一个技巧:用内积表示分类器
为了处理这种高维表示,我们需要第一个技巧。我们发现,对于许多线性模型(如使用*方损失的线性回归),最优权重向量 w 可以表示为训练数据点的线性组合。

公式:w = Σ(α_i * x_i),其中 i 从 1 到 n(训练样本数),α_i 是标量系数。
这个结论可以通过梯度下降法的归纳证明得到:从 w=0 开始,每次梯度更新 w := w - η * ∇L(w) 都只是给 w 加上训练样本 x_i 的倍数,因此 w 始终保持在训练样本张成的子空间中。
这个表示法的巨大优势在于,我们不再需要直接存储和计算高维向量 w,而只需存储 n 个标量 α_i。这使得处理超高维特征空间成为可能,因为存储开销仅与数据量 n 有关,而与特征维度 d 无关。
在训练和预测时,我们只需要计算 w 与某个向量 z 的内积,而这个内积可以完全用 α_i 和样本间的内积来表示。
公式:w^T * z = Σ(α_i * (x_i^T * z))
因此,整个算法可以只通过数据点之间的内积 x_i^T * x_j 来运行。
第二个技巧:核函数技巧
虽然我们只需要内积,但计算 2^d 维空间中的内积 φ(x_i)^T * φ(x_j) 本身仍然非常昂贵。这就是第二个魔法技巧——核函数技巧——发挥作用的地方。
对于前面提到的包含所有交互项的特征映射 φ(x),其内积有一个极其简洁的计算公式:
公式:φ(x)^T * φ(z) = (1 + x^T * z)^d
左边是 2^d 维空间中的内积,计算量巨大。右边只是一个原始特征空间中的内积 x^T * z 加上 1,再取 d 次方,计算仅需 O(d) 时间。我们通过核函数 K(x, z) = (1 + x^T * z)^d 来隐式地定义了高维空间中的内积。
这意味着,我们可以在极高维的特征空间中训练线性分类器,获得强大的非线性能力,而实际计算成本却只与原始维度 d 相关。我们永远不需要显式地写出或计算 φ(x)。
常用的核函数
核函数 K(x, z) 必须是对称且正定的(即对于任意一组点,由 K(x_i, x_j) 构成的矩阵是半正定的)。以下是一些常见的核函数:
- 线性核:
K(x, z) = x^T * z。这对应于原始特征空间,即没有进行特征映射。 - 多项式核:
K(x, z) = (γ * x^T * z + r)^d。其中d是多项式次数,γ和r是参数。它对应于有限维的特征空间。 - 径向基函数核:
K(x, z) = exp(-γ * ||x - z||^2)。这是最著名、最常用的核函数之一。它对应于一个无限维的特征空间,具有通用逼*性,理论上可以使任何数据集(在没有重复且标签不同的样本的情况下)变得线性可分。参数γ控制了高斯分布的宽度。

核函数的强大之处在于,它允许我们为各种结构化数据(如文本、图、序列)定义相似性度量(即核函数),从而在这些数据上应用线性模型,而无需显式地将其转化为向量。
总结

本节课中我们一起学习了核方法的核心思想。为了克服模型的高偏差,我们希望通过增加特征(如特征交互)来提升模型复杂度,但这会导致维度灾难。通过两个关键技巧:
- 将分类器权重
w表示为训练样本的线性组合,使存储与特征维度无关。 - 利用核函数
K(x, z)隐式计算高维空间中的内积,使计算成本大幅降低。
我们得以在极高维甚至无限维的空间中高效地训练线性模型,从而使其具备强大的非线性分类能力。最常用的径向基函数核因其通用逼*性质而备受青睐。核方法将机器学习模型的适用性扩展到了各种非向量型数据上。
机器学习:023:核方法进阶







在本节课中,我们将继续深入学习核方法。上一节我们介绍了核方法的基本思想,即通过核函数将数据隐式映射到高维空间,从而让线性分类器能够学习复杂的非线性决策边界。本节中,我们将探讨如何构造新的核函数,以及如何将现有的机器学习算法“核化”。



核函数构造规则
上一节我们介绍了线性核、RBF核和多项式核。但核函数远不止这些。如果你能根据特定数据构造合适的核函数,就能在不显式计算高维特征向量的情况下,高效地进行学习。以下是构造核函数的一些基本规则。
以下是八条核心的核函数构造规则:


- 线性核是核函数:最基本的核函数是线性核
K(x, z) = x^T z。这直接对应原始特征空间的内积。 - 常数缩放:如果
K1(x, z)是一个核函数,c是一个非负常数,那么c * K1(x, z)也是一个核函数。 - 加法封闭性:如果
K1(x, z)和K2(x, z)都是核函数,那么K1(x, z) + K2(x, z)也是一个核函数。 - 多项式变换:如果
K1(x, z)是一个核函数,g(·)是一个具有非负系数的多项式函数,那么g(K1(x, z))也是一个核函数。 - 乘法封闭性:如果
K1(x, z)和K2(x, z)都是核函数,那么K1(x, z) * K2(x, z)也是一个核函数。 - 函数变换:如果
K1(x, z)是一个核函数,f(·)是任意一个从输入空间到实数的函数,那么f(x) * K1(x, z) * f(z)也是一个核函数。 - 指数变换:如果
K1(x, z)是一个核函数,那么exp(K1(x, z))也是一个核函数。 - 矩阵变换:如果
A是一个半正定矩阵,那么K(x, z) = x^T A z也是一个核函数。当A是单位矩阵时,就回到了线性核。
利用这些规则,我们可以从简单的核(如线性核)出发,组合出复杂的新核。
实例:证明RBF核是有效核函数

让我们运用上述规则来证明径向基函数(RBF)核是一个有效的核函数。RBF核的定义为:
K(x, z) = exp(-||x - z||^2 / (2σ^2))
证明步骤如下:
- 从线性核开始:
K1(x, z) = x^T z(规则1)。 - 进行缩放:
K2(x, z) = (1/(σ^2)) * (x^T z)(规则2)。 - 利用恒等式
||x - z||^2 = x^T x - 2x^T z + z^T z,我们可以将RBF核的指数部分重写为:exp(-(x^T x)/(2σ^2) + (x^T z)/(σ^2) - (z^T z)/(2σ^2))。 - 这可以看作是
exp(K2(x, z))乘以两个函数项。具体地,令f(x) = exp(-(x^T x)/(2σ^2)),那么K(x, z) = f(x) * exp((x^T z)/(σ^2)) * f(z)。 - 根据规则7,
exp((x^T z)/(σ^2))是核函数(因为它是exp(K2(x, z)))。 - 根据规则6,用函数
f(x)和f(z)分别乘以前后,结果f(x) * exp((x^T z)/(σ^2)) * f(z)仍然是核函数。 - 这个表达式正好等于
exp(-||x - z||^2 / (2σ^2)),因此RBF核是有效的。
实例:集合核
核函数不仅限于数值向量。假设我们的数据是集合(例如,文本中的词袋模型)。我们可以定义一个集合核:
K(S1, S2) = exp(|S1 ∩ S2|)
其中 |S1 ∩ S2| 是两个集合交集中元素的数量。



如何证明这是一个有效的核?我们可以将每个集合 S 表示为一个很长的二进制向量 φ(S)。向量的每个维度对应全集中的一个可能元素。如果该元素在集合 S 中,则对应位置为1,否则为0。这样,两个集合的交集大小就等于它们对应向量 φ(S1) 和 φ(S2) 的内积:|S1 ∩ S2| = φ(S1)^T φ(S2)。
于是,集合核 K(S1, S2) = exp(φ(S1)^T φ(S2))。根据规则1(线性核是核)和规则7(指数变换保持核性质),可知该集合核是有效的。尽管 φ(S) 可能维度极高甚至无限,但核技巧允许我们仅通过计算交集大小来高效地使用这个核。




算法的核化








将一个算法“核化”意味着将其改写,使其所有数据访问都仅通过内积进行,然后用核函数替换这些内积。这是一个两步过程:
- 重写算法,确保所有数据操作都表示为数据点之间的内积形式。
- 将内积
x_i^T x_j替换为核函数K(x_i, x_j)。
核化最*邻算法
让我们尝试核化最*邻算法。标准最*邻使用欧氏距离寻找最*点:
distance(x, z) = ||x - z||
由于*方操作不改变距离排序,我们可以使用*方欧氏距离:
distance_sq(x, z) = ||x - z||^2 = x^T x - 2 x^T z + z^T z
这个表达式完全由内积 x^T x, x^T z 和 z^T z 组成。因此,我们可以直接进行核替换:
distance_sq_kernel(x, z) = K(x, x) - 2K(x, z) + K(z, z)
现在,我们可以使用任何有效的核函数 K 来计算“距离”,并找到核空间中的最*邻。这就是核化最*邻算法。不过需要注意的是,最*邻算法本身已经是非线性的,核化对其性能提升可能不如对线性分类器那样显著。
核化岭回归
岭回归(带L2正则的线性回归)的闭式解为:
w = (X^T X + λI)^{-1} X^T y
我们希望将权重 w 表示为训练样本的线性组合:w = X α。将其代入上式:
X α = (X^T X + λI)^{-1} X^T y
为了解出 α,我们在等式两边左乘 X^T,并利用一些矩阵恒等式进行推导(详细过程见课堂板书),最终可以得到:
α = (K + λI)^{-1} y
其中 K 是核矩阵,其元素 K_{ij} = K(x_i, x_j)。这就是核化岭回归的解。在预测时,对于新点 x_{new},预测值为:
y_pred = Σ_{i=1}^{n} α_i K(x_i, x_{new})
在代码中,这可以非常简洁地实现,例如在Python中,求解 α 的核心代码*乎一行:alpha = np.linalg.inv(K + lambda * I) @ y。
总结

本节课中我们一起深入探讨了核方法。我们首先学习了构造新核函数的八条基本规则,这些规则使我们能够像搭积木一样从简单核创建复杂核。接着,我们运用这些规则证明了RBF核和集合核的有效性。最后,我们掌握了将算法核化的通用方法,并将其应用于最*邻算法和岭回归,得到了对应的核化版本。核方法的强大之处在于,它允许我们在不显式处理高维甚至无限维特征空间的情况下,利用其表达能力和线性模型的优化便利性。
机器学习:024:核支持向量机

在本节课中,我们将要学习核支持向量机。我们将回顾核方法的基本概念,并深入探讨如何将支持向量机这一强大的线性分类器通过核技巧扩展到非线性领域。课程将从回顾核函数的定义和性质开始,然后详细讲解如何将线性回归核化,最后重点介绍支持向量机的核化过程及其对偶形式。
课程反馈与项目回顾
上一节我们介绍了核函数的基本规则。在本节开始前,我们先回顾一下课程反馈和之前的项目。
根据课程调查,大部分反馈是积极的。关于在线*台的问题已反馈给相关团队并得到改进。多数学生认为课程工作量适中,并希望涵盖深度学习内容,这部分内容后续会安排。
关于垃圾邮件分类项目,领先团队分享了他们的方法。
以下是提高分类性能的几种有效技术:
- 停用词移除:移除如“the”、“a”等常见但对分类无意义的词汇。
- 二元语法:不仅考虑单个词,还考虑连续的两个词作为特征。
- 向量归一化:将特征向量除以文档总词数,使特征与文档长度无关,这对于新闻分类等任务尤其有用。
- 自定义特征加权:为某些对区分垃圾邮件特别有效的词汇或符号分配更高的权重。
这些方法也是实际垃圾邮件过滤器中的常用技术。此外,垃圾邮件发送者常使用模板生成看似不同的邮件,因此使用跳跃语法(允许两个关键词之间存在任意间隔词)来捕捉这种模式也很有效。



核方法回顾

在春假之前,我们讨论了核方法。我们主要探讨了两个主题:如何定义有效的核矩阵,以及如何对一个算法进行核化。
核函数的作用
核化源于我们对线性分类器的偏爱。线性分类器的形式为:
h(x) = w^T x + b
这类分类器算法高效,但偏差很高,只能学习线性决策边界。根据偏差-方差权衡,如果数据本身不是线性可分的,即使有无限数据,线性分类器也无法正确分类。

为了降低偏差,一个方法是将数据 x 映射到一个高维特征空间 φ(x)。在高维空间中,数据更可能变得线性可分。但问题是,w 的维度也变得极高。
我们发现,许多算法实际上只通过内积形式访问数据。因此,如果我们能巧妙地选择映射 φ(x),就可以定义一个核函数 K(x, z),它能够高效地计算高维空间中的内积:
K(x, z) = φ(x)^T φ(z)
例如,多项式核可以映射到指数级的高维空间,但计算依然很快。径向基函数核则对应于一个无限维的映射。

有效核函数的条件



并非任意函数都能作为核函数。一个函数 K 是有效核函数的充要条件是:对于任意一组向量,由其构成的核矩阵 K(其中 K_ij = K(x_i, x_j))必须是半正定的。

我们介绍了一些规则,可以从简单的核函数(如线性核 K(x, z) = x^T z)出发,通过一系列操作(如相加、相乘、指数运算)构造出新的、有效的核函数。例如,我们可以从线性核出发,通过应用这些规则证明指数核是有效的。
算法的核化步骤
一旦有了核函数,对算法进行核化通常包含两个步骤:
- 证明算法在训练和测试阶段都只通过内积形式访问数据。
- 将这些内积替换为核函数 K(x, z)。
核化线性回归
上一讲我们以线性回归为例演示了核化过程。让我们快速回顾一下。
线性回归最小化以下损失函数:
L(w) = Σ_i (w^T x_i - y_i)^2



可以写成矩阵形式:min_w || X^T w - y ||^2。
为了核化,我们利用最优解 w 可以表示为训练数据的线性组合这一性质:w = X α。将其代入损失函数,得到:
L(α) = || X^T X α - y ||^2
其中 X^T X 就是核矩阵 K,因为 (X^T X)_ij = x_i^T x_j = K(x_i, x_j)。因此问题转化为:
min_α || K α - y ||^2
这是一个关于 α 的优化问题。通过求导并设为零,我们可以得到闭式解:
α = K^{-1} y
测试阶段的应用
在测试时,对于新点 z,预测值为:
h(z) = w^T φ(z) = (X α)^T φ(z) = α^T (X^T φ(z)) = Σ_i α_i K(x_i, z)
这里,K(x_i, z) 构成了一个核向量 k_*。因此,核化回归的最终分类器是一个基于 α 和核函数的线性组合。
参数化 vs. 非参数化
核回归是参数化还是非参数化算法?这取决于视角。从学习高维权重 w 的角度看,它是参数化的(参数数量由特征空间维度决定)。但从学习系数 α 的角度看,参数数量随训练数据量 n 增长,因此它是非参数化的。通常,当使用像RBF核这样的无限维核时,我们将其视为非参数化算法。
核支持向量机
现在,我们来看最著名的核化算法——支持向量机。正是SVM的成功推动了核方法长达十年的研究热潮。

SVM的对偶形式
线性SVM的原始优化问题是:
min_{w,b} (1/2) ||w||^2 + C Σ_i ξ_i
s.t. y_i (w^T x_i + b) ≥ 1 - ξ_i, ξ_i ≥ 0
这是一个凸二次规划问题。在优化理论中,每个凸优化问题都有一个对应的对偶问题。推导SVM的对偶问题后,我们得到以下形式:
max_α Σ_i α_i - (1/2) Σ_{i,j} α_i α_j y_i y_j K(x_i, x_j)
s.t. 0 ≤ α_i ≤ C, Σ_i α_i y_i = 0
这个形式的美妙之处在于,数据点仅以内积 x_i^T x_j 的形式出现。这直接启发了核技巧:我们可以将内积替换为核函数 K(x_i, x_j),从而在隐式的高维空间中求解SVM。
求解对偶问题后,最优权重 w 可以表示为:
w = Σ_i α_i y_i x_i
最终的决策函数为:
h(z) = sign( Σ_i α_i y_i K(x_i, z) + b )
其中偏置 b 可以通过支持向量(即 α_i > 0 对应的点)所满足的边界条件 y_i (w^T x_i + b) = 1 求解得出。
在对偶问题中,大部分 α_i 为0,只有少数位于分类边界附*的数据点对应的 α_i 非零,这些点就是支持向量,这也是算法名称的由来。

课程项目预告
接下来的项目将要求你们实现SVM的原始问题和对偶问题。
- 实现原始问题:将线性SVM的原始形式表述为二次规划问题,并用求解器求解。在线性可分数据上测试。
- 处理非线性数据:当数据非线性可分时,原始线性SVM会失败。
- 实现核化对偶问题:我们将提供对偶形式。你需要使用核矩阵(如RBF核)来定义目标函数和约束,并再次用二次规划求解器求解。使用线性核在可分数据上调试,确保结果与原始问题一致。
- 应用与调优:在复杂的非线性数据(如螺旋数据)上应用核SVM。最后,通过交叉验证网格搜索来优化SVM的超参数(如正则化参数 C 和核参数 γ),找到使误差最小的配置。
总结


本节课我们一起学习了核支持向量机。我们首先回顾了核方法的原理和算法核化的步骤,并通过线性回归的例子加深理解。然后,我们重点探讨了支持向量机如何通过对偶形式自然地引入核函数,从而能够高效地处理非线性分类问题。核SVM的稀疏性(仅依赖支持向量)是其一大优势。最后,我们预告了相关的实践项目,这将帮助大家巩固对核SVM实现和调优的理解。
机器学习:025:核化算法与高斯过程入门





在本节课中,我们将学习核化算法的核心思想,特别是支持向量机(SVM)与最*邻算法的联系,并初步介绍高斯过程的基本概念及其与高斯分布的紧密关系。





课程安排与竞赛通知

在上一节中,我们深入探讨了核方法。本节我们将继续这一主题,并引入高斯过程。


首先,有两项课程安排通知。


以下是具体安排:
- 我们将安排助教开展复习课,计划每周或每两周一次。首次复习课将讲解核方法,后续课程涵盖高斯过程、提升方法和深度学习。
- 我们将举办一次机器学习竞赛。我会提供一个带标签的训练数据集,你们需要提交对无标签测试集的预测结果。此次竞赛可作为额外加分机会,模拟真实场景下的机器学习应用。竞赛预计在本周末或下周初发布,截止日期可能在课程最后一天。任务类型暂未确定,但很可能是分类问题。




核化算法回顾
上一节我们介绍了核方法。我们首先讨论了核回归。
核回归的预测公式为:
[
h(z) = \mathbf{k}_*^T (K + \lambda I)^{-1} \mathbf{y}
]
其中,(\mathbf{k}*) 是测试点 (z) 与所有训练点 (x_i) 的核向量,(K) 是训练点之间的核矩阵,其元素为 (K = k(x_i, x_j))。
接着,我们讨论了核支持向量机(SVM)。核SVM通过利用优化理论中的对偶问题实现核化。
对于一个凸最小化问题,必然存在一个对偶最大化问题,两者在解处等价。对偶问题仅通过数据点的内积访问数据。因此,求解对偶问题后,只需将内积矩阵替换为核矩阵即可实现核化,这是一种非常优雅的方法。

对偶SVM的权重向量最终形式为:
[
\mathbf{w} = \sum_i \alpha_i y_i \phi(\mathbf{x}_i)
]

其中 (\phi) 是将数据映射到高维空间的函数,我们无需显式计算。对于任意测试点 (z) 的分类决策函数为:



[
h(z) = \text{sign}\left( \sum_i \alpha_i y_i k(\mathbf{x}_i, \mathbf{z}) + b \right)
]
核SVM与最*邻算法的联系

现在,让我们仔细审视核SVM的决策函数。本课程开始时,我们介绍了最简单的机器学习算法——k最*邻算法。
k最*邻算法的决策函数可以写成:
[
h(\mathbf{z}) = \text{sign}\left( \sum_i y_i \cdot \delta(\mathbf{x}_i \text{ 是 } \mathbf{z} \text{ 的最*邻}) \right)
]
其中 (\delta) 是指示函数,当 (x_i) 是 (z) 的k个最*邻之一时取值为1,否则为0。

将此公式与核SVM的决策函数 (h(z) = \text{sign}\left( \sum_i \alpha_i y_i k(\mathbf{x}_i, \mathbf{z}) + b \right)) 进行比较,会发现它们非常相似。

以高斯(RBF)核为例:(k(\mathbf{x}_i, \mathbf{z}) = \exp(-|\mathbf{x}_i - \mathbf{z}|^2 / \sigma^2))。当测试点 (z) 与某个训练点 (x_i) 距离很远时,核函数值趋*于0;距离很*时,核函数值较大。这与最*邻算法中只考虑邻*点的思想一致,但核SVM使用的是软阈值(通过高斯衰减),而非最*邻的硬阈值截断。
系数 (\alpha_i) 的作用是什么?在对偶问题中,(\alpha_i) 总是非负的,且许多 (\alpha_i) 为0。这意味着SVM会为数据点分配权重,并直接移除那些 (\alpha_i=0) 的点(即非支持向量),因为它们不影响分类决策。


因此,核SVM(特别是使用RBF核时)可以看作是一种智能化的最*邻算法,它主要做两件事:
- 通过设置 (\alpha_i=0) 来精简训练数据集,移除对决策边界没有贡献的“明显”样本。
- 对测试点进行预测时,根据高斯核函数对邻*点进行软加权*均,在数据密集区域考虑更多邻居,在稀疏区域考虑更少邻居。



引入高斯过程


我们尚未结束对核算法的讨论。接下来要介绍的算法是高斯过程。
在我看来,高斯过程是回归任务中与SVM(分类任务中的强者)地位相当的算法。SVM在分类上表现优异,但在回归上有些笨拙;反之,高斯过程非常擅长回归,但其分类版本则不那么好用。它们的能力是互补的。
要理解高斯过程,我们需要先思考高斯分布。
高斯分布的重要性
高斯分布是一种非常美妙的分布。高斯过程之所以强大,正是因为它建立在高斯分布的基础上,而高斯分布具有许多优良特性。


首先,自然界中许多事物都*似服从高斯分布,例如人的身高(在区分性别后)或智商(理论上)。这是因为中心极限定理。


中心极限定理指出:如果一个分布具有有限方差,那么从该分布中多次采样并计算*均值,这些*均值的分布将趋*于高斯分布。
这意味着,任何由大量独立因素*均作用形成的随机变量,其分布往往接*高斯。例如,身高受基因、营养等多种因素共同影响。
高斯分布还是分布的“黑洞”:一旦涉及高斯分布,结果往往仍是高斯分布。以下是高斯分布对几种运算的封闭性:
以下是高斯分布保持封闭性的运算:

- 求和:两个高斯随机变量之和仍是高斯分布,新分布的均值是原均值之和,方差是原方差之和。
- 边缘化:从一个高维联合高斯分布中,对某些变量积分(即忽略它们),得到的边缘分布仍是高斯分布。
- 条件化:已知一个高维联合高斯分布中部分变量的值,则其余变量的条件分布仍是高斯分布。

这些性质,尤其是条件化,将是高斯过程的核心。
高斯分布运算示例
考虑两个相关的随机变量,例如我房子的价格((x_2))和我邻居房子的价格((x_1))。它们可能服从一个联合高斯分布,两者正相关。
如果我对邻居房价这个变量进行边缘化(即不考虑邻居的具体售价,只关心我的房价),那么我的房价的分布仍然是一个高斯分布。
如果我对邻居房价进行条件化(即已知邻居房子以某个特定价格售出),那么我的房价的条件分布也是一个高斯分布,并且其均值会随着已知的邻居房价变化而变化。相关性越强,已知信息对我房价估计的影响就越大。
如果两个变量不相关(例如我的房价和比尔·盖茨的房价),那么已知比尔·盖茨的房价,我的房价的条件分布不会改变,均值保持不变。
这种相关性是通过协方差矩阵来编码的。对角元素表示各个变量自身的方差,非对角元素表示变量之间的协方差,决定了它们相互影响的程度。

总结
本节课中,我们一起学习了:
- 核SVM在本质上是一种软加权最*邻算法,它通过核函数实现软邻域选择,并通过支持向量精简数据集。
- 引入了高斯过程作为强大的回归工具,并铺垫了其理论基础——高斯分布。
- 回顾了高斯分布的中心极限定理成因及其关键性质:对求和、边缘化、条件化等运算保持封闭性。这些性质是理解高斯过程如何工作的基石。
下节课我们将正式深入高斯过程,看看如何利用这些性质构建一个强大的非参数回归模型。
机器学习:026:高斯过程 🧠












在本节课中,我们将学习高斯过程回归。这是一种强大的贝叶斯非参数方法,用于回归任务。我们将从回顾线性回归开始,逐步推导出高斯过程的核心思想,并理解其如何直接对预测分布进行建模,而无需显式地学习模型参数。








上一节我们介绍了线性回归及其参数学习方法。本节中,我们来看看如何从贝叶斯视角重新思考回归问题,并最终引出高斯过程。



在标准线性回归中,我们假设数据由带噪声的线性函数生成:
y = w^T x + ε,其中 ε ~ N(0, σ²)。
我们的目标是学习参数 w。
我们曾讨论过两种学习 w 的方法:
- 最大似然估计:寻找使数据似然
P(D|w)最大化的w。 - 最大后验估计:寻找使后验概率
P(w|D) ∝ P(D|w)P(w)最大化的w,其中P(w)是参数的先验分布(通常也设为高斯分布)。
然而,最终我们关心的并不是参数 w 本身,而是对于新的测试点 x* 的预测 y*。贝叶斯方法提出,与其先估计一个单一的 w,不如直接对预测分布 P(y* | x*, D) 进行建模。这可以通过对所有可能的模型 w 进行积分(边缘化)来实现:
P(y* | x*, D) = ∫ P(y* | x*, w) P(w | D) dw。

高斯分布有一个美妙的性质:它是分布的“黑洞”。以下是高斯分布的一些关键性质:
- 两个高斯分布的和是高斯分布。
- 两个高斯分布的乘积是高斯分布(归一化后)。
- 对高斯分布进行边缘化得到高斯分布。
- 对高斯分布进行条件化得到高斯分布。

在线性回归的设定中,如果似然 P(y|x, w) 和先验 P(w) 都是高斯的,那么后验 P(w|D) 也是高斯的。进而,预测分布 P(y* | x*, D)(一个高斯似然与一个高斯后验的乘积再边缘化)也将是高斯分布。这意味着,我们可以绕过对具体参数 w 的估计,直接得到一个关于预测 y* 的高斯分布。
基于上述推导,我们可以做出一个更直接的建模假设:所有观测数据(训练标签和测试标签)在给定其输入时,联合服从一个多元高斯分布。这就是高斯过程回归的核心假设。
我们假设:
P([y₁, ..., y_N, y*] | [x₁, ..., x_N, x*]) ~ N(μ, Σ)
为简化,我们通常假设均值 μ 为零(数据可以预先去均值处理)。关键在于协方差矩阵 Σ。

协方差矩阵 Σ 定义了不同数据点之间的相关性。其元素 Σ_ij 由核函数 k(x_i, x_j) 计算得到:
Σ_ij = k(x_i, x_j)。
核函数衡量了两个输入点 x_i 和 x_j 的相似性。相似的点应具有较高的协方差(相关性),不相似的点协方差较低。
以下是核函数的一个经典例子:
- 径向基函数核:
k(x, z) = exp(-||x - z||² / (2l²)),其中l是长度尺度参数。当x和z很接*时,核函数值接*1;当它们相距很远时,值接*0。
这个协方差矩阵必须是一个半正定矩阵,而这正是核函数所满足的性质。
现在,我们有了训练数据 D = {(x_i, y_i)} 和一个测试点 x*。根据我们的联合高斯假设,所有数据的联合分布是:
[y; y*] ~ N(0, [K, k_*; k_*^T, k_**])
其中:
K是N×N的矩阵,K_ij = k(x_i, x_j),表示训练点之间的协方差。k_*是N×1的向量,k_*i = k(x_i, x*),表示测试点与各训练点之间的协方差。k_**是标量,k_** = k(x*, x*),表示测试点自身的方差。
我们已知训练标签 y 的值。我们想知道在给定这些观测的条件下,测试标签 y* 的分布,即 P(y* | x*, D)。利用多元高斯分布的条件化公式,我们可以得到:
y* | x*, D ~ N(μ*, σ*²)
其中:
- 预测均值:
μ* = k_*^T K^{-1} y - 预测方差:
σ*² = k_** - k_*^T K^{-1} k_*
预测均值 μ* 的形式与核岭回归的预测器完全相同。然而,高斯过程不仅给出了点估计 μ*,还给出了该估计的不确定性度量 σ*²。方差在训练数据密集的区域较小,在数据稀疏或外推的区域较大。
为了直观理解高斯过程的应用,考虑一个实际的优化场景:贝叶斯优化。
假设我们想要最小化一个评估代价非常高昂的未知函数 f(x)(例如,寻找最佳化学反应配方,每次实验都耗时费钱)。我们可以使用高斯过程来对 f(x) 进行建模。
- 首先,随机或在少数几个点评估函数,获得初始数据。
- 用高斯过程拟合这些数据。此时,GP 给出了一个对
f(x)的估计(均值函数)以及每个点的不确定性(置信区间)。 - 利用一个采集函数(如“期望提升”)来决定下一个评估点。采集函数会*衡探索(在不确定性高的区域采样,以了解更多函数信息)和利用(在预测值低的区域采样,以找到最小值)。
- 在新的点进行评估,将结果加入数据集,并更新高斯过程模型。
- 重复步骤3和4,直到达到预算或找到满意的解。
这种方法被广泛应用于超参数调优、实验设计和机器人学等领域。一个著名的历史案例是在搜索失踪的马航 MH370 客机残骸时,团队就使用了类似高斯过程的方法来指导海底搜索区域。

本节课中我们一起学习了高斯过程回归。我们从线性回归的贝叶斯视角出发,通过边缘化模型参数,推导出直接对预测分布建模的思想。核心在于假设所有数据的标签联合服从一个多元高斯分布,其协方差由核函数定义。高斯过程回归的最终预测结果是一个高斯分布,既提供了预测均值(与核回归一致),也提供了预测方差,量化了预测的不确定性。这种不确定性估计使得高斯过程在需要决策信心的场景(如贝叶斯优化)中极具价值。
机器学习:027:高斯过程 II 与 KD-树、球树



在本节课中,我们将完成对高斯过程的学习,并通过一个演示来直观理解其应用。随后,我们将转向一个完全不同的主题——用于加速最*邻搜索的数据结构,特别是KD-树和球树。
高斯过程回顾
上一节我们介绍了高斯过程的基本概念。让我们再快速回顾一下其核心思想。
我们从线性模型开始,其中 y = wᵀx + b,并加入高斯噪声。学习权重 w 有两种经典方法:最大似然估计和最大后验估计。它们都为我们提供了一个具体的模型 w,然后用于预测。
我们引入了另一种“完全贝叶斯”或“真实贝叶斯”方法。其核心思想是:我们不固定一个模型 w,而是考虑所有可能的模型。对于测试点 x,其预测分布 *p(y | x, D)** 是所有可能模型预测的加权*均,权重由训练数据 D 下得到该模型的概率决定。由于所有分布都是高斯的,这个积分的结果也是一个高斯分布。
既然结果总是一个高斯分布,我们可以直接假设整个数据集(包括训练点和测试点)的标签联合服从一个高维高斯分布。这被称为高斯过程。我们通常假设其均值为0(可以通过减去标签均值实现),关键在于其协方差函数(或核函数)K。
协方差矩阵 K 的对角线元素 σᵢᵢ 表示每个数据点自身标签的方差。非对角线元素 σᵢⱼ 则表示点 i 和点 j 标签之间的相关性。这正是我们嵌入算法假设的地方。例如,如果我们假设“相似的点有相似的标签”,可以使用径向基函数核:σᵢⱼ = exp(-||xᵢ - xⱼ||² / σ²)。如果我们假设线性关系,则可以使用线性核:σᵢⱼ = xᵢᵀxⱼ。
在给定训练数据标签 y 和协方差矩阵 K 后,测试点 y* 的条件分布仍然是高斯的,其均值和方差有闭式解:
- 均值:μ* = k*ᵀ K⁻¹ y
- 方差:σ*² = k - kᵀ K⁻¹ k**
其中,k* 是测试点与所有训练点之间的协方差向量,**k**** 是测试点自身的协方差。

高斯过程的优势在于,它不仅提供预测值,还提供了预测的不确定性估计,这对于回归问题尤其有价值。
高斯过程应用演示:贝叶斯优化
高斯过程一个非常流行的应用是贝叶斯优化,用于寻找未知且评估成本高昂的函数的最小值。一个典型的例子是机器学习模型的超参数调优。
假设我们有一个支持向量机,需要优化核宽度 σ 和正则化参数 λ。评估一组超参数意味着用这组参数训练模型并在验证集上计算误差,这非常耗时。
以下是两种方法的对比:
- 网格搜索:尝试所有可能的 σ 和 λ 组合。
- 贝叶斯优化(基于高斯过程):
- 首先随机尝试几组超参数,得到对应的验证误差。
- 用这些数据拟合一个高斯过程回归模型,该模型可以预测任意超参数组合下的验证误差及其不确定性。
- 基于一个权衡准则(如“期望提升”),选择下一个最有希望评估的超参数组合(可能是预测误差低的地方,或不确定性高的地方)。
- 评估该点,更新高斯过程模型,重复此过程。
演示表明,贝叶斯优化通常能比网格搜索更快地找到优秀的超参数组合,因为它智能地利用了已有信息来指导搜索,避免了在效果很差的区域进行大量无用尝试。

另一个有趣的应用是“主动学习”,在获取数据标签成本高昂时(如医学测试),高斯过程可以帮助决定下一个最值得标注的数据点,从而高效地学习决策边界。
警告:高斯过程非常强大,但其预测能力有时会带来不受欢迎的结果。例如,美国北卡罗来纳州曾立法,在预测海*面上升时,禁止使用非线性模型(如高斯过程),只允许使用线性外推,这被广泛认为是对科学建模的政治干预。
转向最*邻算法与加速需求
高斯过程在使用RBF核时,其行为类似于一个加权的最*邻算法。现在,我们将花一些时间讨论最*邻算法本身及其加速方法。

最*邻算法的一个主要缺点是速度慢。对于一个测试点,为了找到其最*邻,我们需要计算它与数据集中所有点的距离,然后找出最小值。这在大数据集上是不可行的。
一个直观的加速想法是:如果我们能预先将数据空间划分成区域,那么对于测试点,我们只需在它所在的区域及其附*区域搜索,而可以忽略那些明显很远的区域。KD-树和球树正是基于这种思想的数据结构。
KD-树:原理与构建
KD-树是一种用于组织k维空间中点的二叉树数据结构。其核心思想是递归地使用轴对齐的超*面分割空间。
以下是构建KD-树的基本步骤:
- 选择分割维度:通常选择数据方差最大的维度,或者轮流选择各个维度。
- 确定分割点:在该维度上,选择中位数作为分割点。这样可以保证树是*衡的。
- 分割数据:将数据点根据其在该维度上的值,小于中位数的分到左子树,大于等于的分到右子树。
- 递归:对左右子树重复步骤1-3,直到子区域内的点数量少于某个阈值,或达到最大深度。
构建完成后,每个叶节点对应空间中的一个“盒子”,里面包含一些数据点。


KD-树:最*邻搜索
使用KD-树进行最*邻搜索比线性扫描高效得多。过程如下:
- 下行:从根节点开始,根据测试点在当前分割维度上的值,决定向左或向右子树移动,直到到达一个叶节点。
- 局部搜索:在该叶节点包含的点中,找到距离测试点最*的点,作为“当前最*邻”及其距离 d_current。
- 回溯与剪枝:
- 从叶节点回溯到父节点。
- 检查父节点代表的另一个分支(即未被访问的子树)是否可能包含更*的点。判断依据是:测试点到该分支所在区域边界(即分割超*面)的垂直距离是否小于 d_current。
- 如果垂直距离 >= d_current,则意味着该分支整个区域内的所有点都至少比当前最*邻远,因此可以安全地“剪枝”掉,无需搜索。
- 如果垂直距离 < d_current,则必须进入该分支进行搜索(即对该子树递归执行步骤1-3)。
- 继续回溯:继续向上回溯,重复步骤3,直到回溯至根节点。
为什么可以这样剪枝?
利用勾股定理可以严格证明。考虑测试点 x_t、当前最*邻 x_nn、以及分割超*面。设测试点到超*面的垂直距离为 a,到当前最*邻的距离为 d_current。对于超*面另一侧的任意点 x_other,其到测试点的距离 d_other 满足:d_other ≥ a。因此,如果 a ≥ d_current,则必然有 d_other ≥ d_current,所以 x_other 不可能是更*的邻居。
总结
本节课中我们一起学习了:
- 高斯过程的核心思想:通过假设数据标签的联合高斯分布,并利用协方差矩阵编码点之间的相似性假设,直接进行贝叶斯推断,得到带有不确定性估计的预测。
- 高斯过程的应用:重点介绍了贝叶斯优化,它利用高斯过程高效地寻找昂贵函数的最优解,在超参数调优等领域非常有效。
- 最*邻算法的加速需求:线性扫描的最*邻搜索复杂度高,需要借助空间数据结构来加速。
- KD-树的工作原理:
- 构建:递归地使用轴对齐超*面(按维度中位数)分割空间,形成*衡二叉树。
- 搜索:通过“下行-局部搜索-回溯剪枝”的策略,避免搜索整个数据集,将*均搜索复杂度从 O(N) 降低到接* O(log N)。
下一讲,我们将继续探讨另一种加速最*邻搜索的数据结构——球树,并比较它们的优缺点。
机器学习:028:球树与决策树 🎯




在本节课中,我们将学习两种重要的数据结构:球树(Ball Trees)和决策树(Decision Trees)。我们将从回顾上一讲介绍的KD树开始,探讨其在最*邻搜索中的应用及其局限性,然后介绍球树如何克服这些局限。最后,我们将看到如何从*似最*邻搜索自然地引出决策树的概念。
回顾:KD树 📐
上一节我们介绍了KD树,这是一种用于加速最*邻搜索的数据结构。其核心思想是递归地将数据空间沿坐标轴进行分割。
KD树的构建
构建KD树的算法很简单:
- 从包含整个数据集的根节点开始。
- 选择数据分布最分散的维度。
- 计算该维度上数据点的中位数。
- 将数据点分割:大于中位数的进入右子树,小于中位数的进入左子树。
- 对左右子树递归地重复步骤2-4。
- 当节点中的数据点数量小于某个阈值 M 时停止。
这个过程会生成一个二叉树,其深度约为 log2(N)。
KD树的最*邻搜索
对于一个测试点,搜索其最*邻的算法如下:
- 从根节点开始,根据分割规则向下遍历树,直到到达一个叶节点。
- 在该叶节点内计算测试点到所有点的距离,找到当前最*邻及其距离。
- 以测试点为中心,以当前最*邻距离为半径画一个“球”。
- 开始回溯。对于路径上的每个父节点(对应一个分割超*面),检查这个“球”是否与超*面相交。
- 如果不相交,则可以“剪枝”——排除该超*面另一侧的整个子树,因为其中不可能有更*的点。
- 如果相交,则必须进入该侧子树进行搜索。
- 重复步骤2-4,直到检查完所有可能包含更*点的分支。
这个算法本质上是带有剪枝的深度优先搜索(DFS)。
KD树的局限性
KD树在低维空间(如2维、3维)中表现优异。然而,在高维空间中,其性能会急剧下降,原因在于“维数灾难”:
- 在高维空间中,数据点趋于稀疏,最*邻的距离与最远邻的距离差异不大,使得最*邻搜索本身意义减弱。
- 更重要的是,KD树使用轴对齐的分割方式。在高维空间中,数据点几乎总是位于分割超*面的“边界”附*,导致回溯时无法有效剪枝,最终可能仍需检查几乎所有数据点。
即使数据本质上是低维的(例如位于一个嵌入在高维空间中的流形上),KD树依然无效,因为轴对齐的分割无法适应流形的复杂结构。
球树:应对高维数据 🌐
为了解决KD树在高维空间中的问题,我们引入了球树。球树的核心思想是放弃轴对齐分割,使用超球面来划分空间,从而更好地适应数据的几何结构。
球树的构建
构建球树的步骤如下:
- 对于一个数据集,我们希望找到一个具有最大展布的方向进行分割。一个高效的启发式方法是:
- 随机选择一个点 A。
- 找到离 A 最远的点 B。
- 找到离 B 最远的点 C。
- 向量 BC 的方向*似于最大展布的方向(类似于主成分分析的效果)。
- 将所有数据点投影到方向 BC 上,并沿投影值的中位数将数据集分成两部分。
- 对于每个子集,计算其均值点(中心)和到最远点的距离(半径),形成一个能包含该子集所有点的最小包围球。
- 对每个子集递归地重复步骤1-3,直到满足停止条件(如球内点数少于阈值)。
最终,我们得到一棵树,每个节点存储着一个球的中心和半径。
球树的最*邻搜索



搜索过程与KD树类似,但判断逻辑变为基于球面距离:
- 从根节点(最大的球)开始,根据测试点离哪个子球中心更*,选择一条路径向下遍历至叶节点。
- 在叶节点包含的数据点中计算最*邻,得到当前最佳距离。
- 开始回溯。对于路径上的每个兄弟节点(对应一个球),计算测试点到该球中心的距离。
- 如果
(距离 - 球半径) > 当前最佳距离,则该球内不可能有更*的点,可以剪枝整个子树。 - 否则,必须进入该球进行搜索。


球树的优势在于:
- 对高维不变量:其性能主要取决于数据的本征维度(如流形的维度),而非环境空间的维度。增加无关的噪声维度或进行旋转,对球树结构影响很小。
- 几何适应性:球面分割能更好地包裹低维流形上的数据。
球树的性能考量
尽管球树在高维下比KD树更有效,但随着维度升高,其剪枝效率也会下降。此外,在现代计算机架构下需要权衡:
- 向量化计算:暴力计算(计算测试点到所有点的距离)可以利用高度优化的矩阵运算和并行计算(如GPU),速度极快。
- 单点查询开销:球树每次查询需要计算点到球心的距离并进行逻辑判断,当数据维度很高、剪枝收益不大时,其开销可能超过暴力计算的向量化优势。
因此,在实践中,可以通过增大叶节点球的尺寸(包含更多点)来*衡树的深度与向量化计算的优势。
从*似最*邻到决策树 🌲
基于树结构的最*邻搜索可以进一步优化,从而引出一个经典的机器学习算法——决策树。

*似最*邻搜索


首先,我们做一个*似:进行最*邻搜索时,不进行回溯。
- 从根节点开始,沿着树向下遍历到一个叶节点。
- 仅在该叶节点内寻找最*邻并返回。
这种方法速度极快(仅需O(log N)次遍历),虽然可能不是精确最*邻,但对于分类任务,只要返回的邻居标签正确,结果就是可接受的。


存储标签而非数据
我们可以进一步优化:在构建树时,记录每个叶节点内数据点的类别分布。
- 如果一个叶节点内的点都属于同一类,那么任何落入该节点的测试点,其最*邻都将具有这个标签。因此,我们无需存储原始数据,只需在该叶节点上存储这个确定的标签。
- 如果一个叶节点内包含混合类别,我们可以存储类别的经验概率分布(例如,5个A类,3个B类,则概率为5/8和3/8)。对于测试点,我们可以根据这个分布进行随机预测,或者直接输出概率。
这样,我们就不再需要存储原始训练数据,只需存储树结构以及每个叶节点的标签或标签分布。模型大小变得极小。
决策树的诞生
上述思想自然引出了决策树算法:
- 它是一棵树结构,每个内部节点代表一个基于特征的判断(类似于KD树的分割规则)。
- 每个叶节点代表一个决策结果(分类标签或回归值)。
- 预测时,从根节点开始,根据测试样本的特征值选择分支,最终到达一个叶节点,并输出该节点的结果。
一个关键问题是:能否通过不断分割,使所有叶节点都“纯”(只包含同一类数据)?
- 答案是否定的。反例是:存在两个特征完全相同但标签不同的数据点。它们最终必然会进入同一个叶节点,无法通过基于特征的分割将其分开。
- 排除上述情况后,答案是肯定的。只要没有特征完全相同的异类点,总可以找到某个特征及其分割点,将不同类的点分开。可以通过归纳法证明。
在实践中,为了避免“特征相同、标签不同”的情况,可以在数据中加入微小的随机噪声(如 1e-9),这在数值上几乎无影响,但能保证算法的顺利进行。


总结 📝
本节课我们一起学习了:
- KD树:一种用于低维空间最*邻搜索的高效数据结构,使用轴对齐分割,但在高维空间因维数灾难而失效。
- 球树:通过使用超球面分割来改进KD树,能更好地处理高维数据和低维流形,其性能依赖于数据的本征维度。
- 从*似搜索到决策树:通过放弃精确回溯、仅搜索单一叶节点,并最终用叶节点的标签分布代替原始数据,我们自然地推导出了决策树的基本框架。决策树是一种古老但重要的模型,后续我们将看到如何通过集成方法使其变得非常强大。
机器学习:029:决策树与回归树 🌳

在本节课中,我们将要学习决策树的基本概念、构建方法以及如何将其应用于分类和回归问题。我们将从决策树的直观理解开始,逐步深入到其背后的数学原理,特别是如何通过“不纯度”函数来构建和评估决策树。

从最*邻到决策树
上一节我们介绍了KD树,它是一种用于加速最*邻搜索的数据结构。我们提到,如果只关心最*邻的标签而非其确切位置,那么可以只搜索KD树叶子节点内的点,这是一种*似最*邻方法。
本节中我们来看看,如果更进一步,我们甚至不需要在叶子节点内进行搜索。如果一个叶子节点内的所有数据点都具有相同的标签,那么任何落入该节点的测试点都可以直接被赋予这个标签。这就是决策树的起点:我们不再存储数据点,而是为树的每个叶子节点关联一个标签。
决策树示例 🦸
让我们回到一个现实世界的重要问题:判断一个超级英雄是正义还是邪恶。
训练数据:
- 正义英雄:蝙蝠侠、罗宾、猫女
- 邪恶反派:小丑、企鹅人、阿尔弗雷德(?)


特征:
- 是否戴面具
- 是否戴帽子
- 是否打领带
- 是否把内裤穿在外面



测试案例:你的约会对象(需要判断其善恶)。
我们可以构建一个决策树来进行判断。例如:
- 首先判断“是否吸烟”?如果是,进入右分支。
- 在右分支判断“是否有尖耳朵”?如果没有,则判定为“邪恶”。
- 如果“不吸烟”,则进入左分支,判断“是否戴面具”?
- 如果不戴面具,则判定为“邪恶”;如果戴面具,则根据“身高是否大于1.75米”进一步判断。
通过这个树,我们可以对测试点进行分类。然而,这个树可能无法完美分类所有训练数据(例如,可能将善良的阿尔弗雷德误判为邪恶)。这说明我们需要一个更好的树。
一个关键点是:只要没有两个特征完全相同但标签不同的数据点,我们总可以通过不断分裂(增加树的深度)来构建一个在训练集上达到100%准确率的树。但这通常会导致过拟合——模型只是记住了训练数据,而无法很好地泛化到新数据。
决策树在偏差和方差之间存在紧密的权衡:
- 树深度较浅:模型简单,可能无法很好地拟合训练数据,导致高偏差。
- 树深度很深:模型复杂,能完美拟合训练数据,但对训练数据中的噪声敏感,导致高方差(过拟合)。
我们的目标是找到一个足够小但又能很好拟合训练数据的树。然而,寻找最优规模决策树是一个NP难问题。幸运的是,存在许多有效的启发式算法来构建表现良好的树。
请注意:单个决策树通常不是最强的机器学习算法。但是,当我们后续使用装袋法来降低方差,或使用提升法来降低偏差时,基于决策树的集成模型(如随机森林、梯度提升树)会变得非常强大,被广泛应用于工业界。

如何构建决策树:不纯度函数
与KD树旨在*衡分割不同,决策树的目标是生成“纯净”的叶子节点,即节点内所有数据点尽可能属于同一类别。
为此,我们需要一个不纯度函数来衡量一个数据子集的“不纯度”。我们希望不纯度越低越好。
以下是两种常见的不纯度函数:
1. 基尼不纯度
对于一个包含 N 个数据点的集合 S,假设有 K 个不同的类别标签。我们定义类别 k 的概率 P_k 为:
P_k = |S_k| / |S|
其中 S_k 是 S 中标签为 k 的子集。
基尼不纯度定义为:
Gini(S) = Σ_{k=1}^{K} P_k * (1 - P_k)
直观理解:从集合中随机抽取两个样本,它们属于不同类别的概率。对于二分类问题,Gini(S) = 2 * p * (1-p),其中 p 是一个类别的概率。当 p=0 或 p=1(纯净)时,基尼不纯度为0;当 p=0.5(最不纯)时,基尼不纯度最大。
2. 信息熵

熵来源于信息论,是更常用的不纯度度量。一个集合 S 的熵定义为:
H(S) = - Σ_{k=1}^{K} P_k * log₂(P_k)


熵衡量了从该分布中随机抽取一个样本时所携带的“信息量”或“不确定性”。当所有类别等概率出现(P_k = 1/K)时,不确定性最高,熵最大。当只有一个类别(P_k=1,其余为0)时,不确定性为0,熵最小(为0)。因此,构建决策树的过程可以看作是一个最小化熵(创造秩序)的过程。

熵与KL散度的关系:最小化熵等价于最大化当前分布 P 与最糟糕的均匀分布 Q (其中 Q_k = 1/K) 之间的KL散度。KL散度衡量了两个概率分布之间的差异。
决策树算法:贪婪分裂
现在我们知道如何评估一个叶子节点的好坏(用熵或不纯度)。那么如何评估一次分裂的好坏呢?
假设我们将数据集 S 通过某个特征和阈值分裂为左子集 S_L 和右子集 S_R。这次分裂后的总体不纯度是左右子集不纯度的加权*均:
Impurity(Split) = (|S_L|/|S|) * Impurity(S_L) + (|S_R|/|S|) * Impurity(S_R)
一次好的分裂应该使 Impurity(Split) 比分裂前的 Impurity(S) 降低得尽可能多。这个降低的量有时被称为“信息增益”。

贪婪分裂算法:
由于寻找全局最优树是NP难的,我们采用贪婪策略:
- 从根节点(包含所有训练数据)开始。
- 对于每一个特征,对于该特征上所有可能的分裂阈值(通常取相邻数据点特征值的中点):
- 计算如果在此处分裂,会得到的不纯度
Impurity(Split)。
- 计算如果在此处分裂,会得到的不纯度
- 选择所有特征和阈值组合中,能产生最低不纯度(或最高信息增益)的那个分裂点。
- 在生成的两个子节点上,递归地重复步骤2-3,直到满足停止条件(例如,节点不纯度已为0、节点内数据点少于某个阈值、树达到最大深度等)。

这个算法的时间复杂度对于每个节点大约是 O(n * d * k),其中 n 是节点内样本数,d 是特征数,k 是类别数,在实践中是可行的。


关于分裂的说明:
- 决策树通常进行轴*行分割(即判断
特征_i > 阈值吗?)。虽然也可以进行斜分割,但轴*行分割计算高效且在实践中通常表现良好。 - 上述讨论主要针对分类问题。对于回归问题,目标变量是连续的。此时,我们不使用熵或基尼不纯度,而是使用衡量预测值(如节点内目标值的均值)与真实值之间差异的损失函数,例如均方误差。分裂的目标是使左右子节点的加权均方误差之和最小化。
演示与偏差-方差权衡
通过可视化工具,我们可以直观看到决策树如何分割空间以及深度对模型的影响。
- 对于简单可分的数据,浅层树就能很好地工作。
- 对于复杂或对角线分布的数据,决策树需要更多分裂,可能产生不规则的决策边界,不如SVM等模型的边界*滑。
- 在一个从两个高斯分布生成的数据集上演示表明:
- 当树很浅时,训练误差和测试误差都较高且接*,这是高偏差(欠拟合)的典型表现。
- 随着树深度增加,训练误差持续下降直至为0,但测试误差先下降后上升。测试误差开始上升的点就是过拟合的开始,此时模型方差很高。
- 决策树的“甜蜜点”(最优深度区间)往往很窄,很难精确把握。这凸显了后续使用剪枝、装袋或提升等技术来控制过拟合的重要性。

本节课中我们一起学习了决策树的基本原理。我们了解了决策树如何从最*邻搜索中演化而来,学习了使用熵和基尼不纯度来衡量节点纯度,并掌握了通过贪婪算法构建决策树的过程。最后,我们通过演示观察了决策树深度与其偏差-方差特性之间的关系,认识到单一决策树的局限性,为后续学习更强大的集成方法(装袋法与提升法)奠定了基础。
机器学习:第30讲:Bagging 🎒








在本节课中,我们将要学习一种名为 Bagging 的强大技术,它可以帮助我们解决机器学习模型中的高方差问题。我们将从回顾决策树开始,理解其局限性,然后深入探讨Bagging的原理、实现方式以及它为何如此有效。








回顾决策树 🌳
上一节我们介绍了决策树。我们从一个数据集出发,这个数据集可能包含不同的类别。我们最初使用KD树来加速最*邻搜索,但后来意识到,如果构建的KD树叶子节点都是“纯”的(即只包含一个类别的数据),那么我们甚至不需要进行最*邻搜索,可以直接返回该叶子节点的标签。
决策树本质上与KD树类似,总是沿着一个维度进行分割,但使用了不同的分割标准。对于KD树,我们依次查看每个维度,并选择中位数进行分割,将数据集精确地分成两半。这很简单,因为只需找到该维度上的特征值中位数即可。
然而,对于决策树,情况则不同。我们希望找到一个分割点,使得分割后的两个子集尽可能“纯”。这里的“纯”意味着子集中的数据点尽可能属于同一类别。决策树的分割不要求子集大小完全*衡。
那么如何找到最佳分割点呢?一个简单的方法是:尝试所有可能的分割。具体来说,对于每个维度,我们考虑数据点在该维度上投影值之间的每一个可能的分割点。如果有 D 个维度和 n 个数据点,那么大约有 D * n 个分割点需要评估。
为了评估一个分割点的好坏,我们需要一个不纯度函数。上节课我们介绍了两种:基尼指数和熵。

- 基尼指数:
Gini = Σ_k p_k (1 - p_k) - 熵:
Entropy = - Σ_k p_k log(p_k)
其中,p_k 是某个子集中属于第 k 类的数据点的比例。
对于一个将集合 S 分割为左子集 S_left 和右子集 S_right 的分割,其不纯度计算如下:
Impurity(split) = (|S_left|/|S|) * H(S_left) + (|S_right|/|S|) * H(S_right)
其中 H 可以是基尼指数或熵函数。
决策树的复杂度与优化
如果我们朴素地实现决策树,对于每个候选分割点,我们都需要遍历整个数据集来计算左右子集的不纯度。假设有 K 个类别,那么评估一个分割点的复杂度是 O(K * n)。由于我们需要评估 D * n 个分割点,总复杂度将达到 O(D * K * n^2),这对于大型数据集来说非常慢。
然而,有一个巧妙的优化方法:当我们按顺序评估一个维度上的连续分割点时,每次移动分割点,通常只有一个数据点从一个子集移动到另一个子集。因此,我们可以维护左右子集中每个类别的计数器,并在移动分割点时仅更新受影响的计数器。这样,评估一个分割点的复杂度可以降低到 O(K),使得总复杂度变为 O(D * K * n),算法效率大大提高。
决策树用于回归问题
决策树不仅可以用于分类,也可以用于回归,此时称为回归树。其算法流程基本相同,唯一改变的是不纯度函数。对于回归问题,我们通常使用均方误差作为不纯度度量。
对于一个集合 S,其不纯度(损失)定义为:
L(S) = (1/2) * Σ_{(x,y)∈S} (y - μ)^2
其中 μ 是集合 S 中所有标签 y 的均值。这实际上就是集合 S 中标签的方差。

在回归树中,我们通过不断分割来*似目标函数。每个叶子节点预测一个常数值(该节点内数据标签的均值),最终得到的预测函数是分段常数函数。

决策树的局限性:偏差-方差权衡
决策树面临的主要问题是偏差-方差权衡。我们可以通过限制树的深度(或叶子节点数量)来进行正则化,防止过拟合。
- 训练误差:随着树深度增加,训练误差会持续下降,最终趋于零(除非存在无法分割的相同点)。
- 测试误差:随着深度增加,测试误差先下降后上升,呈现U形曲线。
问题在于,树的深度是一个整数参数,我们只能在离散的深度值(如3、4、5)之间选择,很难精细地找到偏差和方差之间的最佳*衡点。这导致决策树单独使用时,性能往往不稳定。
引入Bagging:降低方差的神奇方法 🛡️
决策树,特别是深度很大的树,通常存在高方差问题。这意味着训练数据的微小变化会导致学到的模型发生很大变化。Bagging(Bootstrap Aggregating的缩写)正是为了解决此类高方差问题而设计的通用技术。
Bagging的核心思想非常直观:如果我们能训练多个模型并对它们的预测进行*均,那么整体模型的方差就会降低。
Bagging的工作原理
- 创建多个数据集:我们只有一个原始数据集
D。Bagging通过自助采样法从D中生成M个新的训练数据集D_1, D_2, ..., D_M。- 自助采样:每次从原始数据集
D中有放回地随机抽取一个样本,重复n次(n是D的大小),形成一个新数据集D_i。由于是有放回抽样,D_i中可能包含重复样本,也可能缺失D中的某些样本。
- 自助采样:每次从原始数据集
- 训练多个模型:在每个生成的数据集
D_i上,独立地训练一个基学习器(例如决策树),得到模型h_1, h_2, ..., h_M。 - 聚合预测:
- 分类问题:采用投票法,即最终的预测结果是
M个模型预测中出现次数最多的类别。 - 回归问题:采用*均法,即最终的预测结果是
M个模型预测值的算术*均。
- 分类问题:采用投票法,即最终的预测结果是
最终模型 H 可以表示为:
H(x) = (1/M) * Σ_{i=1}^{M} h_i(x)
为什么Bagging有效?
回顾偏差-方差分解,模型的期望误差可以分解为:
Error = Noise + Bias^2 + Variance
其中,方差衡量了模型对于训练数据变化的敏感度。对于高方差的模型(如深度决策树),Variance 项很大。
Bagging通过*均多个模型来降低方差。从理论上讲,如果这些基模型 h_i 是独立同分布的,那么随着模型数量 M 的增加,聚合模型 H 的方差会减小。虽然自助采样产生的数据集并非完全独立,但实践证明,这种*均操作能显著降低整体模型的方差,而对偏差的影响很小。
Bagging的优势
- 通用性:Bagging是一种元算法,可以应用于任何高方差的机器学习模型(不仅仅是决策树)。
- 并行化:由于每个基模型是独立训练的,因此Bagging非常适合并行计算。
- 效果显著:它通常能显著提升不稳定模型(如决策树)的预测准确性和鲁棒性。


总结 📚
本节课我们一起学习了以下内容:

- 回顾了决策树,包括其构建过程、不纯度函数(基尼指数、熵)、用于回归的均方误差损失,以及其存在的高方差和偏差-方差权衡难的问题。
- 引入了Bagging技术,它是一种通过自助采样构建多个训练集,并训练多个模型进行聚合(投票或*均)来降低模型方差的有效方法。
- 理解了Bagging为何有效:它主要针对并减少了模型误差中的方差部分,从而提升了整体模型的稳定性和泛化能力,尤其适用于像决策树这样不稳定的学习器。

Bagging是构建强大集成模型(如随机森林)的基础。下一讲,我们将探讨另一种强大的集成方法——Boosting,它主要侧重于降低模型的偏差。
机器学习:第31讲:随机森林与装袋法 🌲


在本节课中,我们将学习两种强大的集成学习方法:装袋法(Bagging)和随机森林(Random Forests)。我们将了解它们如何通过组合多个模型来提升预测性能,特别是如何降低方差和估计不确定性。
课程公告与回顾

上一讲我们介绍了装袋法。这是一种非常有效的降低分类器方差的方法。

我们特别在决策树的背景下使用它,因为如果让决策树完全生长,它会成为一个方差非常高的分类器。
装袋法的核心思想很简单。你的数据来自某个分布 P,但你不知道这个分布,你只有这个有限的数据集 D。
如果你训练的分类器方差很高,这意味着它在某种程度上过度拟合了这个特定的数据集 D,捕捉了数据中并非普遍存在于真实分布 P 中的特性。
那么如何解决这个问题呢?装袋法做了以下事情。
你从这个有 n 个数据点的数据集 D 中,抽取多个数据集:D₁, D₂, ..., Dₘ。
每个数据集的大小都与原始数据集相同,并且是有放回地、均匀随机抽取的。
有放回抽样的区别在于,你每次抽取一个点,但同一个点可能被多次选中。每个点都是从数据集中独立抽取的。
然后,你从每一个抽取出的数据集中学习一个分类器 h。
你训练所有这些分类器,然后你的最终分类器就是所有这些分类器的*均值。
所以你的最终分类器 H 就是:
H(x) = (1/m) * Σⱼ hⱼ(x)
基本思想是,假设你过度拟合了数据集中某些特定的“怪癖”,那么这些怪癖在不同的数据集中会各不相同,最终在*均过程中被抵消掉。
当然,这会增加你的训练和测试时间,但你可以通过并行计算来解决。现代硬件使得并行计算变得非常廉价。
测试确实会变慢,测试时间大约是原来的 m 倍。但你获得了另一个优势:你现在可以得到校准良好的概率估计。
你可以查看每个分类器的预测,统计有多少分类器预测了某个特定标签,这基本上告诉了你对这个预测的置信度。
装袋法非常强大。随机森林是装袋法的一个著名实例,也是一个非常出色的算法。
随机森林算法 🌳
随机森林算法非常简单。它基本上就是对决策树进行装袋,但有一个很小的修改。
以下是具体步骤。
你抽取不同的数据集 D₁ 到 Dₘ。
现在,对于每一个数据集,你学习一棵完整的决策树(一直分裂直到训练误差为零,或者直到无法再分裂)。
你对装袋法非常有信心,相信它能拯救你,所以你甚至“更疯狂”一点。
你对决策树算法做一个小修改:每当你要进行一次分裂时,在当前决策树会尝试所有 D 个维度和每个维度上所有可能分裂的基础上,在随机森林中,你改为:随机子采样 K 个维度,并将搜索限制在这 K 个维度内。
基本上,你构建一棵树。你取数据集,比如 D₃,然后你将其大致分成两半,这是你树的第一个节点。对于这次分裂,你基于某个特定特征 f 和某个特定阈值 t 进行分裂。
如果 x_f > t,则向右走,否则向左走。在这里,我只考虑 K 个维度,其中 K < D。
我这样做的原因是为了确保这些分类器都非常不同。它们将在非常不同的维度上进行分裂。
试想一下,因为它们如此不同,它们在测试时就会犯非常不同的错误。现在,如果你对它们取*均,这些错误就会相互抵消。
这是一个极其有效的算法。随机森林是我最喜欢的算法之一。
伪代码在关于随机森林的笔记中。但重要的是,对于每一次分裂,你都重新采样 K 个特征。不是为每个函数采样,而是每次分裂时都采样。
所以在这里,你随机挑选 K 个特征并在其上寻找最佳分裂。然后在这里,你再随机挑选 K 个特征并寻找最佳分裂。
一个关键问题是:如何设置 K?现在我们有了一个额外的超参数。
事实证明,有一个非常好的经验法则:将 K 设置为 √D(向上取整)。这在实践中效果非常好。

人们已经分析过这一点,并且有理论依据说明为什么它如此有效。但就所有实际目的而言,你几乎可以认为它不是一个超参数。
随机森林的优势 ✨
我喜欢随机森林的原因有很多。首先,它是少数几个可以“开箱即用”的算法之一。
当实践者带着一个数据集来找我时,他们通常有各种不同单位和尺度的特征向量。对于大多数机器学习算法,你必须确保这些特征被仔细地预处理和缩放。
对于随机森林,你不需要做任何这些,因为你只是在进行分裂。特征的尺度根本无关紧要。
其次,它的超参数很少。K 被设置为 √D,M(树的数量)则尽可能设大。没有“太大”的说法,你一直训练直到觉得够了为止。通常 M 是100或几千。
所以这是一个非常容易使用的算法,而且效果出奇地好。
我的经验法则是:它几乎总是第二好的算法。如果你花大量时间和精力去调整另一个针对特定问题假设的算法,你通常可以做得更好,但这需要很多“精心呵护”。
袋外误差估计 📊

装袋算法还有一个杀手级优势,叫做袋外误差估计。

以前我们做模型选择时,会把数据分成训练集和验证集。为了知道误差,你在80%的数据上训练算法,然后在20%的数据上评估。这告诉你在测试数据集上可能表现如何。
这种方法的缺点是你只能在80%的数据上训练。
对于随机森林(或任何装袋分类器),你不需要这样做。你可以在训练数据集上直接估计测试误差。这听起来很疯狂,但确实可以做到。
方法如下:因为你有很多不同的数据集,它们都各不相同。
对于每一个训练数据点,你都有许多不同的分类器 hⱼ(x),每个都在不同的数据集 Dⱼ 上训练。
对于每个训练点 (xᵢ, yᵢ),你可以估计误差。误差就是损失的*均值。
关键点在于:有些分类器在训练时没有包含数据点 xᵢ。


因为有放回抽样,*均而言,每个自助采样集大约包含原始数据集中63%的独特样本,另外37%是重复样本。这意味着对于每个数据点,大约有37%的树在训练时没有用到它。
所以,对于我的数据点 A,我只计算那些在训练数据集中不包含 A 的分类器上的误差。
因此,数据点 A 在那些树中实际上是隐式的验证数据。如果你的 M 足够大,即使你移除了少数分类器也没关系。
我可以将其形式化一点。我的袋外误差定义如下:
OOB_Error = (1/n) * Σᵢ [ (1/|Zᵢ|) * Σ_{j: (xᵢ, yᵢ) ∉ Dⱼ} L( hⱼ(xᵢ), yᵢ ) ]
其中,Zᵢ 是那些没有在 xᵢ 上训练的分类器集合的大小,这只是一个归一化因子。

这非常强大,因为你可以在所有数据上训练你的分类器,并且免费获得一个关于分类器在测试集上表现的无偏估计。你不需要小心处理训练-验证集的划分。
随机森林的局限性与应用场景

那么,有没有随机森林不擅长的数据呢?例如,在计算机视觉中,图像像素具有特定的空间结构和相关性。随机森林并不真正考虑这一点,它独立对待每个维度。因此,它可能永远无法像那些考虑图像特定结构的算法那样好。
当然,对于结构化数据等,情况也更复杂。
对于回归问题呢?完全没有问题。你只需要使用回归树。随机森林对于回归的另一个好处是它能给出不确定性估计,这是你通常从核化回归中得不到的,你需要使用高斯过程才能获得。
在回归中,你仍然会将叶子节点分裂直到每个叶子只有一个点吗?实际上,你会在某个点停止。这是一个你可以引入的超参数。
实际上,有一件事可以改进随机森林:对于每棵树,你可以在构建完整棵树后,从底部开始剪枝。你看最后一个分裂,检查这个分裂是否能改善袋外误差(使用那些未包含在训练集中的数据点)。如果不能,就移除它。这有助于减少纯噪声分裂。


偏差-方差分解演示 📉
我想展示一个关于偏差-方差的演示,现在可以用随机森林来做。
在X轴上,你看到的是集成大小,即我*均的树的数量。
这里有几件有趣的事情。当我增加*均的树的数量时,你首先注意到偏差非常低。如果我只有一棵树,那就是标准的决策树。



在这个例子中,我没有做随机特征选择,因为这是一个二维数据集,√2 约等于1.4,向上取整又是2。
如果你只看一棵决策树,偏差基本上为0,但方差非常高。黑线代表方差,绿线代表噪声。这是一个相当嘈杂的数据集,和你们项目里的一样,是两个有重叠的高斯分布。
这条线是整个模型的误差,基本上是偏差+方差+噪声,这与理论完全一致。
美妙之处在于,随着集成规模的增加,你可以非常清楚地看到方差急剧下降。这里我们有10%的方差,它下降了很多,降到4%,并且持续下降。但你也看到了收益递减,所以这是我的 M。随着 M 增加,我的方差持续下降,最终基本达到*稳。
装袋法的神奇之处在于它降低了方差,但没有增加偏差。偏差项完全不受影响。
这很容易证明:偏差不是你的分类器 h 的函数,而是*均分类器的函数,而*均分类器在这种情况下不受影响。
所以偏差保持恒定,但方差下降得很漂亮。这里的波动只是因为样本量小。
这个演示很好地展示了随机森林的强大能力。请记住装袋法和随机森林。

从装袋法到提升法 ⚡
装袋法已经非常棒了,但还有更棒的东西:提升法。我们今天开始介绍提升法。
提升法和装袋法非常相关。两者都是分类器的集成。
在装袋法中,我们说 H(x) = (1/m) * Σⱼ hⱼ(x)。
在提升法中,你做类似的事情:H(x) = Σⱼ αⱼ * hⱼ(x)。你也是*均许多分类器,但带有一个权重 α。


但提升法走的是另一条路。提升法说:如果我们有一个偏差非常高的简单分类器(弱学习器)会怎样?装袋法处理的是低偏差、高方差的情况,我们通过*均来消除方差。

现在,我们做点别的。我们在想:如果我们真的有很高的偏差,我们如何摆脱偏差?事实证明,可以使用非常类似的方法。


这始于一个著名的问题。1988年,Michael Kearns(学习理论之父之一)提出了一个非常有趣的问题:如果你有弱学习器(类似于高偏差学习器,即永远无法达到零训练误差的分类器),我们能否组合多个弱学习器,形成一个强学习器?能否从多个如此糟糕的分类器中构建出一个超级分类器,使其实际上可以在任何数据集上达到零训练误差?


这就是强学习器的概念。当时的问题是:哪些分类器可以给你零训练误差,哪些不能?这是一个开放性问题。
几年后,Robert Schapire(当时是博士后)给出了著名的答案和证明。证明表明,是的,你总是可以将糟糕的分类器组合成一个非常强的分类器。他是一位纯粹的理论家,当时并没有过多地将其视为算法。
但几年后,他意识到这实际上可以变成一个算法。他发表了一篇名为“AdaBoost”的论文。这是一个巨大的成功。论文基本上说:如果你们任何人有一个糟糕的分类器,我有一个方法可以让它变得非常出色。每个人都想:是的,我正好有一个糟糕的分类器。

它变得非常流行,每个人都开始使用提升法。它具有惊人的理论保证,我们将在接下来的两三讲中介绍。这些保证表明,不仅通过提升,你最终总能达到零训练误差(无论你的分类器多差),而且你可以在非常少的步骤内(步骤数与训练数据量成对数关系)达到零训练误差。这太神奇了。
这是一个极其实用的算法。你可以将任何不太成熟的想法,通过提升,变成一个惊人的算法。



提升法的基本框架
我来建立整体框架,下一讲我们会更深入地探讨。
设 H 是我正在集成的分类器。H 基本上是许多分类器的加权和。这些都是高偏差分类器,不是很好,但我想把它们组合成一个非常强大的“弗兰肯斯坦”分类器。

我们需要一个损失函数来告诉我们一个分类器表现如何。我们可以使用之前见过的任何损失函数,例如指数损失、*方损失,这并不重要。
让我把损失函数写得稍微不同一点。设损失函数为 L(H),这是一种简写。它的意思是:
L(H) = (1/n) * Σᵢ L( H(xᵢ), yᵢ )
基本上,我遍历所有训练数据点,查看预测值和真实标签,计算损失并取*均。损失函数可以是*方损失、指数损失或你喜欢的任何损失函数,比如铰链损失。


核心思想是:这个 H 是分类器的和。

想象我已经进行了几次迭代。我想知道应该添加哪个分类器。所以如果我从 M 到 M+1,我应该添加哪个分类器?最初,你可能只有一个预测所有结果都为0的零分类器。

给定我已经有了一些分类器,我应该添加哪个分类器?我可以将其表述为以下问题:
我应该从我的那组糟糕的高偏差分类器(我的弱学习器集合)中添加哪个小函数 h 到我的 H 中,以便最小化我的损失?我应该添加哪个函数,以最小化以下函数:
L( H + α * h )
这基本上就是:我的分类器集合,如果我向其中添加一个额外的分类器,这就是我感兴趣的。我试图想出一种机制,告诉我当你有一组分类器时,应该向其中添加哪一个。
一旦我有了这个机制,我就可以从任何分类器开始,比如一个随机的,然后我只需不断使用该机制向其添加分类器,从而最小化我的损失。这就是我要解决的问题。
目前,我们暂时不讨论如何最优地选择 α。我们假设 α 是一个小常数。我们下次课会深入探讨。
总结
本节课中,我们一起学习了:
- 装袋法:通过有放回抽样创建多个数据集,训练多个模型并取*均,以有效降低模型方差。
- 随机森林:基于决策树的装袋法,并在每次分裂时随机选择特征子集,进一步增加模型多样性,是强大且易于使用的“开箱即用”算法。
- 袋外误差估计:随机森林等装袋方法提供的一种无需单独验证集即可估计测试误差的强大技术。
- 从装袋法到提升法:引入了提升法的核心思想——通过组合多个“弱学习器”(高偏差模型)来构建一个“强学习器”,并概述了其基本优化框架。

下一讲,我们将深入探讨提升法的具体算法(如AdaBoost)及其工作原理。请保持思维活跃,我们下次继续。
机器学习:032:Boosting



在本节课中,我们将要学习Boosting(提升)方法。这是一种将多个性能较弱的“弱学习器”组合起来,形成一个强大预测模型的技术。我们将从直观理解开始,然后探讨其数学形式,并介绍两种著名的Boosting算法:AdaBoost和梯度提升树。


从Bagging到Boosting
上一节我们介绍了Bagging,它通过组合多个高方差、低偏差的模型来降低整体方差。本节中我们来看看Boosting,它要解决的是相反的问题:偏差问题。
Boosting起源于20世纪80年代末的一个核心问题:能否将多个“弱学习器”(即性能仅略优于随机猜测的学习算法)高效地组合起来,达到“强学习器”(能将训练误差降至0)的效果?Robert Schapire从理论上证明了这是可能的,并提出了实现它的算法。

Boosting的直观理解
Boosting的核心思想是在函数空间中进行梯度下降。我们可以通过一个几何类比来理解它。
想象一个N维空间,每个坐标轴对应一个训练样本的真实标签。那么,整个训练集的标签向量 y 就是这个空间中的一个点。同样,任何分类器 H 在训练集上的预测结果也可以表示为此空间中的一个点 H(x)。
- 强学习器(如深度决策树)的预测点
H(x)会与真实标签点y重合。 - 弱学习器(如浅层决策树)的预测点
H(x)则会偏离y。
Boosting的目标是:从一个初始点(例如全零预测)开始,通过逐步添加弱学习器的预测,使最终组合模型的预测点不断逼*真实标签点 y。这就像一个醉汉回家:每一步方向都不太准(弱学习器),但通过不断朝着大致正确的方向迈出小步(以较小权重 α 添加弱学习器),最终总能到达目的地。

这个过程的关键在于,每个弱学习器只需要保证其预测方向与当前“残差”(即从当前预测点到真实标签点 y 的方向)的夹角小于90度。如果方向完全错误(夹角大于90度),我们只需将其预测结果取反即可。只有当弱学习器的预测方向与残差方向完全正交时,算法才会停止进步。
Boosting的形式化:AnyBoost
基于梯度下降的视角,我们可以推导出Boosting的一般形式,称为AnyBoost。
我们的目标是构建一个集成模型:
H(x) = Σ_{t=1}^{T} α_t * h_t(x)
其中每个 h_t(x) 是一个弱学习器,α_t 是其权重。
在每一步 t,我们已经有了前 t-1 步累积的模型 H_{t-1}。我们希望找到一个新的弱学习器 h_t,使得添加它后,损失函数 L 下降最快。这等价于求解:
h_t = argmin_{h ∈ ℋ} Σ_{i=1}^{N} [∇L(H_{t-1}(x_i))] * h(x_i)
其中 ∇L(H_{t-1}(x_i)) 是损失函数在当前模型预测值处的梯度。
对于*方损失函数 L(y, H(x)) = 1/2 (y - H(x))^2,其梯度简化为残差:
∇L(H(x_i)) = H(x_i) - y_i
因此,寻找 h_t 就变成了寻找一个与当前残差向量(真实值减去当前预测值)负内积最小(即方向最一致)的弱学习器。



以下是AnyBoost算法的步骤:


- 初始化模型
H_0(x) = 0。 - 对于
t = 1到T:- 对每个训练样本
i,计算负梯度(对于*方损失,即残差r_i = y_i - H_{t-1}(x_i))。 - 训练一个弱学习器
h_t,使其预测h_t(x_i)尽可能与r_i相关(即最小化Σ r_i * h_t(x_i),或等价地,用r_i作为伪标签来拟合h_t)。 - 选择步长
α_t(可以固定为一个小常数,或通过线搜索确定)。 - 更新模型:
H_t(x) = H_{t-1}(x) + α_t * h_t(x)。
- 对每个训练样本
- 输出最终模型
H_T(x)。
著名的Boosting算法





基于AnyBoost框架,有两个特别重要且广泛应用的变种。


梯度提升树(Gradient Boosted Trees)




梯度提升树是当今最强大的机器学习算法之一,被广泛应用于搜索引擎排名、推荐系统等领域。

它做出了以下具体选择:
- 弱学习器
h_t:使用深度受限(例如4-6层)的决策树(CART树)。这种树训练和预测速度快,对数据尺度不敏感,但偏差较高。 - 损失函数:通常使用*方损失(用于回归)或对数损失(用于分类)。
- 拟合目标:在每一步,我们让决策树去拟合当前模型的负梯度(即残差)。有趣的是,对于*方损失,这等价于让决策树直接以残差
r_i为标签,去最小化*方误差。因此,我们可以直接使用标准的回归树算法,无需修改。
梯度提升树的伪代码极其简洁:
1. 初始化 H(x) = 0
2. For t = 1 to T:
a. 计算残差: r_i = y_i - H(x_i), for all i
b. 用数据 {(x_i, r_i)} 训练一棵回归树 h_t
c. 更新模型: H(x) = H(x) + α * h_t(x)
3. 输出 H(x)
其主要超参数是树的深度和步长 α。树越深,单步拟合能力越强,但也可能引入更多方差;步长越小,需要的迭代次数 T 越多,但过程更稳定。
AdaBoost
AdaBoost(自适应提升)是历史上第一个成功且实用的Boosting算法,比梯度下降视角的提出早了约十年。它是AnyBoost框架在特定损失函数(指数损失)下的特例。
AdaBoost专为分类问题设计,其核心思想是:
- 样本权重:在每一轮迭代中,它会增加上一轮被错误分类样本的权重,使得弱学习器在后续轮次中更关注这些“难”样本。
- 弱学习器权重
α_t:它会为每个弱学习器计算一个权重,该权重基于其分类准确率。准确率越高的弱学习器,在最终模型中的话语权越大。

虽然其原始推导与梯度下降视角不同,但最终都归结为以自适应(Adaptive)的方式确定弱学习器及其权重 α_t,这也是其名称的由来。

总结
本节课中我们一起学习了Boosting方法。
- 我们首先理解了Boosting要解决的是模型的偏差问题,其目标是将多个弱学习器组合成强学习器。
- 我们通过一个几何类比,将Boosting直观地理解为在函数空间中进行梯度下降,通过不断朝正确方向迈出小步来逼*最优解。
- 我们形式化地推导了Boosting的一般框架AnyBoost,其核心是在每一步寻找与当前损失函数梯度最对齐的弱学习器。
- 我们介绍了两个最重要的Boosting算法:梯度提升树(通过拟合残差来迭代提升回归树)和AdaBoost(通过调整样本权重和分类器权重来提升分类性能)。
Boosting,特别是梯度提升树,因其强大的预测能力和相对简单的实现,已成为现代机器学习工具箱中不可或缺的组成部分。
机器学习:033:AdaBoost算法详解 🚀


在本节课中,我们将深入学习AdaBoost算法。AdaBoost是Boosting家族中最著名、最早的算法之一,它通过组合多个弱分类器来构建一个强大的分类器。我们将从梯度提升的基本思想出发,逐步推导出AdaBoost的具体形式,并理解其核心机制。







回顾:梯度提升的基本思想

上一节我们介绍了梯度提升。其核心思想是,我们的最终分类器 H(x) 是多个弱分类器 h_t(x) 的加权和:
H(x) = Σ_{t=1}^{T} α_t * h_t(x)
每个弱分类器 h_t(x) 虽然“弱”(即仅比随机猜测略好),但能指出正确的改进方向。梯度提升的过程可以形象地理解为:我们从一个初始预测(例如全零向量)开始,目标是最小化损失函数 L。在每一步,我们计算损失函数在当前预测处的梯度,然后训练一个新的弱分类器,使其预测方向尽可能与负梯度方向一致。接着,我们沿着这个弱分类器指示的方向,以一个步长 α 更新我们的预测。通过不断重复这个过程,我们逐步逼*最优解。

AdaBoost:自适应提升

今天,我们将聚焦于最著名的Boosting算法——AdaBoost(自适应提升)。从历史角度看,AdaBoost是先被发明的,后来人们才意识到它实际上是函数空间梯度下降的一个特例。AdaBoost是梯度提升框架下的一种具体实现,它做出了几个关键选择:
- 损失函数:采用指数损失
L = Σ_i e^{-y_i H(x_i)}。 - 步长选择:不再使用固定步长,而是通过线搜索优化每一步的步长
α,即沿着弱分类器指示的方向,找到使损失函数最小的点。 - 问题设定:专用于二分类问题,其中标签
y_i ∈ {-1, +1},且弱分类器也输出-1或+1。


这些选择使得AdaBoost具有一些非常优雅的性质。
AdaBoost的核心推导

我们的目标是找到下一个弱分类器 h(x) 及其权重 α。推导过程围绕最小化指数损失展开。


步骤一:计算梯度与权重


假设当前我们已经有了一个组合分类器 H。为了找到下一个弱分类器,我们需要计算损失函数 L 关于当前预测 H(x_i) 的梯度。对于指数损失,其关于 H(x_i) 的梯度为:

∇L/∂H(x_i) = -y_i * e^{-y_i H(x_i)}

我们记 r_i = -∇L/∂H(x_i)。为了后续推导方便,我们定义权重 w_i:
w_i = e^{-y_i H(x_i)} / Z,其中 Z = Σ_i e^{-y_i H(x_i)} 是归一化因子。
可以验证,所有权重 w_i 之和为1。这些权重 w_i 直观地表示了每个数据点 i 对当前总损失的贡献大小。


步骤二:寻找最佳弱分类器
在梯度提升中,我们希望找到一个弱分类器 h,使其预测方向与负梯度方向(即 r 方向)最一致。这等价于最小化 h 与 r 的内积:
h* = argmin_h Σ_i h(x_i) * r_i

代入 r_i 和 w_i 的定义,并利用 y_i ∈ {-1, +1} 和 h(x_i) ∈ {-1, +1} 的性质,经过一系列代数变换(将求和按分类正确与错误拆分),上述最小化问题可以转化为:
h* = argmin_h Σ_{i: h(x_i) ≠ y_i} w_i
结论:在AdaBoost的每一步,我们需要寻找的弱分类器 h,是那个能在当前权重分布 w_i 下,最小化加权分类错误率的模型。加权错误率 ε 定义为被 h 分类错误的样本的权重之和。

步骤三:确定弱分类器的权重(步长α)

找到弱分类器 h 后,我们需要确定其权重 α。这通过线搜索完成,即求解:



α* = argmin_α L(H + αh) = argmin_α Σ_i e^{-y_i (H(x_i) + α h(x_i))}
令人惊奇的是,对于指数损失和二分类设定,这个优化问题有闭式解:
α* = 1/2 * ln((1 - ε) / ε)
其中 ε 是上一步中弱分类器 h 的加权错误率。这个公式非常直观:分类器越准确(ε越小),其权重 α 就越大,在最终模型中的话语权也越高。
AdaBoost的工作流程与直观理解
结合以上推导,AdaBoost的算法流程可以直观理解如下:
- 初始化:所有训练样本的权重
w_i相等。 - 循环迭代:
- 基于当前的样本权重分布,训练一个弱分类器
h_t,目标是最小化加权错误率ε_t。 - 计算该弱分类器的权重
α_t = 1/2 * ln((1 - ε_t) / ε_t)。 - 更新样本权重:增加被
h_t分类错误样本的权重,减少分类正确样本的权重。更新公式为w_i ← w_i * e^{-α_t y_i h_t(x_i)},然后重新归一化。这使得算法在后续迭代中更关注那些难以分类的样本。 - 将加权后的弱分类器加入整体模型:
H(x) ← H(x) + α_t h_t(x)。
- 基于当前的样本权重分布,训练一个弱分类器
- 输出最终模型:
H(x) = sign(Σ_t α_t h_t(x))。
直观比喻:AdaBoost像一个学习小组。每次讨论(迭代)后,大家会把还没搞懂的问题(错误样本)标记为重点(增加权重),下次讨论时就集中火力解决这些难题。每个组员(弱分类器)的能力不同,贡献的分数(α)也不同。通过多次这样的聚焦讨论,小组最终能攻克所有难题。
AdaBoost的特性与讨论

- 抵抗过拟合:与许多模型不同,AdaBoost即使在训练误差达到0后继续迭代,测试误差也常常上升得非常缓慢。这是因为随着迭代进行,弱分类器的权重
α_t会变得越来越小,后续迭代对模型的改动幅度微乎其微,相当于内置了正则化效果。 - 弱点:AdaBoost对噪声数据和异常值非常敏感。因为它会持续给分类错误的样本增加权重,一个错误的标签可能会导致算法过度关注该样本,从而影响整体性能。
- 与强大基学习器的关系:像SVM这样本身就很强的学习器,从Boosting中获益可能有限,因为Boosting主要解决的是偏差(Bias) 问题。而决策树等简单模型作为基学习器,与Boosting结合能产生非常好的效果(如梯度提升树GBDT)。



总结
本节课我们一起深入学习了AdaBoost算法。
- 我们从梯度提升的通用框架出发,理解了Boosting通过逐步添加弱分类器来优化整体模型的思想。
- 我们看到了AdaBoost如何通过选择指数损失函数、线搜索确定步长以及专用于二分类,成为梯度提升的一个特例。
- 通过推导,我们揭示了AdaBoost每一步的核心任务:寻找最小化加权错误率的弱分类器,并为其赋予一个与准确率相关的权重
α = 1/2 * ln((1-ε)/ε)。 - 我们探讨了AdaBoost通过动态调整样本权重来聚焦难例的工作机制,并分析了其抵抗过拟合的特性以及对噪声敏感的弱点。

AdaBoost以其简单、有效且理论优美的特点,在机器学习历史上占有重要地位,并且是理解现代集成学习方法的基础。
机器学习:034:Boosting与Adaboost


在本节课中,我们将深入学习Boosting算法,特别是Adaboost。我们将探讨其工作原理、算法步骤、优势与局限性,并理解其为何能快速收敛。

课程概述与通知
首先,我们来看一些课程相关的通知。
日历竞赛目前进展顺利,部分团队在测试集上取得了100%的准确率。这有些出乎意料,请大家在提交时注意竞赛规则。

新的作业项目已经发布。项目7涉及实现CART树、Bagging和Boosting(特别是Adaboost)。该项目有一定挑战性,但基于之前作业的数学推导,实现起来应该更直接。完成该项目后,下一个项目会相对简单。

根据期中评估的反馈,许多同学希望学习深度学习相关内容。因此,在完成Boosting的讲解后,我们将开始介绍神经网络与深度学习。
回顾Boosting与Adaboost
上一节我们介绍了Boosting的基本思想,即通过组合多个弱学习器来构建一个强学习器。本节中,我们来看看其中最著名的算法之一:Adaboost。
在Boosting框架中,我们有一个由多个分类器加权求和得到的总分类器 H。在每一轮迭代中,我们在当前分类器 H 的基础上,添加一个新的弱学习器 h,并为其分配一个权重 α。我们的目标是最小化损失函数。
对于Adaboost,我们使用指数损失函数。关键步骤在于,我们不仅沿着弱学习器 h 的方向(*似于损失函数的负梯度方向)前进,还会进行一次线搜索,以找到能最小化损失函数的最优步长 α。
Adaboost的最优步长
通过求解优化问题,我们可以得到一个封闭形式的解,用于计算最优步长 α。公式如下:
α = 0.5 * log((1 - ε) / ε)
其中,ε 是当前弱学习器在加权数据集上的错误率。这个公式非常优美,它意味着我们无需进行繁琐的线搜索,只需根据错误率就能直接计算出最佳步长。




Adaboost算法详解

以下是Adaboost算法的具体步骤。你需要在自己的项目中实现它。
- 初始化权重:对于训练集中的每个样本 i,初始化其权重 w_i = 1/N,其中 N 是样本总数。
- 迭代训练:对于 t = 1 到 T(T为迭代次数),执行以下步骤:
a. 训练弱学习器:使用当前样本权重 w_t 训练一个弱学习器 h_t。该学习器需要在加权数据集上取得比随机猜测(错误率小于0.5)略好的性能。
b. 计算加权错误率:计算弱学习器 h_t 的加权错误率 ε_t。公式为:ε_t = Σ_{i: h_t(x_i) ≠ y_i} w_i。
c. 计算弱学习器权重:根据错误率计算该弱学习器的权重 α_t。公式为:α_t = 0.5 * log((1 - ε_t) / ε_t)。
d. 更新总分类器:将弱学习器及其权重添加到总分类器中:H(x) = H(x) + α_t * h_t(x)。
e. 更新样本权重:根据当前弱学习器的表现更新每个样本的权重。对于每个样本 i,新的权重为:w_i ← w_i * exp(-α_t * y_i * h_t(x_i))。然后对所有权重进行归一化,使其和为1。
权重更新的直观理解
权重更新规则是Adaboost的核心。让我们分析一下:
- 如果样本 i 被正确分类(即 y_i * h_t(x_i) = 1),则其权重乘以 exp(-α_t)。由于 α_t > 0,exp(-α_t) < 1,因此该样本的权重会减小。
- 如果样本 i 被错误分类(即 y_i * h_t(x_i) = -1),则其权重乘以 exp(α_t) > 1,因此该样本的权重会增加。
这意味着,Adaboost会重点关注那些之前被错误分类的“困难”样本,在后续迭代中给它们分配更高的权重,迫使新的弱学习器努力去纠正这些错误。这种机制使得Adaboost能够快速聚焦于决策边界附*的点。

Adaboost的优势与局限
优势:
- 算法简单,易于实现。
- 通常收敛速度很快。
- 在实践中经常能取得非常好的效果。

局限:
- 对噪声数据和异常值非常敏感。一个错误标记的样本可能会获得极高的权重,从而将整个决策边界拉向错误的方向,导致过拟合。


Adaboost的理论保证



Adaboost有一个非常强大的理论性质:它的训练误差会以指数速度下降。



我们可以证明,Adaboost所使用的指数损失函数 L(H) = Σ_i exp(-y_i H(x_i)) 是0-1训练误差 Err(H) = Σ_i I(y_i ≠ sign(H(x_i))) 的一个上界。也就是说,L(H) ≥ Err(H) 始终成立。

进一步推导可以得出,在经过 T 轮迭代后,训练误差的上界满足:
Err(H) ≤ N * (Π_{t=1}^T 2√(ε_t(1-ε_t)) )



由于每个弱学习器的错误率 ε_t < 0.5,因此乘积项 2√(ε_t(1-ε_t)) < 1。这意味着训练误差的上界随着迭代次数 T 呈指数下降。理论上,在经过大约 O(log N) 轮迭代后,训练误差就能降为0。
超越零训练误差
一个常见的问题是:当训练误差已经达到0后,继续运行Adaboost还有意义吗?
答案是肯定的。即使所有样本都被正确分类(sign(H(x_i)) = y_i),继续优化指数损失函数 L(H) 仍然有意义。这相当于在增大分类器 H 对于每个样本的“置信度”或“间隔”(margin)。将样本推离决策边界更远,通常能带来更好的泛化性能。因此,Adaboost在达到零训练误差后继续运行,实际上是在构建一个大间隔分类器。
实践练习与算法对比
为了加深理解,我们提供了一个手算练习。你需要在一个简单的二维数据集上,模拟Adaboost的三轮迭代过程,计算每一轮的弱学习器、错误率 ε_t、权重 α_t 以及更新后的样本权重。通过这个练习,你能清晰地看到权重如何随着分类结果而变化。

最后,我们简要对比了其他算法。有人问及遗传编程(Genetic Programming),它受生物进化启发,通过随机变异和选择来优化函数。然而,与基于梯度信息或概率模型的现代优化方法(如高斯过程)相比,遗传编程通常效率低下且缺乏收敛保证,因此在严肃的机器学习应用中很少被视为首选方法。
迈向深度学习:从核方法到神经网络
在课程的最后,我们为下一讲的内容做了铺垫。许多同学期待的深度学习,其核心思想与我们已经学过的核方法有深刻的联系。
在核方法中,我们通过一个映射函数 Φ(x) 将数据映射到高维特征空间,然后在该空间中学习线性分类器。核函数的巧妙之处在于,我们无需显式计算 Φ(x),只需计算内积 K(x, z) = Φ(x)^T Φ(z)。

神经网络,特别是深度学习,采取了一种不同的策略:它不再使用手工设计的核函数,而是直接学习这个映射函数 Φ(x)。具体来说,在神经网络中,Φ(x) 通常是一系列可学习的仿射变换与非线性的组合。例如,一个简单的单层映射可以是:
Φ(x) = σ(Ax + b)
其中 A 是权重矩阵,b 是偏置向量,σ 是非线性激活函数。


历史上常用Sigmoid函数作为 σ,但现代深度学习更倾向于使用更简单的整流线性单元(ReLU):σ(z) = max(0, z)。ReLU因其在优化中的良好性质而被广泛采用。
如果没有非线性激活函数 σ,那么多层变换最终仍会退化为一个线性变换,模型的表达能力不会增加。因此,非线性激活函数是神经网络获得强大表达力的关键。

在下节课中,我们将深入神经网络的细节,学习如何同时训练权重 A、b 以及最终分类层的权重 W,并观看一些精彩的演示。
本节课总结
在本节课中,我们一起学习了:
- Adaboost算法:详细剖析了其初始化、迭代训练、加权错误率计算、弱学习器权重(步长)计算以及样本权重更新的完整流程。
- 算法核心:理解了Adaboost通过指数级调整样本权重来聚焦于分类错误样本的机制,以及其快速收敛的理论保证(训练误差指数下降)。
- 优缺点:认识了Adaboost对噪声敏感的特点,以及其在达到零训练误差后继续优化以增大间隔的原理。
- 与深度学习的联系:初步了解了神经网络如何通过可学习的非线性映射 Φ(x) 来替代核方法中固定的映射,为理解深度学习奠定了基础。
通过完成相关的编程项目和实践练习,你将能够巩固对这些重要概念的理解。
机器学习:035:神经网络与深度学习




在本节课中,我们将学习神经网络与深度学习的核心概念。我们将回顾神经网络的基本思想,探讨其*年复兴的关键原因,并通过直观的比喻和示例来理解其工作原理。



课程概述

神经网络是一种强大的机器学习模型,其核心思想是通过学习数据的非线性映射,并结合线性分类器来实现复杂任务的分类或回归。*年来,由于整流线性单元(ReLU)、图形处理器(GPU) 和随机梯度下降(SGD) 等技术的应用,深度学习取得了突破性进展。



神经网络回顾
上一节我们介绍了线性分类器的局限性。本节中,我们来看看如何通过神经网络来增强模型的表达能力。

神经网络的基本形式是学习一个映射函数 Φ(x),使得分类器变为:
h(x) = Φ(x)^T w + b
与核方法不同,神经网络同时学习映射函数 Φ(x) 和分类器参数 w 与 b。这使其比单纯的线性分类器更强大。
深度学习的复兴
神经网络并非新技术,但其*年来的复兴主要归功于以下三个关键变化:
以下是促成深度学习复兴的三个关键因素:
- 激活函数的改变:人们开始使用整流线性单元(ReLU) 代替传统的Sigmoid函数。ReLU的公式为
σ(z) = max(0, z)。这解决了Sigmoid函数在饱和区梯度消失的问题,使得基于梯度下降的训练更加高效。 - 硬件加速:GPU 的普及极大地加速了神经网络训练。神经网络训练的核心运算是矩阵乘法,而GPU非常擅长并行处理这类计算,使得训练大型网络成为可能。
- 优化算法:随机梯度下降(SGD) 虽然从纯优化角度看并非最佳算法,但其在实践中被证明能有效防止过拟合,并适用于大规模数据集。



此外,“深度学习”这个名称本身也是一种成功的重新定位,让人们意识到这与过去的神经网络有所不同。
深度学习的优势与应用领域
与核方法相比,深度学习有一个显著优势:其计算成本随数据量增长呈线性增加,而核方法则通常是*方级增长。这意味着深度学习能更好地利用海量数据。

深度学习在以下两个领域取得了革命性成功:
- 图像识别:深度学习模型能够端到端地学习从原始像素到最终标签的映射,省去了复杂的手工特征工程流程。在ImageNet竞赛中,深度学习模型将错误率大幅降低,甚至超越了人类水*。
- 语音识别:同样,深度学习也彻底改变了语音识别领域,使得手机语音助手等应用成为可能。
神经网络工作原理剖析
为了理解神经网络的内部机制,我们以一个回归问题为例。我们的目标是学习一个函数 h(x) = w^T σ(Ux + c) + b,其中 σ 是ReLU激活函数。
我们可以将这个公式展开,将其视为多个“小函数”的加权和:
h(x) = Σ_d [ w_d * max(0, u_d^T x + c_d) ] + b
这里的每个 max(0, u_d^T x + c_d) 都是一个“折线”函数(在更高维是超*面)。它由权重向量 u_d 和偏置 c_d 定义,在输入超过某个阈值后被“激活”(输出正值),否则输出0。
神经网络的学习过程,就是通过调整所有这些 u_d, c_d, w_d 和 b,用许多这样的折线段来拟合目标函数。理论上,只要有足够多的这样的“折线单元”(即足够大的隐藏层维度 H),神经网络可以以任意精度逼*任何*滑函数,这被称为通用*似定理。

深度(多层)网络的威力
之前我们讨论的是单隐藏层网络。深度网络则通过堆叠多个这样的层来构建:Φ(x) = σ( U_1 σ( U_2 x + c_2 ) + c_1 )。
一个直观的比喻是折纸:
- 单层网络:像在纸上折出一条折痕,定义一条分界线。
- 深层网络:像进行多次折叠。第二次折叠是在第一次折叠形成的复杂结构上进行的,这使得模型能够复用已学习的基础模式,以指数级效率组合出更复杂的函数。

理论上,一个足够宽的单层网络可以表达任何函数,但所需的参数可能极其庞大。而深度网络通过多层组合,可以用少得多的参数达到同等的表达能力,这是其强大之处。目前的研究趋势是构建更深的网络。

关于过拟合与随机梯度下降

一个自然的问题是:如此强大的模型为何不会严重过拟合?这很大程度上要归功于随机梯度下降(SGD)。我们将在下一讲详细讨论SGD。简而言之,SGD的随机性使其在优化过程中不会精确收敛到训练损失的最低点,从而无意中起到了正则化的作用,缓解了过拟合。
演示实例
我们通过一个简单的一维回归demo,可视化了不同数量隐藏单元下神经网络拟合曲线的过程。单元越多,拟合的折线段越多,对复杂函数的*似能力越强。

此外,还有一个有趣的应用演示:训练一个神经网络来判断人脸是否“好看”(基于Hot or Not网站数据)。尽管这是一个非常主观且复杂的任务,神经网络在测试集上达到了约74%的准确率(优于随机猜测),并能对知名人物给出符合大众预期的评分,这展示了其学习高级抽象概念的能力。
课程总结
本节课我们一起学习了:
- 神经网络的基本框架:学习特征映射与分类器。
- 推动深度学习复兴的三大关键技术:ReLU、GPU和SGD。
- 神经网络的工作原理:通过组合多个折线(超*面)函数来*似复杂函数。
- 深度网络的本质:通过层叠结构,指数级提升模型表达能力。
- 深度学习的优势:擅长处理图像和语音,并能有效利用大数据。
- 对过拟合的初步解释:与SGD的优化特性有关。

在接下来的课程中,我们将深入探讨随机梯度下降的细节及其在训练神经网络中的关键作用。
机器学习:036:神经网络与深度学习(续)
在本节课中,我们将继续学习神经网络与深度学习的核心内容,重点探讨如何训练神经网络,包括梯度计算、反向传播算法以及随机梯度下降等关键概念。我们还将讨论神经网络优化中的一些重要细节,如初始化、非凸优化以及现代深度学习实践中的常用技巧。




课程安排与项目更新
倒数第二节课。机器学习课程。请大家,除非坐在最后一排,否则请收起笔记本电脑。
项目8已发布。正如之前所说,不必担心,它相对简单。它比项目7容易得多,项目7可能是较难的项目之一。
最新的作业也已发布。这是可选的。因此,您不需要提交它。您仍然应该完成它的两个原因是:A. 因为它是考试的良好准备;B. 因为您在作业6中推导的内容正是您在项目8中需要实现的内容。如果您完成了作业,它将极大地帮助您。项目8确实非常简单。
此外,有人询问了模拟考试。我已将它们发布在Piazza的“资源”部分下。最顶部是“模拟期末考试”之类的。请在准备时查看这些资料。
最后,我相信冲突考试的提前报名现已结束。因此,我认为只有极少数人因大学认可的冲突而无法参加考试。我们将安排一个替代日期。请做好准备。我相信我们今天会发布相关信息。
有任何关于课程安排的问题吗?很好。

神经网络回顾与学习目标
我们讨论深度学习和神经网络。
正如我们上次所讲,深度学习本质上有一个损失函数,它是我们预测器H(即假设)的函数。这可以是一个通用函数,遍历所有不同的样本并计算损失。例如,一个典型的例子可能是*方损失:(H(X_i) - Y_i)^2。这是回归设置。
神经网络只是线性分类器的简单扩展。H(X) = W^T * φ(X)。这里的技巧在于,φ(X)本身是一个映射。所以,φ(X) = σ(U * X)。让我们暂时忽略偏置项。这就是一个单层神经网络。如果您有多个层,您可以在这里再嵌套一个函数。那么您有 φ'(X) = σ(U' * φ''(X)),依此类推。您可以根据需要创建任意多层。在这个例子中,我们有一个三层神经网络。
输入进入这里,乘以一个矩阵,应用一个激活函数(例如ReLU,将负数置零),得到一个向量输出,再乘以一个矩阵,再次应用ReLU,依此类推。最后,您得到您的预测。
今天我想讨论的是如何学习这样的神经网络。我们有一个损失函数。之前我们看到,当您有一个损失函数和这样的分类器时,我们只需进行梯度下降。对于神经网络,您实际上做完全相同的事情。唯一的不同是,您不仅仅有一个向量W,您还有这些中间矩阵。这些是您的参数。您有最后的W(最后一层),以及所有中间层,每层都有一个变换矩阵。
那么如何进行梯度下降呢?首先,您必须计算关于每一个这些矩阵的梯度。然后,实际上,和以前一样,您只需取梯度,然后进行一个小步长的更新。您只需说:U 变成 U - α * 梯度。这就像经典的梯度下降,没有什么特别的。
计算梯度:链式法则与反向传播
稍微棘手的一点是,您必须计算这些位于网络深处的权重矩阵的梯度。您基本上必须考虑如何通过这个函数,再到下一个函数,依此类推,直到最终到达输出层。
事实证明,有一个非常好的技巧可以做到这一点。它被称为链式法则。谁听说过链式法则?太棒了。谁听说过链式吸烟?实际上差不多。
以下是您的做法。第一个梯度很简单。那就是梯度 dL/dW。在这个例子中,这只是*方损失的梯度,其中 H(x) 是 W^T * φ(X_i)。所以 dL/dW = Σ_{i=1}^n (W^T * φ(X_i) - Y_i) * φ(X_i)。到目前为止,这没有什么特别的。您已经实现了这个,在ERM作业中,您正是这样做的。φ(x) 是您的特征向量,您最小化*方损失,计算梯度,然后进行梯度更新:W 变成 W - α * 这个梯度。
现在轮到计算关于中间矩阵 U 的梯度了。这变得有点棘手。我们如何使用链式法则得到它呢?我们想要 dL/dU。使用链式法则,您会意识到,您必须经过所有这些链,每一层都会使计算越来越昂贵。但事实证明,实际上它非常廉价,因为您可以重用计算。这被称为反向传播。
反向传播的发明实际上花了很长时间,远在神经网络发明之后。起初,人们并没有使用链式法则来训练它,这是有原因的。
我们想要计算关于第一个矩阵 U 的梯度。它基本上在 φ(x) 内部。我们如何做到这一点?我们可以说 dL/dU = (dL/dA) * (dA/dU)。这里我们使用了一个简单的技巧:将 U * X 的输出称为 A(x),然后 φ(x) = σ(A(x))。这只是为了给每个步骤命名。
所以,根据链式法则,损失函数关于 U 的梯度等于损失函数关于 A 的梯度乘以 A 关于 U 的梯度。

现在让我们尝试计算第二层的梯度。我们想要知道损失函数关于 U' 的梯度。同样,根据链式法则,这等于损失函数关于 A' 的梯度乘以 A' 关于 U' 的梯度。
关键点在于:A 关于 U 的梯度是什么?A(x) = U * φ(x)。所以 dA/dU 就是 φ(x)。这很容易计算。当您将输入推过这个函数时,您已经计算了所有这些 φ(x),而这些正是您在这里需要的梯度部分。
那么 dL/dA 这部分呢?这部分您已经在上一步计算了。所以您需要做的就是计算 dL/dA' 这部分。事实证明,这非常容易,它实际上就是激活函数的导数。
我不会更详细地讲解,因为它很繁琐,而且对您帮助不大。最好您自己完成。请认真对待,完成作业,推导所有这些更新。关于它的美妙之处在于,最终您会得到一个非常简单的算法。它只是说:好了,我想计算所有这些不同矩阵的梯度。我该怎么做?我计算第一个梯度,然后将其乘以一个向量,得到第二个梯度,再乘以另一个向量,得到第三个梯度,依此类推。这是一个非常简单的过程。实际上,我在笔记中提供了伪代码。如果您查看笔记中“反向传播”的部分,那就是伪代码。在项目8中,您需要实现的就是那个代码。当我说它简单时,我的意思是:是的,它只有三行伪代码。
梯度下降与随机梯度下降
您的问题是,我们使用真正的梯度下降还是随机梯度下降?给我两分钟,我会讲到。
关键点是,当您计算位于神经网络深处的梯度时,假设您有10层,您需要做的就是取前一层的梯度,几乎全部使用,只需乘以一项,就得到下一个梯度。因此,计算所有这些梯度实际上非常高效。这就是关键。
如今,计算这些梯度变得越来越不重要。即使在五年前,博士生们大部分时间都在计算梯度和实现梯度,这非常痛苦。您必须让它快速运行。但如今,实际上只是最*的发展,所有这些语言都有自动微分。所以您实际上只需计算函数,输入函数,然后说“计算梯度”,它就会符号化地计算梯度。这是过去几年才变得非常高效的事情。所以现在,如果您使用TensorFlow或PyTorch等所有软件包,它们都会为您计算梯度。但了解其原理仍然很重要。
神经网络优化的特殊性
现在我们知道如何计算梯度了。特别是当您完成作业后,一切都会变得非常清晰。
基本上,我们有了我们的网络。我们得到所有这些不同的梯度。然后我们需要做的就是进行梯度下降。所以我们说:W 变成 W - α * dL/dW,U 变成 U - α * dL/dU,依此类推。对所有参数都这样做。然后重新开始。

还有两个细节,与之前我们所做的相比有两个重要变化。第一个是普通的梯度下降,我们已经做过了,并且您已经实现了它。
一个非常微妙且重要的区别是,这个函数不是凸函数。这是我们过去推导梯度下降时所有损失函数都是凸函数的情况。凸函数看起来像这样。我们说,您可以从任何地方开始,所以我们从零向量开始,然后进行梯度下降。每次您迈出一小步,都会进一步下降。最终,我们会到达最小值。这就是凸函数上的梯度下降。
对于神经网络,我们仍然使用凸损失函数,但整体不是凸的。为什么不是凸的?因为 φ 本质上由于激活函数的存在。所以关于 W 是凸的,但关于 U、U' 和 U'' 不再是凸的。因为您有这些非线性,如果您取二阶导数,很容易证明它不是凸函数。
所以您试图最小化的函数看起来像这样。您可能忘记了找到全局最小值。您永远找不到全局最小值。有指数级的局部最小值,像这样的小坑,您总是会陷入其中一个。所以找到全局最小值是不可能的。您想做的是找到一个好的局部最小值。
因此,最重要的变化是,初始化突然变得重要了。您从哪里开始不再无关紧要。以前总是无关紧要的,您可以从任何地方开始,从全零向量开始很方便。现在不再是这种情况了。如果您从这里开始,进行梯度下降,会发生什么?您会一步步下降,收敛到这个最小值。因为梯度下降会收敛到局部最小值。如果您从这里开始,您会到这里。如果您从这里开始,您会到这里。所以初始化是一件大事。
当然,如果您能负担得起,训练10个不同的网络并取最小值。更好的方法是*均输出,将它们集成起来。
所以初始化现在非常重要。事实上,如果用全零矩阵初始化,您会得到糟糕的结果,因为那样每个维度都是相同的。记住我们上次说的,低层特征学习什么?这些低层特征学习非常简单的函数。然后基本上,下一层学习更复杂的函数,由这些简单函数构建而成。但如果它们都被初始化为相同,实际上每个函数都是相同的。所以您希望随机初始化它们。人们只是用随机噪声(低阶高斯噪声)初始化这些 U 矩阵和 W 向量。
这是神经网络优化与例如支持向量机之间的一个非常重要的区别。这也是人们如此喜爱支持向量机的原因之一,因为它们是全局的。它们全局优化事物。您得到全局最小值。您保证每个人在相同数据上训练相同的支持向量机得到完全相同的答案。对于神经网络,您和我在相同数据上训练神经网络。我们随机初始化。我们得到不同的答案。这让人困惑,人们不喜欢这样。
随机梯度下降的优势
第二件事是我上次提到的,随机梯度下降非常重要。问题是,人们在神经网络的第一轮中使用了这些非常激进的求解器,例如*似海森步长的梯度下降等。这些是伟大的优化算法,因为它们能尽快让您到达最小值。如果您知道,通常负担不起海森或牛顿法,但人们使用*似的牛顿法,这些方法非常有效。优化社区已经开发这些方法很长时间了,它们只需几步就能收敛到最小值,比梯度下降快得多。所以人们说,不要使用梯度下降,使用这些更快的优化算法。所以您从这里开始。事实证明,是的,只需几步,您实际上就在最小值了。这太棒了。承诺是这样的。
但神经网络表现不佳。问题是您处于高度非凸的空间中。所以无论您从哪里开始,附*总有一个糟糕的局部最小值。现在,如果您使用这些非常激进的优化算法,它们基本上会立即收敛到局部最小值,您会直接到达那里。但通常这些不是好的最小值,通常好的最小值在很远的地方。
这就是随机梯度下降的用武之地。让我告诉您什么是随机梯度下降。
每个权重的梯度基本上是 dL/dU。它是所有数据点的和,i=1 到 n。基本上,我们对每个数据点求和,每个数据点都对梯度贡献一点点。我们计算这个总和,那就是我们的最终梯度。
现在,随机梯度下降背后的想法是这样的。想象您有一个像这样的函数。我试图最小化它。它是非凸的。周围有很多坑。
随机梯度下降非常简单。您说,与其计算所有数据点的梯度(这是正确的做法),我不如*似它。我用一个点来*似它。所以我说,现在 dL/dU 大约等于一个点的损失梯度。这完全错了。梯度是许多小梯度的*均值。而我说的是,好吧,我一次只看一个训练样本。我只计算一个训练样本,它给我梯度。我假装那是我唯一的训练样本。
假设我在这里,梯度指向这个方向,因为它与损失函数正交。但如果我只取一个样本,我可能会指向这个方向。这很糟糕。但这是我们以前见过的。您在哪里见过这个?很多嘈杂的梯度,对吧?完全相同的想法。如果您有很多嘈杂的梯度,您所做的就是取一个非常小的步长,朝这个方向迈出一小步。*均而言,这些梯度正是正确的梯度。所以有时偏右一点,有时偏左一点,等等。这让我回到了醉汉梯度下降算法。所以您迈出一系列步伐,*均而言,朝着正确的方向前进。
酷的是,计算精确梯度需要 O(n) 次操作,因为您必须遍历整个训练数据集,计算每个训练点的梯度贡献并求和。现在,您做的是随机梯度下降。在这段时间内,您实际上可以采取 n 步。所以您迈出一小步,再一小步,再一小步,依此类推。当您这样做时,您向前移动,您的梯度也会改变,因为如果您在这里,梯度实际上更多地指向这个方向。所以当您已经处理了一半数据后,您实际上已经取得了一些进展。现在,未来一半的数据点,*均而言,不再指向原始梯度的方向,而是指向我所在点的梯度方向,实际上更多地指向这个方向。
所以,在原始梯度下降中,您基本上采取一些大步,像这样,像这样,依此类推。在随机梯度下降中,您采取许多非常小的步伐。但是,因为您可以在处理数据时调整方向,您实际上更快地到达最小值。
您的问题是,您切换了故事。最初您从局部最小值开始,现在您告诉我关于醉汉的事情。公*地说,这不是他说的原话,但没错。
这是一个原因,为什么人们最初不认真对待随机梯度下降。随机梯度下降是已知的,但人们认为它是一个糟糕的算法。我可以告诉您为什么。因为如果我试图证明,需要多少步才能找到精确到 10^-5 精度的最小值,事实证明,随机梯度下降需要永远。为什么需要永远?因为最初,您非常接*最小值。一旦您在那里,您会采取许多随机步骤。您永远无法真正达到它。这又是一个醉汉回家的例子,他到了家,却找不到该死的钥匙孔。这就是问题所在。您就在这里,因为太嘈杂了,您永远无法真正收敛。
但这并不是一个大问题,因为在机器学习中,我们实际上并不关心精确的最小值。整个损失函数本来就是人为构建的。
但还有更好的事情,这让我们回到优化。事实证明,现在我们正在回家,这里有很多小坑。这个函数是非凸的,这里有很多吸引子。基本上,函数看起来像这样。当您下山时,如果您使用精确梯度方法,您会计算这里的梯度,并且总是会找到这个确切的最小值。但随机梯度下降非常嘈杂,它会做什么?它会经过这里。它不会找到这个愚蠢的最小值。它会直接走过去。
因为它是一个如此糟糕的算法,它实际上很棒,因为它不会掉进沿途的每一个坑。您只会最终掉进一些大坑里,无法逃脱。人们没有想过这个,但事实证明这正是您想要的。您想要这些大坑。为什么?人们认为您想要非常深的坑。您想最小化损失并变得非常非常深。这就是梯度下降在这些二阶方法中真正擅长的。
但您实际上不想要这个。想象函数看起来像这样。最小值实际上在这里,这个非常陡峭的损失。但我声称这是一个可怕的损失。您真正想要的是最终在这里。谁能告诉我为什么?没错。这是您的函数。但有一个函数,我的损失函数。我的损失函数是我的训练集的函数。它是两样东西的函数:我的数据和我的函数(我的假设)。如果我固定数据(我在这里这样做),那么我得到的是我的假设的函数,我试图找到最小值。

但我们后来实际要做什么?后来,我们将丢弃训练数据,转向测试数据。当我们在这里放入不同的数据集时,函数将会改变。我们有这些非常陡峭的局部最小值。现在会发生什么?基本上,它们优化了这个东西。现在在测试时,实际上有一个不同的函数。也许它看起来像这样。哎呀,我在这里,现在却在这里。突然,我找到的最小值变得非常非常糟糕。这说得通吗?

所以,如果您有这些非常窄的最小值,它们往往非常特定于您训练的具体数据集。如果您有非常宽的最小值,如果您改变数据,它实际上不太可能改变很多。所以,您真正想要的是在一个非常宽的最小值上尽可能降低损失函数。而这是随机梯度下降唯一能够找到的东西。这实际上是至关重要的。
如果您有一个非常大的数据集并且可以负担过拟合,那么这些影响变得不那么危险。没错,这意味着如果您有一个非常大的数据集,函数的变化会非常小。没错。
但什么是非常大的数据集呢?这些是非常高维的空间,您总是采样不足。所以人们发现,最初他们只是凭经验发现,如果使用随机梯度下降训练神经网络,它突然变得好得多。花了很长时间才理解其原因。
梯度步数是否受训练点数量的限制?不,您一遍又一遍地遍历数据集。在梯度下降中,您所做的是遍历所有数据点,计算梯度,采取一个梯度步长。现在您所做的是随机取一个数据点,计算梯度的那个小*似值,进行梯度更新,并不断迭代。所以您无法真正保证。只是如果有一个非常窄的最小值,我的意思是在高维空间中,在一维空间中,很明显这个东西会掉进去。但即使在二维空间中,想象这是我的函数。这里有一个小坑。我太接*了,实际上掉进去了。梯度突然指向这个方向,不再指向那个方向。但因为随机梯度下降如此嘈杂,您会再次指向它并迈出一步。我不清楚。所以您实际上最终掉进去似乎不太可能。它只是不断摇晃。
实际上,人们在实践中优化这些东西时使用两个技巧。第一个是,他们实际上不只是随机取一个点。他们取大约64或128个点,称之为小批量。原因很简单,因为如果您通过网络传播一个点或64个点,成本大致相同,只是因为您的计算机有这些小的并行向量和L1缓存等。所以实际上这样做是高效的。
第二件事是,最初,您使用一个相当大的学习率。这回到了您的问题:我们如何保证不掉进这些局部最小值?最初,您使用一个相当大的学习率。好处是这可以防止您掉进小的局部最小值,并让您接*实际局部最小值所在的区域。所以也许您做100个周期(一个周期是遍历整个数据集一次),使用大的学习率。然后之后,您大概在这里。现在您只是跳来跳去。这看起来有点像这样。现在您在这里,您所做的是在这之间来回跳跃,因为您的步长太大了。然后您做的是将学习率降低10倍。然后您基本上采取小步长。这意味着现在我收敛到实际的局部最小值。让我再画一次。这是基本思想。想象您的函数通常看起来像这样。这是最小值。所以您想做的是,您从这里开始,最初采取许多步骤,像随机步骤。它们非常嘈杂,让您到达这里。现在您只是来回弹跳。您这样做几步,直到基本上不再有进展。然后一旦在这里,您采用小的学习率,现在您基本上向下移动到这里,直到得到最小值。当您查看损失时,它实际上看起来像这样。如果您查看现代神经网络的损失,它看起来像这样,然后您降低学习率,它看起来像这样。有时您会再次降低学习率。
您的问题是,一旦您做了一段时间的随机梯度下降,现在您相当确信接*局部最小值了,为什么不直接使用二阶方法呢?您可以。在实践中,通常不值得实现,因为现在您已经做了很多工作,您只需用小的学习率进行几次迭代,就可以了。但没错,您可以。
或者有更技术性的解释。随机梯度下降保证它最终能够爬出来。是的,有。这需要我花一个月来解释。但如果您感兴趣,现在有大量文献分析这个问题。问题是,是否有更严格的答案,为什么随机梯度下降能给出好的局部最小值?答案是,是的。您可以用多种方式形式化这一点。如果您愿意,课后我可以给您一些直觉,解释为什么会这样。
问题是,如果函数看起来像那样怎么办?没错,那是一堆。实际上,这就是它的样子。您有数百万个参数。您处于一个百万维的空间中,不仅仅有几个这样的坑,有数十亿个最小值。您最终会掉进其中一个。
不过,关于这一点的一个好处是,如果您想用神经网络进行装袋法,您通常有足够的随机性,以至于不需要对数据进行子采样。通常,当您进行装袋法时,您用替换法对n个数据点进行子采样。但对于神经网络,因为您只是随机初始化网络,您从空间的不同部分开始,最终到达非常不同的局部最小值,甚至不需要对数据集进行不同的子采样。您实际上会得到行为非常不同的神经网络。令人惊讶的是,它们往往有大致相同的错误率,但会犯非常不同的错误。这使得神经网络非常适合集成。所以,如果您真的想获得最低的错误率,例如在Kaggle竞赛中,您所做的就是训练5个神经网络,然后*均它们的结果。这实际上带来了巨大的改进。
神经网络的“神经元”视角
我想向您展示一些东西。在我结束之前,我想谈一件事:什么是神经网络中的“神经元”?人们总是谈论为什么它被称为神经网络?这些都是函数。我试图以这种方式解释,因为我认为这与我们到目前为止在课程中所做的并没有太大不同。
但让我快速向您解释为什么人们称它为神经网络,以及什么是神经视角。我不是很喜欢它,因为它会导致《连线》杂志等出现奇怪的文章。
但基本上,人们说,您可以将这表示为某种图。您的X输入,我画出来。对于X的每一个维度,这里有一个小球,一个小圆圈。所以这是一个向量X,这是第一个维度的值,第二个维度,等等。这是一个五维向量。这说得通。这只是向量表示法。如果这说得通,请举手。太棒了。

现在我要做什么?我把我的X放在这里。我得到一个新的表示,称为 φ''(x)。这有一堆维度。这里的转换是 x 变成 U * x。所以 φ(x) = σ(U'' * x)。这说得通吗?如果这说得通,请举手。很好。
现在我们再次邀请,这是 φ'(x)。这是我的 φ(x)。这是我的 H(x)。
现在,如果我考虑这个,这是什么?这是每个输入的函数。所以人们做的是画一个箭头,说这个值是这个家伙的第一个维度,它基本上是U矩阵的第一行乘以x。所以他们称这些为连接。然后您对每一层都这样做。现在您有了一个网络。我不喜欢它。我可以告诉您为什么我不喜欢它。因为人们然后与大脑进行类比,分析这些神经元,说这些神经元做什么等等。问题在于,我不太喜欢它,因为它实际上只是一个D维空间,您可以旋转空间,得到完全不同的表示,但输出完全相同。所以在某种意义上,解释空间的不同维度似乎很奇怪。我看不出这有多大价值。但这导致了很多误解,人们认为这就是大脑所做的(这不是真的),或者说这些神经元做的比实际做的多得多。它实际上只是一个函数 φ(x)。当然,这是一个D维向量。所以这些向量中的每一个都有一个值。但重要的是,当人们说“我观察一个神经元的值”时,他们真正的意思只是这个U矩阵的一个维度。
顺便说一下,最初它是受大脑启发的。最初的神经网络来自那个方向。在实践中,人们除了ReLU还使用其他东西吗?答案是,如今,修正线性单元非常非常流行。原因其实很简单。人们以前认为必须使用连续函数和可微函数。修正线性单元,如果您仔细观察,会发现它是不可微的。所以您在不可微函数上进行梯度下降,这似乎很疯狂,会导致各种问题。事实证明,如果您使用随机梯度下降,它已经非常嘈杂,实际上并不重要。所以当人们开始使用随机梯度下降时,实际上可以使用修正线性单元。然后,与tanh和sigmoid函数相比,其优势变得明显,因为这些tanh和sigmoid函数非常*坦。记住它们的样子。它们基本上将所有东西映射到0到1之间。使用这些sigmoid和tanh函数的网络得到的是它们饱和得非常快。所以修正线性单元往往更擅长不陷入局部最小值。
权重衰减在使用这些sigmoid函数时很重要,因为您希望将它们保持在中间。权重衰减只是L2正则化的另一个词。没什么别的。它只是与VDK并行发明的东西。所以人们也对权重使用正则化。但对于修正线性单元来说不那么重要,但仍然有助于避免过拟合。
演示与总结
我想向您展示上次没成功的东西。现在它在这里。这个函数,黑点基本上是我的训练点。在左边是一个带有修正线性单元的神经网络。您在这里看到的结构有一个输入,2个隐藏节点和一个输出。所以两个隐藏节点意味着我的第一个函数将一维输入映射到二维输出。然后下一层将二维输出映射到一维输出。
所以您在这里映射的是维度的数量。您看到修正线性单元有两个节点。所以它基本上有两个转折点。您看到tanh要*滑得多。现在我可以引入四个节点。您在这里可以看到一件事,这就是人们认为tanh好得多的原因,因为tanh几乎击中每一个转折点。错误率要低得多。而修正线性单元在这里有点挣扎。但原因是,修正线性单元存在的这些问题是因为它们难以优化。当您有数百万个时,这些问题就消失了。基本上,总有一些指向正确的方向。所以修正线性单元在复杂问题上往往更好,但在这些小演示中更差。这是误导性的。现在我可以,每次,8维隐藏表示,等等。所以,我让它越来越复杂。您在这里可以看到,tanh函数非常非常好地优化了这个。在这里,您仍然有这些分段线性函数。您在这里可以看到的是,在某种意义上,它在这里产生了一些幻觉。函数在这里上升,尽管没有数据支持这一点。这没关系。
我还想快速向您展示一件事。TensorFlow。我不知道。TensorFlow是谷歌的免费软件包。实际上,大多数人更喜欢PyTorch,它来自Facebook。但我认为TensorFlow稍微容易使用一些。
您在这里可以看到,我们可以取一些数据。这些是我的数据点,正的和负的。我现在可以构建一个新的网络。如果您输入TensorFlow playground,您可以玩这个,他们提供了一个不错的小演示。这是我的输入。这是我输入的第一个维度。这是我输入的第二个维度。所以基本上这是我的X坐标,我的Y坐标。然后我有一个四维的学习表示,这是我的 φ(x)。这是我的输出。让我们只做一个一维输出。为什么不呢。我现在可以训练这个东西。您在这里看到的是输出。它现在训练了这个,并且全部正确。现在我可以看的一件事是,我可以实际查看这个单层神经网络,观察这些神经元是否有意义。所以在这里,您实际上看到它学习了一堆函数。现在我可以输入一个例子,让它更难一点。优化这个。您在这里看到。它在挣扎。来吧。所以您做的是,您知道,挣扎,您只需添加更多神经元。好了,更好了。所以,您看到的是,这些是我的输入。现在我可以查看,当我把鼠标悬停在这个上时,您可以看到右边的图像变化。所以它向我展示的是这个特定函数的激活情况。您可以看到它学习了这些单独的小函数。最终的输出现在是这些函数的组合,它正好完美拟合了异或数据集。
现在我可以做一些非常难的事情,但我可以先做这个。这个应该更容易。现在。它应该能够完美拟合。没时间了。哦,是的。漂亮。现在螺旋,螺旋实际上非常难。我们现在可以看到这个是否有效。它可能做不到。它在做什么?哦,是的。所以您现在做的是添加更多神经元。看看它做什么。不。我添加了另一层。就像千层面。更多层通常更好。它在做什么吗?开始了。整个事情是JavaScript,在我的笔记本电脑上。所以有点不公*。哦,对了,它在做某事。我们可以添加更多。我不知道。让我们,您知道,好吧,让我们最大化它。它使用修正线性单元。看看会发生什么。还没有。它最终会到达那里。它能做到。它能做到。只是需要一段时间。
让我打断一下。最后一件事。上次我提到,这在图像处理中变得极其强大。这里有一个例子,是一个初创公司。他们实际上销售他们的深度学习社区。他们所做的就是训练深度网络,输入图像,并在右侧分类。所以这是一张图像,基本上写着日落、水、黎明、黄昏等等。所以我们现在可以做的是尝试我们自己的图像。他们实际上可以。去谷歌图片搜索。我应该搜索什么?大象。好了。我用了我的?是的。那是我的搜索。所以。好了,这是图像。有点小,我们可以试试。他说,这个,这个,这个怎么样?这是我年轻时的照片,当我还住在德国时。我想,好吧,没关系。这里说这是图像。我不是机器人。它说什么?它说成功。哦,我的天哪。

我们得在高潮中结束。所以这是最后一个。下周三见。
机器学习:037:神经网络与深度学习


在本节课中,我们将学习神经网络与深度学习的核心概念,特别是卷积神经网络的工作原理,并了解当前该领域的一些前沿研究。



课程概述

这是本课程的最后一讲。由于之前因天气原因取消了一节课,我们今天需要做一个选择。根据大家的投票,我们将继续深入探讨深度学习,特别是卷积神经网络,并了解一些当前的研究进展。

神经网络回顾

上一节我们介绍了神经网络的基本概念。简单来说,神经网络旨在学习一个函数,其形式为 h(x) = Wᵀ φ(x)。这里的技巧在于,φ(x) 本身也是一个函数,它可以由更基础的函数嵌套构成。例如,φ(x) 可以是 φ'(x) 的函数,从而形成多层结构。
这种结构被称为全连接网络。如果我们用图形表示,输入 x 的每个维度都是一个节点,这些节点连接到隐藏层 φ(x) 的每个节点,隐藏层再连接到输出层。之所以称为“全连接”,是因为每一层的每个节点都与前一层的所有节点相连。

卷积神经网络的引入

然而,在处理图像数据时,全连接网络存在一个问题:它忽略了图像固有的空间结构信息。当我们把一张图片的像素展开成一个长向量时,就丢失了像素之间的二维邻接关系。




图像有一个关键特性:局部*移不变性。这意味着,如果图像中的物体(比如一张人脸)在画面中稍微移动一点位置,它仍然代表同一个物体。但对于向量化的像素表示,位置的微小变化会导致向量值发生剧烈改变,因为对应的像素完全不同了。
为了识别物体,一个全连接网络需要看到物体出现在图像所有可能位置的训练样本,这需要海量的数据。卷积神经网络 通过修改函数 φ 的结构,将这种*移不变性直接编码到网络中,从而极大地减少了所需的数据量。
卷积神经网络的工作原理
卷积神经网络尊重图像的原始结构。它的输入不是一维向量,而是具有多个通道的二维图像(例如,彩色图像的红色、绿色和蓝色通道)。函数 φ 的作用是接收这些图像,并生成一组新的图像作为输出,下一层的 φ' 再以这些新图像为输入,以此类推。直到网络的最后,才将图像表示转换为一维向量进行最终分类。

这个过程中的核心操作是卷积。具体做法如下:
- 我们有一个小的滤波器(例如一个3x3像素的网格)。
- 将这个滤波器在输入图像上滑动。
- 在每个位置,计算滤波器与对应图像区域像素值的点积,结果作为输出图像在该位置的值。

这个滤波器中的数值就是需要学习的权重。通过训练,不同的滤波器会学会检测图像中不同的局部特征,例如边缘、角点或圆形。随着网络层数的加深,后续层可以组合这些低级特征,检测出更复杂的模式,如眼睛、鼻子等。
训练卷积神经网络的方法与训练普通神经网络相同(例如使用反向传播)。实际上,卷积网络可以看作是一种特殊的全连接网络,只不过我们将大部分连接的权重强制设为零,只保留局部连接。这种限制迫使网络学习对*移变化不敏感的特征,这正是其成功的关键。
当前研究进展:提高网络鲁棒性


卷积神经网络在计算机视觉领域取得了巨大成功。当前的研究致力于改进这些网络。一个主要问题是:现代神经网络往往非常深(甚至有上千层),这类似于“传话游戏”,信息需要经过很多层传递,任何一层出现误差都会影响后续所有层。
为了提高深度网络的鲁棒性,研究人员提出了多种方法:
- 残差连接:让某一层不仅能接收前一层的输出,还能接收更早层的输出,确保即使中间层“传错话”,原始信息仍然可用。
- 随机深度:在训练时,随机“丢弃”(暂时移除)网络中的某些层。每次参数更新时,都随机选择不同的层组合进行训练。这迫使网络不依赖于任何单一层的完美运作,并且最终用于测试的完整网络可以看作是许多较浅网络的集成*均,提高了泛化能力。
前沿研究:密集连接网络
基于随机深度等思想的启发,我们提出了更极端的架构:密集连接网络。在这种网络中,每一层都接收前面所有层的输出作为输入。这就像开会时,每个人都能听到之前所有人的发言,而不仅仅是前一个人的。这种结构极大地减少了网络中的冗余,让信息流动更高效,通常能用更小的网络取得更好的性能,目前是多个基准数据集上的最优方法。
研究探索:理解网络所学
另一个有趣的研究方向是理解深度网络究竟学到了什么。我们的一个猜想是:深度网络(特别是卷积网络)能够将图像数据所在的复杂“流形”映射到一个线性子空间中。
为了验证这一点,我们进行了一个实验。我们使用一个在ImageNet上预训练好的网络(从未见过特定人物)。我们将一张没有胡子的人物图像输入网络,得到其高维特征表示。然后,我们计算“有胡子”和“无胡子”人群*均特征向量的差值,得到一个“胡子方向”向量。将这个向量加到原人物的特征上,再通过优化方法反推出对应的新图像。结果发现,生成的新图像中,人物确实长出了胡子,且看起来非常自然。

这表明,深度网络学习到的特征空间具有很好的线性特性,语义概念(如“有胡子”)对应着空间中的特定方向。我们还可以进行其他操作,如让人物变老、微笑、戴眼镜等。这个实验也揭示了方法的局限性,例如数据偏差(数据集中男性远多于女性)会导致在某些情况下效果不佳。
无监督学习简介

最后,我们简要提一下机器学习的另一个重要分支:无监督学习。本课程主要关注有监督的预测任务。而在无监督学习中,目标是从数据中发现内在结构,例如聚类或降维。

一个经典问题是流形学习:假设高维数据实际上分布在一个低维流形上(就像一张皱巴巴的纸放在三维空间中),目标是找到这个低维结构并将其“展开”。早期的方法(如等距特征映射、局部线性嵌入)只能处理简单的合成数据。如今,深度学习为处理真实世界复杂数据的无监督学习提供了新的强大工具。

课程总结

本节课中,我们一起深入探讨了卷积神经网络的核心思想,它通过卷积操作和权重共享,巧妙地利用了图像的*移不变性。我们还了解了当前深度学习领域的一些前沿研究,包括提高网络鲁棒性的技术(如随机深度、密集连接)以及对网络所学表示的探索。最后,我们简要对比了有监督预测和无监督发现结构这两大机器学习范式。希望本课程能为你进一步探索机器学习领域打下坚实的基础。
机器学习:038:五分钟内完成Kaggle课堂竞赛 🚀
在本节课中,我们将学习如何利用一个名为Vowpal Wabbit(VW)的高效机器学习工具,在极短时间内构建一个文本分类器。我们将通过一个具体的课堂竞赛案例——根据特朗普总统的推文内容,判断其发布设备是iPhone还是Android手机——来演示整个流程。
数据与任务介绍
在我的课堂上,我们曾组织过一次Kaggle竞赛。我们向学生提供了特朗普总统的推文,他们的任务是判断这些推文是用iPhone还是Android手机发布的。其背后的假设是:总统本人可能使用Android手机,而他的工作人员可能使用iPhone。如果同一个账户下的推文确实由不同的人发布,那么我们就能训练一个分类器来区分这两种设备。

我们为此创建了一个排行榜。我本人也提交了一个预测结果作为基准。我给自己设定的挑战是:在五分钟内完成从数据准备到提交预测的整个过程。


游戏规则是:如果学生们能在三周内,用比我五分钟内更好的成绩击败我,他们就能在这个项目上获得满分。事实证明,击败我并非难事。我的基准准确率是80%,而排行榜上顶尖学生的准确率达到了90%,这是一个显著的提升。

上图是私有排行榜的成绩。后来,学生们向我发起挑战,希望看到我实际训练分类器的屏幕录像,以验证我是否真的能在五分钟内完成。接下来,我就为大家展示具体步骤。
工具选择:Vowpal Wabbit
我选择使用的工具是Vowpal Wabbit (VW)。这是一个由John Langford(先后任职于雅虎和微软研究院)开发的分类器。它的特点是非常快速,本质上是一个高效的逻辑回归分类器,但也支持*方损失等多种损失函数。它的一大优势是集成了特征哈希(Feature Hashing) 技术,这意味着你可以直接将单词作为输入,VW会自动将它们哈希到对应的特征桶中,省去了繁琐的特征工程。
安装VW非常简单,可以通过包管理工具(如brew)直接安装。

实战演练:五分钟倒计时

现在,我将设置一个五分钟的计时器,开始实际操作。

第一步:数据准备
首先,下载竞赛数据。数据包含训练集和测试集。

在测试数据中,我们只需要推文文本本身。我并没有使用提供给学生的元数据(如发推时间)。实际上,这些元数据是非常强的特征,很多学生正是利用它们击败了我的基准模型。
以下是数据预处理的关键步骤列表:
- 格式化标签与特征:在训练数据中,标签(iPhone或Android)在左,推文在右。对于测试数据,我们需要先添加一个占位符标签。
- 清理文本:需要移除VW无法处理的特殊字符,例如冒号(
:)、竖线(|)、点号(.)和反斜杠(\)等,因为这些字符在VW的输入格式中有特殊含义。 - 统一大小写:将所有文本转换为小写,以减少特征维度。
- 移除表头:确保文件没有标题行。
第二步:训练模型
数据准备好后,我们需要将其顺序打乱,然后调用VW进行训练。
以下是我使用的核心VW训练命令及其参数解释:
vw train.vw --loss_function logistic --learning_rate 1 --passes 5 -c -f model.vw --initial_t 1
--loss_function logistic:指定使用逻辑回归损失函数。--learning_rate 1:设置学习率为1。--passes 5:指定对整个训练数据进行5轮迭代。-c:创建缓存文件,这在多轮训练时能提高效率。-f model.vw:将训练好的模型保存到名为model.vw的文件中。--initial_t 1:设置学习率衰减的初始时间步。
第三步:进行预测与提交
模型训练完成后,使用它对测试集进行预测。
以下是预测命令:
vw -i model.vw -t test.vw -p predictions.txt
-i model.vw:加载之前保存的模型。-t test.vw:在测试集上进行预测(-t表示测试模式,不更新模型)。-p predictions.txt:将预测结果输出到predictions.txt文件。
得到预测结果文件后,只需按照Kaggle要求的格式稍作整理(例如,添加ID列),即可提交。


最终,在计时器结束前,我成功完成了文件上传。


核心要点总结
本节课中,我们一起学习了如何利用Vowpal Wabbit工具进行快速的文本分类任务。整个过程可以概括为以下几个关键点:
- 工具高效:VW凭借其特征哈希和优化算法,能实现极快的模型训练。
- 流程简洁:核心步骤就是数据清洗、模型训练和预测输出。
- 命令核心:训练命令的关键在于指定损失函数、学习率、迭代轮数并保存模型;预测命令则是加载模型并应用于新数据。
回顾我的五分钟挑战,一旦掌握了正确的命令行参数,整个过程就变得非常直接。我使用了逻辑回归损失,学习率设为1,进行了5轮迭代。在实际应用中,这些超参数(如学习率、迭代轮数)通常需要通过交叉验证来优化,但本次挑战旨在演示快速原型构建的可能性。


希望这节课能帮助你理解如何运用高效的工具快速解决机器学习问题。这就是全部内容。


机器学习基础:039:课程介绍与学习路径

在本节课中,我们将了解康奈尔大学《智能系统的机器学习》课程的核心内容、学习目标以及课程结构。课程将从最基础的算法开始,逐步深入到当前最先进的技术,旨在帮助学习者建立坚实的理论基础与实践能力。
课程概述
机器学习*年来的蓬勃发展源于其巨大的潜力。其核心理念是,无需为每个具体任务编写新程序,而是编写一个通用程序,并通过数据“教导”它完成多种任务。然而,当前的人工智能技术并非无需理解即可直接使用的简单工具。
课程深度与目标
市面上许多人工智能课程仅教授如何使用从网络下载的代码,这通常是不够的。本课程的不同之处在于,它不仅讲解如何使用这些算法,更深入剖析其工作原理与底层原理。
课程的目标是为学习者奠定坚实的理论基础。完成本课程后,学习者将具备应用这些算法、调试它们并使其在实际问题中有效工作的能力。
学习路径与内容结构
以下是本课程从基础到高级的核心学习路径:
-
起点:感知机算法。课程从最简单的感知机算法开始,其核心公式可表示为:
y = sign(w·x + b)
其中,w是权重向量,x是输入特征,b是偏置项,sign是符号函数。 -
进阶:现代前沿算法。在打好基础后,课程将逐步引导学习者理解并掌握直至当前最先进的各种机器学习算法。
总结


本节课中,我们一起了解了这门机器学习课程的设计哲学与学习路径。课程强调理解算法背后的原理而非仅仅调用代码,并规划了一条从最基础的感知机算法到现代前沿技术的清晰学习路线,旨在培养学习者真正的解决问题与工程实现能力。
机器学习:040:Transformer模型详解 🧠
在本节课中,我们将学习Transformer模型的核心原理。Transformer是当前自然语言处理领域最重要的架构之一,它通过自注意力机制为每个单词生成上下文相关的嵌入表示,从而解决了传统语言模型中词序丢失和一词多义等问题。我们将从最简单的语言模型开始,逐步构建出完整的Transformer架构。
从最简单的语言模型开始
上一节我们介绍了语言建模的基本概念,本节中我们来看看一个最简单的实现方式。
语言建模的核心任务是:给定一个句子序列,预测下一个单词。例如,输入句子“I like to eat”,模型需要预测下一个单词(如“banana”)。
最简单的模型是将输入表示为词袋向量。这是一个非常高维的向量,其维度等于词汇表大小(例如10,000维)。向量中,每个单词对应一个位置,如果该单词出现在输入中,则对应位置为1,否则为0。
对于句子“I like to eat”,其词袋向量 x 在“I”、“like”、“to”、“eat”对应的四个位置上是1,其余位置都是0。
然后,我们训练一个神经网络来预测下一个单词。该网络可以表示为一个函数:
h(x) = softmax(W * ReLU(U * x + b))
其中:
U是一个矩阵,将高维的输入向量x映射到一个低维的隐藏空间(例如128维)。U * x的操作本质上是取出输入单词对应的U矩阵的列向量,并将它们相加。ReLU是一个激活函数。W是另一个矩阵,其每一行都可以看作一个针对特定单词的分类器,用于判断该单词是否是下一个词。softmax函数将W的输出转换为一个概率分布。对于第i个单词,其概率为:
softmax(z)_i = exp(W_i^T * z) / sum_j(exp(W_j^T * z))
这里z是隐藏层的表示。W_i^T * z的内积大小代表了单词i作为下一个词的可能性。


模型的输出是一个概率向量,我们可以根据这个分布采样得到预测的下一个词(例如“banana”)。然后,我们将预测出的词加入输入序列,继续预测下一个词,如此循环即可生成文本。
词袋模型的局限性
然而,这个简单的模型存在两个主要问题:
- 词序丢失:词袋表示完全忽略了单词的顺序。“I like to eat”和“eat to like I”会产生完全相同的向量
x和隐藏表示z,这显然不合理。 - 静态词嵌入:每个单词通过矩阵
U获得一个固定的向量表示(即词嵌入,如Word2Vec)。但这无法处理一词多义的情况。
例如,在句子“I may visit in May”中,单词“may”出现了两次,但含义不同(一个是情态动词“可能”,一个是月份“五月”)。在词袋模型中,两个“may”会被相同地处理,因为它们的初始嵌入 U[“may”] 是相同的。模型只能通过上下文来区分它们的不同含义,但当前的架构不具备这个能力。
Transformer的核心思想:上下文嵌入
Transformer的核心目标就是解决上述问题,为每个单词生成上下文相关的嵌入。它不再使用词袋表示,而是保留每个单词的独立向量,并让这些向量能够根据上下文相互影响。
以下是实现这一目标的关键步骤:
1. 位置编码
首先,我们需要将单词的顺序信息注入模型。Transformer为每个输入单词的初始嵌入向量 U_i 加上一个位置编码向量 P_i:
U_i' = U_i + P_i
P_i 是一个仅与单词在序列中的位置 i 相关的向量。它通常由不同频率的正弦和余弦函数生成:
P(i, 2d) = sin(i / 10000^(2d/D))
P(i, 2d+1) = cos(i / 10000^(2d/D))
其中 d 是维度索引,D 是向量的总维度。这样,相*的位置会有相似的编码,而相距较远的位置编码差异较大。通过这种方式,即使两个相同的单词(如两个“may”),也会因为位置不同(P2 和 P5)而获得不同的初始表示 U_2' 和 U_5'。
2. 自注意力机制
这是Transformer的核心。它允许每个单词的向量根据序列中所有其他单词的向量进行更新,从而获得上下文信息。
具体来说,对于每个位置 i 的向量 U_i',我们通过三个不同的可学习矩阵 W_Q, W_K, W_V,将其转换为三个向量:
- 查询向量
q_i = W_Q * U_i' - 键向量
k_i = W_K * U_i' - 值向量
v_i = W_V * U_i'
我们可以将 q 理解为“我在寻找什么”,k 理解为“我是怎样的以便被找到”,v 理解为“我提供什么信息”。
然后,为了更新位置 i 的向量,我们计算 q_i 与序列中所有位置的键 k_j 的相似度(通常用点积):
s_{ij} = q_i^T * k_j
这个相似度分数经过softmax归一化后,得到权重 α_{ij}:
α_{ij} = exp(s_{ij}) / sum_k(exp(s_{ik}))
最终,位置 i 的新向量 U_i'' 是所有位置的值向量 v_j 的加权和:
U_i'' = sum_j(α_{ij} * v_j)
这个过程就是自注意力。每个单词的新表示都成为了整个序列中所有单词信息的加权组合。由于softmax的特性,权重 α_{ij} 通常是稀疏的,即每个单词主要只受少数几个相关单词的影响。例如,句子中的第二个“may”会更多地受到前面“in”的影响,从而获得与第一个“may”不同的表示。
3. 前馈神经网络与残差连接
在自注意力层之后,每个位置的向量会独立地通过一个相同的前馈神经网络(FFN)。这是一个简单的多层感知机,通常包含两层线性变换和一个激活函数:
FFN(x) = W_2 * ReLU(W_1 * x + b_1) + b_2
为了训练更稳定、更深入,Transformer还引入了残差连接和层归一化。
- 残差连接:将子层(如自注意力层或FFN层)的输入直接加到其输出上,即
Output = LayerNorm(x + Sublayer(x))。这有助于梯度流动,使模型易于学习恒等映射。 - 层归一化:对每个样本的所有特征维度进行归一化,使其均值为0,方差为1。这有助于稳定训练过程。



Transformer的整体架构
一个完整的Transformer层通常按以下顺序堆叠:
- 多头自注意力层(带残差连接和层归一化)
- 前馈神经网络层(带残差连接和层归一化)
“多头”注意力是指并行地运行多个自注意力机制(每个头有不同的 W_Q, W_K, W_V 矩阵),然后将所有头的输出拼接起来,再通过一个线性投影层进行融合。这允许模型同时关注来自不同表示子空间的信息。
Transformer模型可以堆叠很多层(例如GPT-3有96层)。每一层都进一步整合和抽象信息,最终输出一系列富含上下文信息的向量。
编码器-解码器架构
最初的Transformer论文《Attention Is All You Need》中描述的是一个用于机器翻译的编码器-解码器架构。
- 编码器:接收源语言句子,通过多层Transformer层进行处理,输出一系列上下文向量。这就是我们上面描述的部分。
- 解码器:用于生成目标语言句子。它的结构与编码器类似,但有三个关键区别:
- 掩码自注意力:在解码时,生成单词是一个接一个进行的。为了确保在预测第
t个单词时,模型只能看到前面t-1个已生成的单词,解码器的自注意力层使用了掩码,阻止当前位置关注未来的位置。 - 交叉注意力:在解码器的某个Transformer层中,除了自注意力子层,还插入了一个交叉注意力子层。在这里,查询向量
q来自解码器上一层的输出,而键向量k和值向量v来自编码器的最终输出。这使得解码器在生成每一个单词时,都能有选择地关注源语言句子的不同部分。 - 输出:解码器的最后一个输出向量会通过一个线性层和一个softmax层,预测词汇表中下一个单词的概率。
- 掩码自注意力:在解码时,生成单词是一个接一个进行的。为了确保在预测第
对于像GPT这样的纯解码器模型,它只使用了Transformer的解码器部分(带掩码的自注意力),并将整个任务(如文本生成)视为自回归的下一个词预测问题。

总结

本节课中我们一起学习了Transformer模型的核心原理。我们从最简单的词袋语言模型出发,指出了其词序丢失和静态词义的局限。Transformer通过引入位置编码来注入顺序信息,并通过自注意力机制让每个单词的表示能够动态地受到整个上下文的影响,从而生成上下文相关的词嵌入。模型由多头自注意力层和前馈神经网络层堆叠而成,并广泛使用残差连接和层归一化来促进深度训练。标准的Transformer采用编码器-解码器架构,其中解码器使用掩码自注意力和交叉注意力来完成序列到序列的生成任务。正是这种强大的架构,使得模型在仅训练“预测下一个词”的目标时,也能涌现出对语言和世界知识的深刻理解。
机器学习:041:DBSCAN聚类算法详解 🎯
在本节课中,我们将学习一种名为DBSCAN的聚类算法。DBSCAN是一种基于密度的聚类方法,它能够识别任意形状的簇,并能有效处理数据中的噪声点。与K均值等算法相比,DBSCAN具有独特的优势。
算法原理与参数
DBSCAN算法由Ester等人在1996年提出。它主要依赖两个参数:Epsilon (ε) 和 M。
- Epsilon (ε):一个距离常数,用于定义邻域范围。
- M:一个数量常数,用于定义核心点。
算法的第一步是构建一个基于ε的邻域图。对于数据集中的每一个点,我们以其为中心,画一个半径为ε的圆(或高维空间中的球)。所有落在这个圆内的点,都被认为是该点的“邻居”。
公式表示:点 p 的 ε-邻域 Nε(p) 定义为:
Nε(p) = { q ∈ 数据集 | distance(p, q) ≤ ε }
核心点、边界点与噪声点
在构建了邻域关系后,我们根据参数 M 来识别核心点。
核心点的定义是:如果一个点的 ε-邻域内包含至少 M 个点(包括它自己),那么这个点就是一个核心点。
代码逻辑:
if len(Nε(p)) >= M:
p 是核心点
不是核心点的数据点,则根据其与核心点的关系,被进一步分类:
- 边界点:如果一个点不是核心点,但它位于某个核心点的 ε-邻域内,那么它是一个边界点。
- 噪声点:如果一个点既不是核心点,也不是任何核心点的邻居,那么它被标记为噪声点。
聚类形成过程
识别出所有核心点后,就可以开始形成聚类簇。以下是聚类的步骤:
- 初始化:随机选择一个尚未被访问过的核心点。
- 扩展簇:
- 将该核心点分配到一个新的簇中。
- 然后,“邀请”该核心点所有 ε-邻域内的点(包括核心点和非核心点)加入这个簇。
- 对于新加入的点,如果它本身也是核心点,那么递归地将其所有邻居也“邀请”加入当前簇。
- 重复:当一个簇无法再扩展(即没有新的核心点邻居可以引入新成员)时,回到步骤1,选择另一个未访问的核心点,开始形成新的簇。
- 标记噪声:当所有核心点都被访问过后,剩余未被分配到任何簇的点,即为噪声点。
这个过程可以形象地理解为:只有“核心点”有权举办派对并邀请其所有朋友(邻居)参加。被邀请的朋友如果是核心点,他们也可以继续邀请自己的朋友。最终,所有通过这种朋友关系链连接起来的点,就形成了一个“派对”(簇)。没有被任何派对邀请的人,就是“噪声”。
算法演示与对比

为了直观理解DBSCAN的工作过程,我们可以观察它在一个人脸形状数据集上的表现。该数据集包含几个圆形簇和分散的噪声点。
当设置 M=4, ε=1 并运行DBSCAN时:
- 算法首先随机选中一个核心点,并逐步扩展,形成一个完整的圆形簇(如绿色部分)。
- 接着,它选中另一个核心点,形成第二个簇(如蓝色部分),并完美地勾勒出圆环形状。
- 这个过程持续进行,直到所有核心点都被处理,最终准确地识别出所有圆形簇,并将散布的点标记为噪声。
相比之下,如果我们对同一数据集使用K均值算法(即使预先告知它存在4个簇),结果会大不相同。K均值倾向于将空间划分为几个球形区域,完全无法捕捉到数据中固有的环形簇结构。这凸显了DBSCAN在识别非凸形状簇方面的强大能力。


总结
本节课我们一起学习了DBSCAN聚类算法。我们了解到:
- DBSCAN是一种基于密度的聚类算法,核心参数是邻域半径 ε 和最小点数 M。
- 它通过识别核心点、边界点和噪声点来工作。
- 聚类过程从核心点出发,通过密度可达关系不断扩展,能有效发现任意形状的簇,并对噪声数据不敏感。
- 与K均值等基于距离的算法相比,DBSCAN在处理复杂簇结构和噪声方面通常更具鲁棒性。

掌握DBSCAN为你提供了一种强大的工具,用于探索那些簇形状不规则或包含大量离群点的数据集。

浙公网安备 33010602011771号