查看全课大纲(第 46 / 82 节)
- 1.函数与数据泛化
- 2.向量:从几何直觉到高维空间
- 3.矩阵与张量
- 4.特征值与特征向量:矩阵变换的不动方向
- 5.凸函数:从向量求导的矩阵记号到好优化的函数形状
- 6.概率与统计:机器学习的数学基础
- 7.独立性与随机变量:贝叶斯公式与二项分布
- 8.期望、方差与协方差:随机变量的数字画像
- 9.联合概率:当一条轴不够用的时候
- 10.概率分布(一):从伯努利到伽马函数
- 11.概率分布(二):贝塔、泊松、正态与两个贝叶斯故事
- 12.机器学习的模型:找输入与输出的关系
- 13.机器学习的应用
- 14.过拟合
- 15.机器学习的分类
- 16.有监督学习:从房价预测说起
- 17.损失函数
- 18.梯度下降(上):更新规则与学习速率
- 19.梯度下降(2)
- 20.牛顿方法
- 21.KNN简介
- 22.距离测算
- 23.朴素贝叶斯
- 24.朴素贝叶斯的实际应用
- 25.信息熵:决策树构建的度量基础
- 26.信息增益与决策树的构建
- 27.ID3算法
- 28.决策树节点的划分
- 29.CART树
- 30.Bagging
- 31.Boosting:自适应提升算法
- 32.Gradient Boosting
- 33.线性模型:回归与分类的同一副骨架
- 34.最小二乘:把最优参数直接解出来
- 35.最小二乘法的几何与概率视角
- 36.极大似然:给最小二乘一个概率出身
- 37.逻辑回归(1):把线性模型接到分类上
- 38.逻辑回归(2):损失函数与多分类
- 39.---- 手造数据: 5 个样本, 2 个特征; x2 几乎 = 2*x1 (偏差手工指定, 无随机) ----
- 40.讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
- 41.优化方法(1):坐标下降与前向选择
- 42.优化方法(2):前向策略与最小角回归
- 43.拉格朗日乘子法(1):从无约束到等式约束
- 44.拉格朗日乘子法(2):等式约束下的平行条件与拉格朗日函数
- 45.拉格朗日乘子法(3):不等式约束与 KKT 条件
- 46.最大间隔:把分类问题变成优化问题
- 47.拉格朗日对偶问题:把 w 和 b 全部换成 α
- 48.支持向量:边界上的少数派
- 49.SVM 计算过程:一笔到底算完,再走进核方法
- 50.贝叶斯公式:概率即信念
- 51.隐含变量和概率模型:给看不见的原因建模
- 52.EM 算法:期望与最大化的迭代
- 53.琴生不等式:EM 的数学钥匙
- 54.三个硬币问题:EM 的复盘与衔接
- 55.高斯混合模型:用隐变量解释双峰数据
- 56.隐马尔可夫模型
- 57.隐马尔可夫模型(2):前向算法与动态混合模型
- 58.隐马尔可夫模型在 NLP 中的运用
- 59.EM 算法:把「为什么收敛」推到底
- 60.HMM 在 NLP 中的运用:从分词到机器翻译
- 61.HMM 参数估计:Baum-Welch 的三块拉格朗日
- 62.高维下的高斯模型
- 63.主题模型:从词袋到隐含主题
- 64.Dirichlet 分布(1)
- 65.Dirichlet 分布(2)
- 66.统计学习内容回顾
- 67.K-means 算法
- 68.PCA 降维
- 69.SVD 降维
- 70.从聚类到流形
- 71.局部线性嵌入
- 72.随机邻域嵌入:SNE 与 t-SNE
- 73.无参模型:让数据自己说话
- 74.高斯过程:函数空间里的正态分布
- 75.高斯过程(2):噪声、正则化与核的线性组合
- 76.神经网络简介:从感知器到自编码器
- 77.反向传播:把误差一层层传回去
- 78.卷积神经网络(CNN):让特征自己学出来
- 79.循环神经网络(RNN):给网络装上记忆
- 80.深度学习回顾:静态一类,动态一类
- 81.增强学习(1):蒙特卡洛、树搜索与 Q-learning
- 82.强化学习(2):从乌鸦吃核桃到井字棋的 value 回传
最大间隔:把分类问题变成优化问题
约 28 分钟
小象实战讲义 · 机器学习算法精讲
前三节把拉格朗日乘子法从头到尾搭了一遍——等式约束、不等式约束、KKT 条件。为什么花这么大力气做这件事?讲师开宗明义:我们所有构造的这些问题,就是为了下面的实际情况。这个”实际情况”就是 SVM(支持向量机)的核心思想——最大间隔(Max Margin)。这一节会看到:一堆数据点要分成两类,能分开的线有无数条,怎么从数学上挑出”最好的那一条”——最后把它变成一个刚好能用上一节工具的优化问题。
💡 核心导读
- 换一种写法:直线方程从 换成 SVM 惯例的 ;向量 恰好是这条线的法向量。
- 聪明的构造:标签取 (不用 ),于是 一个乘积就能判断分对分错——正正得正、负负得正。
- 等比缩放:把离线最近的点放到 两条边界线上,分类条件强化成 。
- 间距公式:两条边界线之间的距离 ——间距最大,等价于 最小。
- 落地: s.t. ——上一节准备好的不等式优化工具,马上用上。
先把直线的方程换一种写法
在高维空间里把数据分成两类的时候,经常会出现这样的情况:同时满足条件的线不止一条。线的上面是一个区域、下面是一个区域,任何一条能把两类点各归各区的线都算数。所以第一步,先把线的方程重新描述一下。
我们以前用的表示方法是 。从今天起换一种结构,写成:
(讲师的说法:“以前我们用 和 ,现在因为 SVM 都用这个系数表示,那我们也用这个”——大部分书也用 代表权重。这个写法的实质,是把输入和输出都放进同一个向量里,让这组向量满足一个等于零的关系。) 大于 0,代表线上面那部分区域;小于 0,代表下面那部分;等于 0,就是中间这条线本身。
拿一个具体例子换算一遍。:令 得 、令 得 ,两点一画,这条红线就出来了。把它改写成等于零的形式:
这里藏着一个非常重要的几何事实: 这个向量,垂直于这条线。拿线的方向向量 来验:,点积为零,垂直。再换一条线试试: 改写成 ,,与这条线的方向 点积 ——仍然垂直。(同一条线的方程整体乘 , 跟着反向,垂直关系不变——上一节 与 的老提醒。)
一句话确认:线性函数 里, 代表这条线的法线方向。二维里它是一条线;到了高维空间,就是高维空间里的一个”面”——超平面(Hyperplane):二维是线、三维是面、更高维统称超平面。
用一个乘积判断分对还是分错
数据还是老样子:, 属于 维的高维空间; 是二分类的标签。这里有一个刻意的约定:不用 ,用 代表两类——为什么这么换,马上就能看到。
给定一个 ,拿 一算:大于 0,预测 ;小于 0,预测 。那某个 到底被分对了还是分错了?讲师构造了一个非常聪明的函数:
只看这个乘积的符号:大于 0,分对了(correctly classified);小于 0,分错了(wrong classified)。道理就藏在 里:如果 (预测 )而真实的 恰好也是 ,正正得正;如果 (预测 )而 ,负负得正——只要分对,乘积必是正的;分错,一正一负,乘积必是负的。这就是标签用 而不用 的原因:换上这套标签,“分对分错”才装得进一个乘积里。
于是回到开场的局面:能把这些点完整分成两部分的线,经常有多种可能——讲师在黑板上画了 A、B、C 三条线,每一条都能完美地分开。那问题自然来了:既然都能满足条件,怎么去选择一个最好的线?这就是我们接下来要构造的具体问题。
最大的边界:把最近的点放到 ±1 上
讲师的板书是四个点:两个黄色点是一类,两个绿色点是一类。要找一条 ,使两类之间的间距(margin)最大——注意一个细节:每一个类别,都至少有一个数据落在这个边界之上。从直觉上看,有最大边界的那条线,就是最好的线;在中间随便再画一条别的线,肯定不如它。
那怎么把”间距”变成能算的东西?先解决一个尺度问题。任何一个点,只要在线上面, 就大于 0;在线下面,就小于 0——但这个值本身可大可小。而优化间距的时候,这个距离无论多大、多小,都可以整同比地进行放缩:把 和 一起乘上同一个常数,线本身不动(上下的区域划分完全不变),变的只是函数值的刻度。那就干脆把刻度定死——让离线最近的那些点,恰好落在 这两条线上。
于是画面变成三条平行线: 一条、 一条、 在正中间。分类条件跟着强化:
含义是:所有的数据,要么恰好在这两条边界线上,要么在边界线之外——不但分对,还要离分界线有一段安全距离。
间距到底有多大
现在算这两条边界线之间的距离。设间距对应的位移是 :从下边界上的一个点 出发,沿着 的方向(上一节刚确认过, 就是这条线的法线方向)走一段,落到上边界的点 上:
两个点各自身在边界上,所以:
把 代入第二个式子并展开:
第一项和第三项合起来正是 ,代入:
( 就是 的模的平方。)而间距本身就是这个位移向量的模:
间距 ,每一侧的半间距是 。 越大,间距越小; 越小,间距越大。
方法论旁注:很多书(包括不同人讲的课)算间距用的是”点到直线的距离”——那也是可以的;但讲师自己的路数是上面这个”从一个边界点沿 走到另一个边界点”的构造,他自己觉得这种方式更容易理解一点。
拿 (即 ,、)把这套推导数值过一遍:
# ---- 讲师的间距推导: 数值验证 margin = 2/||w|| ----
# 直线 y = 2x + 3, 即 2x - y + 3 = 0: w = (2, -1), b = 3
import math
w1, w2, b = 2.0, -1.0, 3.0
norm = math.sqrt(w1 ** 2 + w2 ** 2)
print(f"直线 2x - y + 3 = 0: w = (2, -1), b = 3, ||w|| = {norm:.4f}")
print(f"法向量检查: w·(1,2) = {w1*1.0 + w2*2.0:.1f} (方向 (1,2) 是直线方向, 点积为零 -> 垂直)")
print()
x1 = (0.0, 4.0)
print(f"下边界点 x1 = (0, 4): w^T x1 + b = {w1*x1[0] + w2*x1[1] + b:.1f} (应为 -1)")
lam = 2.0 / (norm ** 2)
x2 = (x1[0] + lam * w1, x1[1] + lam * w2)
print(f"lambda = 2/||w||^2 = 2/{norm**2:.0f} = {lam:.1f}")
print(f"上边界点 x2 = x1 + lambda*w = ({x2[0]:.4f}, {x2[1]:.4f}): w^T x2 + b = {w1*x2[0] + w2*x2[1] + b:.4f} (应为 +1)")
print()
d = math.sqrt((x2[0]-x1[0])**2 + (x2[1]-x1[1])**2)
print(f"间距 = |x2 - x1| = {d:.4f}")
print(f" = lambda*||w|| = {lam:.1f} * {norm:.4f} = {lam*norm:.4f} (= 2/||w||)")
print(f"半间距 = 1/||w|| = {1.0/norm:.4f}")直线 2x - y + 3 = 0: w = (2, -1), b = 3, ||w|| = 2.2361
法向量检查: w·(1,2) = 0.0 (方向 (1,2) 是直线方向, 点积为零 -> 垂直)
下边界点 x1 = (0, 4): w^T x1 + b = -1.0 (应为 -1)
lambda = 2/||w||^2 = 2/5 = 0.4
上边界点 x2 = x1 + lambda*w = (0.8000, 3.6000): w^T x2 + b = 1.0000 (应为 +1)
间距 = |x2 - x1| = 0.8944
= lambda*||w|| = 0.4 * 2.2361 = 0.8944 (= 2/||w||)
半间距 = 1/||w|| = 0.4472位移一步到位: 贴在下边界(),沿 一走, 精确落在上边界(,分毫不差)。间距两种算法——直接量 、或者 ——都得到 。
把分类问题变成优化问题
有了 ,开场的 A/B/C 之问就可以量化回答了——三条线都能分开同一组点,但各自的间距不同:
# ---- 三条线都能分开, 哪条最好? 算 margin ----
# 板书例: 黄色 +1 类两点, 绿色 -1 类两点
import math
pts = [((1.0, 2.0), +1), ((2.0, 1.0), +1), # 黄色
((3.0, 4.0), -1), ((4.0, 3.0), -1)] # 绿色
def margin_of(w1, w2, b, name):
# 1) 先验证: 所有点都被分开 (y_i * (w^T x + b) > 0)
scores = []
for (x1, x2), y in pts:
s = y * (w1 * x1 + w2 * x2 + b)
scores.append(s)
ok = all(s > 0 for s in scores)
# 2) 等比缩放: 把最近的点 (得分最小) 放到 1 上
m = min(scores)
w1s, w2s, bs = w1 / m, w2 / m, b / m
norm = math.sqrt(w1s ** 2 + w2s ** 2)
margin = 2.0 / norm
print(f"线 {name}: w=({w1:.0f},{w2:.0f}), b={b:.0f} -> 全部分对: {ok}, "
f"最近点得分 {m:.0f} -> 缩放后 ||w||={norm:.4f}, margin=2/||w||={margin:.4f}")
return margin
print("黄色 +1: (1,2), (2,1); 绿色 -1: (3,4), (4,3)")
print()
mA = margin_of(-1.0, -1.0, 5.0, "A(居中)")
mB = margin_of(-1.0, -1.0, 4.0, "B(偏一侧)")
mC = margin_of(-1.0, -2.0, 6.0, "C(斜着)")
print()
print(f"margin 对比: A={mA:.4f} > B={mB:.4f} > C={mC:.4f}")
print("三条线都能把两类完美分开, 但 A 的间距最大 —— 直觉上'中间那条'最好")黄色 +1: (1,2), (2,1); 绿色 -1: (3,4), (4,3)
线 A(居中): w=(-1,-1), b=5 -> 全部分对: True, 最近点得分 2 -> 缩放后 ||w||=0.7071, margin=2/||w||=2.8284
线 B(偏一侧): w=(-1,-1), b=4 -> 全部分对: True, 最近点得分 1 -> 缩放后 ||w||=1.4142, margin=2/||w||=1.4142
线 C(斜着): w=(-1,-2), b=6 -> 全部分对: True, 最近点得分 1 -> 缩放后 ||w||=2.2361, margin=2/||w||=0.8944
margin 对比: A=2.8284 > B=1.4142 > C=0.8944
三条线都能把两类完美分开, 但 A 的间距最大 —— 直觉上'中间那条'最好三条线全都把两类完美分开(每一行都先验了”全部分对: True”),但 A 的间距 最大——直觉在此兑现成数字。所以整个问题变成:在所有能把数据分开的线里,找间距最大的那条。两个条件写在一起:
- 约束:所有数据被正确分类、且在边界之外——();
- 目标:间距最大——。
最大化 ,等价于最小化 ,也等价于最小化 (乘常数、取平方都不改变最优解的位置;带上 是让后面求导干净)。这就是大家最常用的、SVM 所要优化的函数:
一个机器学习的分类问题,就这样变成了一个完整的优化问题。而且它的约束恰好是不等式——上一节刚准备好的工具马上能用。把约束挪成标准形式 :
按上一节的办法构造拉格朗日函数(关于 和一串乘子的函数):
(乘子这里不用 了——SVM 的惯例记号是 ,讲师顺势换了名字:“我们也就换个名叫 ”。)接下来怎么解?对 求导、同时对所有的 求导,置零——注意 是一个向量,“等于零”是等于一串零(每个分量都是零)。具体怎么解,下一节详细展开;这里先埋一个钩子: 的时候是什么情况? 的时候又是什么情况?——它们都能精确地对应回分类问题本身,下一章揭晓。
讲师的收尾把这三讲串成了一句完整的话:从数学的根子上、最底层,了解整个优化——尤其是带限制条件的优化,分等式的和不等式的,中间给的是特别清晰的几何例子;而机器学习里的最大边界问题,通过刚才构造出来的边界,变成了一个完整的优化问题;优化问题怎么解?通过拉格朗日乘子去解。下一节课,就把这两点结合到一起。
📝 动手练一练
- ±1 的用意:为什么二分类标签要用 而不是 ?请用”判断分对分错”的那个乘积构造说明。如果用 ,这个构造还成立吗?
👉 点击查看参考答案
用 :分对时,预测值与标签同号—— 且 (正正得正),或 且 (负负得正),乘积 恒为正;分错时一正一负,乘积恒为负。一个乘积就把”分对/分错”装了进去,还顺手长成了 的约束形式。
如果用 :标签为 时无论预测是什么,乘积永远是 ——符号信息全丢,“分对分错”装不进乘积里。 是让”符号对上符号”成立的最小改动。
- 手算间距:设 、。(1) 两条边界线 之间的间距是多少?(2) 下边界上有一点 ,求 ;(3) 按讲师的构造求 、算出 ,并验证 。
👉 点击查看参考答案
(1) ,间距 (半间距 )。
(2) ,即 。
(3) ;。验证:,恰好 。间距自检:,与 严格一致。
本章小结
- 方程换装: 换成 (SVM 惯例记号); 是法向量、垂直于这条线;高维空间里线推广为超平面(Hyperplane)。
- 聪明构造:标签 , 分对、 分错——正正得正、负负得正。
- 等比缩放:、 同乘常数,线与区域划分不变;把最近的点放到 边界上,条件强化为 ——要么在线上,要么在线外。
- 间距公式:、 ⟹ margin ,半间距 ;A/B/C 三条能分开的线里,间距最大的是”中间那条”。
- 优化落地: s.t. ;约束改写成 后,拉格朗日函数 ——对 (等于一串零)与所有 求导置零,下一节解。
- 埋钩: 与 各对应什么情况,能精确对应回分类问题——下一章揭晓。
📋 行动清单
- 把 改写成 的形式,写出 ,并验证 与线方向垂直
- 自己重推一遍 ,再用 手算间距
- 跑代码块一,把 C 线换成自己设计的一条”歪线”,看 margin 如何进一步变小
- 用一句话说清:为什么等比缩放之后,“分对”可以升级成””
- 预习下一节《拉格朗日对偶问题》—— 怎么解、 的零与非零意味着什么,都在那里展开
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。