
Hidden Markov Model (HMM) —— 隐马尔可夫模型
系统讲解隐马尔可夫模型(HMM)的完整数学原理与三大核心算法:从马尔可夫链到双重随机过程的演进出发,定义HMM的五元组参数(Q, V, π, A, B);详细推导估值问题、解码问题和学习问题;并通过词性标注、语音识别等经典应用场景展示HMM的实践价值。
阅读文章ZHY's Blog
A UNIVERSE OF IDEAS · BY ZHANG HAOYI
让好奇心 点亮知识宇宙
在代码、模型与思想之间自由漫游。这里持续记录人工智能、机器学习、软件工程与成长实践,让每次阅读都成为一次新的发现。
ARTICLE NOTE
上一篇文章中,我们详细讨论了 AdaBoost —— 它通过“错题本”机制串行地组合弱分类器,用指数损失函数和前向分步加法模型给出了 Boosting 思想的第一个优雅实现。但 AdaBoost 的适用性受限于两个因素:其一是指数损失对异常值过于敏感,其二是其推导高度依赖于分类问题的特定形式,难以直接推广到回归任务或自定义损失场景。
梯度提升机(Gradient Boosting Machine, GBM) 由 Jerome Friedman 于 1999 年提出,是 Boosting 家族从“具体算法”迈向“通用框架”的关键一步。其核心突破可以概括为一句话:将 AdaBoost 的“解析优化”升级为“函数空间中的梯度下降” —— 无论损失函数是什么,只要它是可微的,GBM 都能用统一的框架处理。每一轮迭代中,新树的目标不再是拟合指数损失的解析解,而是拟合前一轮模型损失函数的负梯度。这个“负梯度”在不同的损失函数下有不同的形态:平方损失下它就是残差,绝对损失下它是符号函数,对数损失下它是概率误差 —— 但框架本身不改变。
在偏差-方差分解的视角下,GBM 与随机森林形成了鲜明的互补:随机森林通过并行平均降低方差,GBM 通过串行纠错降低偏差。这种特质让 GBM 在追求极致精度的场景中表现出色,但也使其对异常值和噪声更为敏感 —— 平方损失下的大残差会被串行迭代不断放大。
本文将从加法模型与前向分步算法出发,完整推导 GBM 的数学框架,并通过偏差-方差分解对比其与随机森林的本质差异,最后分析其对异常值敏感的根本原因与缓解策略(鲁棒损失函数、学习率、子采样)。
Note读完本文,你将理解 GBM 为何能成为现代机器学习竞赛中最具统治力的算法范式之一。
而 GBM 的通用框架——任意可微损失 + 函数空间梯度下降——正是理解后续 XGBoost 与 LightGBM 工程优化的理论基础:它们在保留 GBM 核心逻辑的同时,引入了二阶导数、正则化、直方图近似等关键改进,将“通用框架”推进为“工业级实现”。
Boosting类算法(包括AdaBoost和GBM)都可以统一描述为加法模型(Additive Model) :最终模型由多个基函数的加权和组成。
数学上,加法模型的形式为:
f(x)=m=1∑Mβmb(x;γm)其中:
在给定训练数据 T={(x1,y1),(x2,y2),...,(xN,yN)} 和损失函数 L(y,f(x)) 的条件下,学习加法模型 f(x) 就变成了一个经验风险极小化问题:
βm,γmmini=1∑NL(yi,m=1∑Mβmb(xi;γm))这是一个极其复杂的优化问题 —— 我们需要同时优化所有基函数的参数和权重。当 M 较大时,直接求解几乎是不可能的。
前向分步算法(Forward Stagewise Algorithm) 是解决上述问题的巧妙策略。其核心思想是从前向后,每一步只学习一个基函数及其系数,逐步逼近目标函数。
具体来说,在第 m 步,我们固定前 m−1 个基函数不变,只优化第 m 个:
(βm,γm)=argβ,γmini=1∑NL(yi,fm−1(xi)+βb(xi;γ))其中 fm−1(x)=∑j=1m−1βjb(x;γj) 是前 m−1 步已经得到的模型。
更新模型:
fm(x)=fm−1(x)+βmb(x;γm)前向分步算法的完整流程如下:
输入:训练数据集 T,损失函数 L,基函数集合 {b(x;γ)}
输出:加法模型 f(x)
算法步骤:
算法优势:前向分步算法将一个复杂的全局优化问题,分解为 M 个相对简单的局部优化问题,每一步只需优化一个基函数的参数 (β,γ),极大地降低了计算复杂度。
前向分步算法虽然思路清晰,但每一步仍然需要求解一个优化问题:
β,γmini=1∑NL(yi,fm−1(xi)+βb(xi;γ))对于任意损失函数 L,这个优化问题可能仍然很困难。特别是当损失函数不是平方损失或指数损失时,没有简单的解析解。
梯度提升(Gradient Boosting) 的核心贡献就在于:它用“拟合负梯度”代替了“直接优化损失函数” ,从而将前向分步算法推广到了任意可微损失函数。
要理解GBM为什么“拟合负梯度”,我们需要跳出参数空间,进入函数空间。
参数空间的梯度下降:
在传统的参数优化中,我们最小化损失函数 L(θ),参数更新公式为:
θ=θ−α⋅∂θ∂L(θ)函数空间的梯度下降:
在GBM中,我们把函数 f(x) 本身当作优化变量。在第 m 步,前 m−1 个基函数已经固定,即 fm−1(x) 已知。我们的目标是最小化:
L(f)=i=1∑NL(yi,fm(xi))其中 fm(x)=fm−1(x)+βmhm(x)。
如果我们把 f(x) 当作“参数”,用梯度下降的思路来更新:
fm(x)=fm−1(x)−ρm⋅∂f(x)∂L(y,f(x))f=fm−1关键点:对比 fm(x)=fm−1(x)+βmhm(x) 和上面的梯度下降更新式,可以发现:
hm(x)≈−∂fm−1(x)∂L(y,fm−1(x))也就是说,第 m 棵树的训练目标,就是去拟合前一轮模型损失函数的负梯度。这就是GBM中 “拟合负梯度” 的完整数学推导。
负梯度也被称为 “伪残差(Pseudo Residual)” 。
当损失函数是平方损失 L(y,f)=21(y−f)2 时:−∂f∂L=y−f=残差,此时GBM退化为拟合残差 —— 每一棵树学习的是“真实值与当前预测值的差”。
当损失函数是绝对损失 L(y,f)=∣y−f∣ 时,负梯度是 sign(y−f) ——只告诉新树“方向”,不告诉“幅度”。
当损失函数是对数损失(分类任务)时,负梯度是概率误差。
直观理解:残差 y−f(x) 越大,说明前一轮模型 f(x) 与真实值 y 相差越大。下一轮学习器通过拟合残差(或更一般地,负梯度),就能重点纠正前一轮犯错较大的地方。
输入:训练集 {(xi,yi)}i=1N,可微损失函数 L(y,f(x)),迭代次数 M
输出:最终模型 fM(x)
算法步骤:
步骤1:初始化 —— 用一个常数 γ 来初始化模型。对于平方损失,γ 就是所有 yi 的均值。
f0(x)=argγmini=1∑NL(yi,γ)步骤2:对 m=1,2,...,M 迭代
(a) 计算负梯度(伪残差) :
rim=−[∂f(xi)∂L(yi,f(xi))]f=fm−1,i=1,2,...,N(b) 用基学习器(通常是CART回归树)拟合负梯度:
训练一棵回归树,以 {xi} 为输入,{rim} 为目标值,得到第 m 棵树的叶节点区域 {Rjm}j=1Jm。
(c) 计算每个叶节点的最优输出值:
γjm=argγminxi∈Rjm∑L(yi,fm−1(xi)+γ)(d) 更新模型:
fm(x)=fm−1(x)+νj=1∑Jmγjm⋅I(x∈Rjm)其中 ν∈(0,1] 是学习率(Learning Rate) ,也叫收缩系数(Shrinkage) ,用于控制每棵树的贡献,防止过拟合。
步骤3:输出最终模型 fM(x)。
代码实现:
1import numpy as np2from sklearn.tree import DecisionTreeRegressor3
4class GradientBoostingRegressor:5 """从零实现梯度提升回归器"""6
7 def __init__(self, n_estimators=100, learning_rate=0.1, max_depth=3):8 self.n_estimators = n_estimators9 self.learning_rate = learning_rate10 self.max_depth = max_depth11 self.trees = []12 self.initial_pred = None13
14 def fit(self, X, y):15 # 步骤1:初始化16 self.initial_pred = np.mean(y)17 f = np.full(len(y), self.initial_pred)18
19 # 步骤2:迭代M轮20 for _ in range(self.n_estimators):21 # (a) 计算负梯度(对于平方损失,负梯度 = y - f)22 residuals = y - f23
24 # (b) 用决策树拟合残差25 tree = DecisionTreeRegressor(max_depth=self.max_depth)26 tree.fit(X, residuals)27 self.trees.append(tree)28
29 # (c) 更新预测(学习率控制步长)30 f += self.learning_rate * tree.predict(X)31
32 return self33
34 def predict(self, X):35 f = np.full(len(X), self.initial_pred)36 for tree in self.trees:37 f += self.learning_rate * tree.predict(X)38 return f39
40# 示例:拟合正弦函数41np.random.seed(42)42X = np.linspace(0, 10, 100).reshape(-1, 1)43y = np.sin(X).ravel() + 0.1 * np.random.randn(100)44
45gbm = GradientBoostingRegressor(n_estimators=50, learning_rate=0.1, max_depth=3)46gbm.fit(X, y)47y_pred = gbm.predict(X)48
49print(f"训练集MSE: {np.mean((y - y_pred) ** 2):.4f}")对于二分类问题,GBM使用对数损失(Log Loss) :
L(y,f(x))=log(1+e−yf(x)),y∈{−1,+1}负梯度为:
rim=1+eyifm−1(xi)yi其余步骤与回归任务相同。最终通过 sign(fM(x)) 做出分类决策。
在机器学习中,泛化误差可以分解为三个部分:
Error=Bias2+Variance+Noise随机森林通过并行构建多棵独立树并平均它们的预测来降低方差。
在之前的文章中我们推导过:如果 m 棵树之间的相关性为 ρ,单棵树的方差为 σ2,则平均预测的方差为:
Var(RF)=ρσ2+m1−ρσ2当 m→∞ 时,方差趋近于 ρσ2。
随机森林通过行采样(Bootstrap) 和列采样(特征子空间) 来降低 ρ,从而进一步降低方差。
随机森林的本质 —— 通过“平均”来平滑掉单棵树的噪声,降低方差。
GBM则走了完全不同的路径。它通过串行地拟合残差(负梯度) ,每一轮都在修正前一轮的错误。
从偏差-方差的角度来看:随机森林降低方差,GBM降低偏差。
GBM的本质 —— 通过“持续纠错”来逼近真实函数,降低偏差。
这解释了为什么随机森林在噪声数据上更稳健,不容易过拟合;而GBM在干净数据上通常能达到更高的精度,但需要精细调参。
| 对比维度 | 随机森林 | GBM |
|---|---|---|
| 构建方式 | 并行构建独立树 | 串行构建依赖树 |
| 核心目标 | 降低方差 | 降低偏差 |
| 树的特点 | 完全生长的深树 | 浅层弱学习器 |
| 过拟合风险 | 较低(内置正则化) | 较高(需精细调参) |
| 训练速度 | 快(可并行) | 慢(需串行) |
| 对噪声敏感度 | 低 | 高 |
| 适用场景 | 快速原型、噪声数据 | 追求极致精度 |
GBM对异常值的敏感性源于其 “串行纠错” 的机制。
原因一:平方损失放大了异常值的影响
原因二:串行传播放大了异常值的影响
方法一:使用鲁棒的损失函数
方法二:降低学习率:较小的学习率意味着每棵树的贡献更小,模型更新更“谨慎”,从而降低了异常值的影响。
方法三:子采样(Subsampling):在每次迭代中,只使用部分样本(如80%)来训练树。这可以降低异常值被选中的概率,类似于随机森林的行采样思想。
方法四:使用XGBoost/LightGBM等现代实现:这些实现内置了L1/L2正则化,可以有效控制模型的复杂度,减轻异常值的影响。
代码实现:
1from sklearn.ensemble import GradientBoostingRegressor2from sklearn.datasets import make_regression3import numpy as np4
5# 生成数据并加入异常值6X, y = make_regression(n_samples=200, n_features=5, noise=10, random_state=42)7y[0] = y[0] * 10 # 制造一个异常值8
9# 使用平方损失(默认)10gbm_mse = GradientBoostingRegressor(loss='squared_error', n_estimators=100,11 learning_rate=0.1, random_state=42)12gbm_mse.fit(X, y)13
14# 使用Huber损失(对异常值更鲁棒)15gbm_huber = GradientBoostingRegressor(loss='huber', n_estimators=100,16 learning_rate=0.1, random_state=42)17gbm_huber.fit(X, y)18
19print(f"MSE损失模型在异常值样本上的预测: {gbm_mse.predict([X[0]])[0]:.2f}")20print(f"Huber损失模型在异常值样本上的预测: {gbm_huber.predict([X[0]])[0]:.2f}")21print(f"真实值: {y[0]:.2f}")22# Huber损失通常能更好地抵抗异常值的影响1import numpy as np2import matplotlib.pyplot as plt3from sklearn.ensemble import GradientBoostingRegressor4from sklearn.model_selection import train_test_split5from sklearn.metrics import mean_squared_error6
7# 1. 生成非线性数据8np.random.seed(42)9X = np.linspace(0, 10, 300).reshape(-1, 1)10y = np.sin(X).ravel() + 0.3 * np.random.randn(300)11# 加入异常值12y[0] = 5.013y[10] = -4.014
15X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)16
17# 2. 训练不同参数的GBM18results = {}19for lr in [0.01, 0.1, 0.5]:20 for depth in [2, 4, 6]:21 gbm = GradientBoostingRegressor(22 n_estimators=100,23 learning_rate=lr,24 max_depth=depth,25 random_state=4226 )27 gbm.fit(X_train, y_train)28 y_pred = gbm.predict(X_test)29 mse = mean_squared_error(y_test, y_pred)30 results[(lr, depth)] = mse31 print(f"lr={lr:.2f}, depth={depth}: MSE={mse:.4f}")32
33# 3. 可视化最佳模型34best_params = min(results, key=results.get)35best_gbm = GradientBoostingRegressor(36 n_estimators=100,37 learning_rate=best_params[0],38 max_depth=best_params[1],39 random_state=4240)41best_gbm.fit(X_train, y_train)42
43X_plot = np.linspace(0, 10, 200).reshape(-1, 1)44y_plot = best_gbm.predict(X_plot)45
46plt.figure(figsize=(10, 6))47plt.scatter(X_train, y_train, alpha=0.5, label='训练集')48plt.scatter(X_test, y_test, alpha=0.5, label='测试集')49plt.plot(X_plot, y_plot, 'r-', linewidth=2, label='GBM预测')50plt.xlabel('X')51plt.ylabel('y')52plt.legend()53plt.title(f'GBM: lr={best_params[0]}, depth={best_params[1]}')54plt.show()总结
概念 核心内容 加法模型 f(x)=∑βmb(x;γm),Boosting家族的通用框架 前向分步算法 从前向后,每一步只优化一个基函数 GBM的核心思想 用基学习器拟合前一轮损失函数的负梯度 函数空间梯度下降 将 f(x) 本身当作优化变量,在函数空间中做梯度下降 伪残差 负梯度的别名,是 “残差”在任意损失函数下的推广 GBM vs 随机森林 GBM降低偏差,随机森林降低方差 异常值敏感性 平方损失放大异常值影响,串行机制放大偏差 缓解方法 鲁棒损失函数、降低学习率、子采样、正则化 核心要点回顾
- 加法模型 + 前向分步算法是Boosting家族的通用框架。前向分步将复杂的全局优化转化为 M 个简单的局部优化。
- GBM的核心创新在于:用 “拟合负梯度” 代替了 “直接优化损失函数” ,从而将Boosting推广到了任意可微损失函数。负梯度是“残差”在任意损失函数下的推广。
- 函数空间的梯度下降是理解GBM的关键视角——我们把 f(x) 本身当作优化变量,每一轮都在函数空间中沿着负梯度方向走一小步。
- GBM vs 随机森林:随机森林通过并行平均降低方差,GBM通过串行纠错降低偏差。随机森林 “安全” ,GBM “锋利” 。
- GBM对异常值敏感的根本原因在于:平方损失放大异常值的影响,而串行机制会把这个影响在后续迭代中不断放大。可以通过Huber损失、降低学习率、子采样和正则化来缓解。
按顺序完成这组文章,循序渐进地掌握主题
发现错误、内容过时或有改进想法?欢迎告诉我
根据本文分类与标签,为你推荐可能感兴趣的内容

系统讲解隐马尔可夫模型(HMM)的完整数学原理与三大核心算法:从马尔可夫链到双重随机过程的演进出发,定义HMM的五元组参数(Q, V, π, A, B);详细推导估值问题、解码问题和学习问题;并通过词性标注、语音识别等经典应用场景展示HMM的实践价值。
阅读文章
系统讲解期望最大化(EM)算法的完整数学原理:从极大似然估计在隐变量存在时的困境出发,推导E步与M步的迭代框架;基于Jensen不等式证明ELBO证据下界与收敛性;通过二硬币模型与高斯混合模型(GMM)两个完整实例展示EM的具体计算流程;揭示K-Means是EM在硬分配下的特例这一深层联系。
阅读文章
系统讲解K-Means聚类的核心原理与算法细节,涵盖Lloyd交替优化算法的收敛性分析、K-Means作为EM算法特例的理论联系(硬分配 vs 软分配)、K-Means++初始化策略的D²采样机制与O(log K)近似保证,以及肘部法则与轮廓系数的选择K值方法及其局限。
阅读文章请使用微信扫描二维码分享
当前文章会保持在原页面