集成学习之Boosting —— AdaBoost原理

集成学习之Boosting —— AdaBoost实现

集成学习之Boosting —— Gradient Boosting原理

集成学习之Boosting —— Gradient Boosting实现

上一篇介绍了AdaBoost算法,AdaBoost每一轮基学习器训练过后都会更新样本权重,再训练下一个学习器,最后将所有的基学习器加权组合。AdaBoost使用的是指数损失,这个损失函数的缺点是对于异常点非常敏感,(关于各种损失函数可见之前的文章: 常见回归和分类损失函数比较),因而通常在噪音比较多的数据集上表现不佳。Gradient Boosting在这方面进行了改进,使得可以使用任何损失函数 (只要损失函数是连续可导的),这样一些比较robust的损失函数就能得以应用,使模型抗噪音能力更强。

Boosting的基本思想是通过某种方式使得每一轮基学习器在训练过程中更加关注上一轮学习错误的样本,区别在于是采用何种方式?AdaBoost采用的是增加上一轮学习错误样本的权重的策略,而在Gradient Boosting中则将负梯度作为上一轮基学习器犯错的衡量指标,在下一轮学习中通过拟合负梯度来纠正上一轮犯的错误。这里的关键问题是:为什么通过拟合负梯度就能纠正上一轮的错误了?Gradient Boosting的发明者给出的答案是:函数空间的梯度下降。

函数空间的的梯度下降

这里首先回顾一下梯度下降 (Gradient Descend)。机器学习的一大主要步骤是通过优化方法最小化损失函数\(L(\theta)\),进而求出对应的参数\(\theta\)。梯度下降是经典的数值优化方法,其参数更新公式:

\[ \theta = \theta - \alpha \cdot \frac{\partial}{\partial \theta}L(\theta) \tag{1.1}\]

Gradient Boosting 采用和AdaBoost同样的加法模型,在第m次迭代中,前m-1个基学习器都是固定的,即\[f_m(x) = f_{m-1}(x) + \rho_m h_m(x) \tag{1.2}\]

因而在第m步我们的目标是最小化损失函数 \(L(f) = \sum\limits_{i=1}^NL(y_i,f_m(x_i))\),进而求得相应的基学习器。若将\(f(x)\)当成参数,则同样可以使用梯度下降法:

\[f_m(x) = f_{m-1}(x) - \rho_m \cdot \frac{\partial}{\partial f_{m-1}(x)}L(y,f_{m-1}(x)) \tag{1.3}\]

对比式 (1.2)和 (1.3),可以发现若将\(h_m(x) \approx -\frac{\partial L(y,f_{m-1}(x))}{\partial f_{m-1}(x)}\),即用基学习器\(h_m(x)\)拟合前一轮模型损失函数的负梯度,就是通过梯度下降法最小化\(L(f)\) 。由于\(f(x)\)实际为函数,所以该方法被认为是函数空间的梯度下降。


负梯度也被称为“响应 (response)”或“伪残差 (pseudo residual)”,从名字可以看出是一个与残差接近的概念。直觉上来看,残差\(r = y-f(x)\)越大,表明前一轮学习器\(f(x)\)的结果与真实值\(y\)相差较大,那么下一轮学习器通过拟合残差或负梯度,就能纠正之前的学习器犯错较大的地方。

Gradient Boosting算法流程

  1. 初始化: \(f_0(x) = \mathop{\arg\min}\limits_\gamma \sum\limits_{i=1}^N L(y_i, \gamma)\)

  2. for m=1 to M:
    (a) 计算负梯度: \(\tilde{y}_i = -\frac{\partial L(y_i,f_{m-1}(x_i))}{\partial f_{m-1}(x_i)}, \qquad i = 1,2 \cdots N\)
    (b) 通过最小化平方误差,用基学习器\(h_m(x)\)拟合\(\tilde{y_i}\),\(w_m = \mathop{\arg\min}\limits_w \sum\limits_{i=1}^{N} \left[\tilde{y}_i - h_m(x_i\,;\,w) \right]^2\)
    (c) 使用line search确定步长\(\rho_m\),以使\(L\)最小,\(\rho_m = \mathop{\arg\min}\limits_{\rho} \sum\limits_{i=1}^{N} L(y_i,f_{m-1}(x_i) + \rho h_m(x_i\,;\,w_m))\)
    (d) \(f_m(x) = f_{m-1}(x) + \rho_m h_m(x\,;\,w_m)\)
  3. 输出\(f_M(x)\)

回归提升树

在Gradient Boosting框架中,最常用的基学习器是决策树 (一般是CART),二者结合就成了著名的梯度提升树 (Gradient Boosting Decision Tree, GBDT)算法。下面先叙述回归问题,再叙述分类问题。注意GBDT不论是用于回归还是分类,其基学习器 (即单颗决策树) 都是回归树,即使是分类问题也是将最后的预测值映射为概率。

决策树可以看作是一个分段函数,将特征空间划分为多个独立区域,在每个区域预测一个常数,如下图所示:

因此单棵决策树可表示为 \(h(x\,;\,\left \{R_j,b_j \right \}_1^J) = \sum \limits_{j=1}^J b_j I(x \in R_j)\),其中\(\left \{R_j \right \}_1^J\)为划分出来的独立区域 (即各个叶结点),\(\left \{ b_j \right \}_1^J\)为各区域上的输出值。为了求出这两个参数,于是上面Gradient Boosting中的2.b步变为:
​ \[\left \{ R_{jm} \right\}_1^J = \mathop{\arg\min}\limits_{\left \{ R_{jm} \right\}_1^J}\sum\limits_{i=1}^N \left [\tilde{y}_i - h_m(x_i\,;\,\left \{R_{jm},b_{jm} \right\}_1^J) \right]^2\]

即先求出树划分出的区域,而相应的\(b_{jm} = \mathop{mean} \limits_{x \in R_{jm}} \tilde{y}_{im}\)为该区域的平均值。

接下来注意到2.c步中求出的\(\rho_m\)对于整棵树中所有区域都是一样的,这样可能并不会使损失最小,因此Friedman提出可以对每个区域\(R_j\)分别求一个最优的值\(\gamma_{jm} = \rho_m b_{jm}\),则2.c步变为:
​ \[\gamma_{jm} = \mathop{\arg\min}\limits_\gamma \sum\limits_{x_i \in R_{jm}}L(y_i,f_{m-1}(x_i)+\gamma)\]

GBDT回归算法流程

  1. 初始化: \(f_0(x) = \mathop{\arg\min}\limits_\gamma \sum\limits_{i=1}^N L(y_i, \gamma)\)

  2. for m=1 to M:
    (a) 计算负梯度: \(\tilde{y}_i = -\frac{\partial L(y_i,f_{m-1}(x_i))}{\partial f_{m-1}(x_i)}, \qquad i = 1,2 \cdots N\)
    (b) \(\left \{ R_{jm} \right\}_1^J = \mathop{\arg\min}\limits_{\left \{ R_{jm} \right\}_1^J}\sum\limits_{i=1}^N \left [\tilde{y}_i - h_m(x_i\,;\,\left \{R_{jm},b_{jm} \right\}_1^J) \right]^2\)
    (c) \(\gamma_{jm} = \mathop{\arg\min}\limits_\gamma \sum\limits_{x_i \in R_{jm}}L(y_i,f_{m-1}(x_i)+\gamma)\)
    (d) \(f_m(x) = f_{m-1}(x) + \sum\limits_{j=1}^J \gamma_{jm}I(x \in R_{jm})\)
  3. 输出\(f_M(x)\)

回归问题损失函数的选择

常用的损失函数为平方损失 (squared loss),绝对值损失 (absolute loss),Huber损失 (huber loss),下面给出各自的负梯度 (来自ESL 360页):

分类提升树

将GBDT由回归拓展到分类,关键是损失函数的选择。如果选用了指数损失 (exponential loss),则退化为AdaBoost算法。另一种常用的分类损失函数为logistic loss,形式为\(L(y,f(x)) = log(1+e^{-2yf(x)})\) 。


要将其最小化,则对于\(f(x)​\)求导并令其为0:\[\frac{\partial\,log(1+e^{-2yf(x)})}{\partial f(x)} = P(y=1|x) \frac{-2e^{-2f(x)}}{1+e^{-2f(x)}} + P(y=-1|x) \frac{2e^{2f(x)}}{1+e^{2f(x)}} = 0 \quad \Longrightarrow \quad f(x) = \frac12 log\frac{P(y=1|x)}{P(y=-1|x)}\]


可以看到这与指数损失的目标函数一样,都是对数几率,见下图 (来自MLAPP 566页):

区别在于指数损失容易受异常点的影响,不够robust,且只能用于二分类问题。所以像scikit-learn中GradientBoostingClassifier的默认损失函数就是deviance。

与回归提升树的流程类似,求logistic loss的负梯度为:\(\tilde{y} = -\frac{\partial \, log(1+e^{-2yf(x)})}{\partial f(x)} = -\frac{-2y e^{-2yf(x)}}{1+e^{-2yf(x)}} = \frac{2y}{1+e^{2yf(x)}}\)

对于每个区域\(R_j\)的最优值为:\(\gamma_j = \mathop{\arg\min}\limits_\gamma \sum\limits_{x \in R_j} L(y,f_{m-1}(x)+\gamma) = \mathop{\arg\min}\limits_\gamma \sum \limits_{x \in R_j} log(1+e^{-2y(f_{m-1}(x)+\gamma)})\)

上式难以直接求出,因此常用近似值代替: \(\gamma_j = \frac{\sum\limits_{x \in R_j}\tilde{y}}{\sum\limits_{x \in R_j}|\tilde{y}|(2-|\tilde{y}|)}\)

因为是分类问题,最后输出\(f_M(x)\)后要进行概率估计:设 \(P = P(y=1|x)\),\[f(x) = \frac12 log\frac{P(y=1|x)}{P(y=-1|x)} = \frac12log \frac{P}{1-P} \quad \color{Blue}{\Longrightarrow}\quad P = P(y=1|x) = \frac{1}{1+e^{-2f(x)}} \;\in \left\{0,1 \right\}\]

正则化 (Regularization)

1、Shrinkage

对每个基学习器乘以一个系数\(\,\nu\, (0 < \nu <1)\),使其对最终模型的贡献减小,从而防止学的太快产生过拟合。\(\nu\)又称学习率,即scikit-learn中的learning rate。于是上文的加法模型就从:
​ \[f_m(x) = f_{m-1}(x) + \rho_m h_m(x\,;\,w_m)\]

变为:
​ \[f_m(x) = f_{m-1}(x) + \nu \rho_m h_m(x\,;\,w_m)\]

一般\(\nu\)要和迭代次数M结合起来使用,较小的\(\nu\)意味着需要较大的M。ESL中推荐的策略是先将\(\nu\)设得很小 (\(\nu\) < 0.1),再通过early stopping选择M,不过现实中也常用cross-validation进行选择。

2、Early stopping

将数据集划分为训练集和测试集,在训练过程中不断检查在测试集上的表现,如果测试集上的准确率下降到一定阈值之下,则停止训练,选用当前的迭代次数M,这同样是防止过拟合的手段。

3、限制树的复杂度

不加限制完全生成的树同样可能会学的太快导致过拟合,因而通常对其进行预剪枝。常用的方法是限制树的深度(scikit-learn中的max_depth)等。

4、Subsampling

借用bootstrap的思想,每一轮训练时只使用一部分样本,不同点是这里的采样是无放回抽样,这个方法被称为Stochastic Gradient Boosting。对于单棵树来说,只使用一部分样本拟合会增加单棵树的偏差和方差,然而subsampling会使树与树之间的相关性减少,从而降低模型的整体方差,很多时候会提高准确性。

subsampling的另一个好处是因为只使用一部分样本进行训练,所以能显著降低计算开销。

特征重要性

单棵决策树的可解释性很强,GBDT则继承了这个优点。

对于单棵树T,用下式来衡量每个特征\(X_l\)的重要性:\[\mathcal{I}_{l}^2(T) = \sum\limits_{t=1}^{J-1}\hat{i}_t^2I(v(t) = l)\]

其中\(J\)表示叶结点 (leaf node) 数量,\(J-1\)表示内部结点 (internal node) 数量,\(X_{v(t)}\)是与内部结点t相关联的分裂特征。对于每个内部结点t,用特征\(X_{v(t)}\)来模拟划分特征空间,得到一个分裂后的平方误差减少量,即\(\hat{i}^2_t\),最后将所有内部节点上的误差减少量加起来,就是特征\(X_l\)的重要性。总误差减少地越多,该特征就越重要。

对于M棵树的集成而言,特征重要性就是各棵树相应值的平均:\[\mathcal{I}_{l}^2 = \frac1M\sum\limits_{m=1}^M\mathcal{I}_l^2(T_m)\]

终末 —— 决策树和GBDT

Gradient Boosting算法理论上可以选择多种不同的学习算法作为基学习器,但实际使用地最多的无疑是决策树,这并非偶然。决策树有很多优良的特性,比如能灵活处理各种类型的数据,包括连续值和离散值;对缺失值不敏感;不需要做特征标准化/归一化;可解释性好等等,但其致命缺点是不稳定,导致容易过拟合,因而很多时候准确率不如其他算法。

决策树是非参数模型,这并不意味着其没有参数,而是在训练之前参数数量是不确定的,因此完全生长的决策树有着较大的自由度,能最大化地拟合训练数据。然而单颗决策树是不稳定的,样本数相同的训练集产生微小变动就能导致最终模型的较大差异,即模型的方差大,泛化性能不好。集成学习的另一代表Bagging是对付这个问题的一大利器 (详见前一篇文章Bagging与方差) 。而Bagging的拓展算法 —— 随机森林,通过在树内部结点的分裂过程中,随机选取固定数量的特征纳入分裂的候选项,这样就进一步降低了单模型之间的相关性,总体模型的方差也比Bagging更低。

另一方面,决策树和Gradient Boosting结合诞生了GBDT,GBDT继承了决策树的诸多优点,同时也改进了其缺点。由于GBDT采用的树都是复杂度低的树,所以方差很小,通过梯度提升的方法集成多个决策树,最终能够很好的解决过拟合的问题。然而Boosting共有的缺点为训练是按顺序的,难以并行,这样在大规模数据上可能导致速度过慢,所幸近年来XGBoost和LightGBM的出现都极大缓解了这个问题,后文详述。


Reference:

  1. Friedman, J. Greedy Function Approximation: A Gradient Boosting Machine
  2. Friedman, J. Stochastic Gradient Boosting
  3. Friedman, J., Hastie, T. and Tibshirani, R. The Elements of Staistical Learning

/

集成学习之Boosting —— Gradient Boosting原理的更多相关文章

  1. [白话解析] 通俗解析集成学习之bagging,boosting & 随机森林

    [白话解析] 通俗解析集成学习之bagging,boosting & 随机森林 0x00 摘要 本文将尽量使用通俗易懂的方式,尽可能不涉及数学公式,而是从整体的思路上来看,运用感性直觉的思考来 ...

  2. 1. 集成学习(Ensemble Learning)原理

    1. 集成学习(Ensemble Learning)原理 2. 集成学习(Ensemble Learning)Bagging 3. 集成学习(Ensemble Learning)随机森林(Random ...

  3. 集成学习之Boosting —— Gradient Boosting实现

    Gradient Boosting的一般算法流程 初始化: \(f_0(x) = \mathop{\arg\min}\limits_\gamma \sum\limits_{i=1}^N L(y_i, ...

  4. 【Python机器学习实战】决策树与集成学习(六)——集成学习(4)XGBoost原理篇

    XGBoost是陈天奇等人开发的一个开源项目,前文提到XGBoost是GBDT的一种提升和变异形式,其本质上还是一个GBDT,但力争将GBDT的性能发挥到极致,因此这里的X指代的"Extre ...

  5. 回归树|GBDT|Gradient Boosting|Gradient Boosting Classifier

    已经好久没写了,正好最近需要做分享所以上来写两篇,这篇是关于决策树的,下一篇是填之前SVM的坑的. 参考文献: http://stats.stackexchange.com/questions/545 ...

  6. 集成学习二: Boosting

    目录 集成学习二: Boosting 引言 Adaboost Adaboost 算法 前向分步算法 前向分步算法 Boosting Tree 回归树 提升回归树 Gradient Boosting 参 ...

  7. 集成学习之Boosting —— XGBoost

    集成学习之Boosting -- AdaBoost 集成学习之Boosting -- Gradient Boosting 集成学习之Boosting -- XGBoost Gradient Boost ...

  8. 机器学习——集成学习(Bagging、Boosting、Stacking)

    1 前言 集成学习的思想是将若干个学习器(分类器&回归器)组合之后产生一个新学习器.弱分类器(weak learner)指那些分类准确率只稍微好于随机猜测的分类器(errorrate < ...

  9. 集成学习之Adaboost算法原理

    在boosting系列算法中,Adaboost是最著名的算法之一.Adaboost既可以用作分类,也可以用作回归. 1. boosting算法基本原理 集成学习原理中,boosting系列算法的思想:

随机推荐

  1. 97 条 Linux 常用命令及Vim命令总结

    一:Vim编辑模式命令 基本上Vim共分为3种模式,分别是一般模式,编辑模式和命令行模式,这三种模式的作用分别如下简述: 一般模式:默认模式.打开vim直接进入的是一般模式,在这个模式下,可以进行的操 ...

  2. Java8新特性(转载)

    1.Lambda表达式 Lambda表达式(也称为闭包)是整个Java 8发行版中最受期待的在Java语言层面上的改变.使用 Lambda 表达式可以使代码变的更加简洁紧凑. Lambda允许把函数作 ...

  3. (转) SpringBoot非官方教程 | 第一篇:构建第一个SpringBoot工程

    简介 spring boot 它的设计目的就是为例简化开发,开启了各种自动装配,你不想写各种配置文件,引入相关的依赖就能迅速搭建起一个web工程.它采用的是建立生产就绪的应用程序观点,优先于配置的惯例 ...

  4. 利用 TestNG 并行执行用例

    原文地址https://testerhome.com/topics/1639 一.测试类*注1 package com.testerhome; import io.appium.java_client ...

  5. java对象,引用的区别

    一,其实 对象 就是一个类的实例 在Java中有一句比较流行的话,叫做“万物皆对象”,这是Java语言设计之初的理念之一.要理解什么是对象,需要跟类一起结合起来理解.下面这段话引自<Java编程 ...

  6. linux centos7 erlang rabbitmq安装

    最终的安装目录为/opt/erlang 和 /opt/rabbitmq wget http://erlang.org/download/otp_src_21.0.tar.gztar zxvf otp_ ...

  7. vim多行注释和取消注释 Ubuntu

    多行注释: 1. 进入命令行模式,按ctrl + v进入 visual block模式,然后按d 是选择到最后一行,也可以直接光标上下左右,把需要注释的行标记起来 2. 按大写字母I,再插入注释符,例 ...

  8. la5135 无向图 点-双连通 运用

    大白书 P314 #include <iostream> #include <algorithm> #include <string.h> #include < ...

  9. Java 对比Vector、ArrayList、LinkedList

    ①引言 在日常生活中能高效的管理和操作数据是非常重要的.Java提供了强大的集合框架,大大提高了开发者的生产力,今天就了解一下有关集合框架方面的问题. Vector.ArrayList.LinkedL ...

  10. 报错org.openqa.selenium.WebDriverException: disconnected: unable to connect to renderer解决方法

    做自动化时经常会遇到不兼容的问题,比如以下简单的脚本,主要是打开浏览器,然后最大化窗口,打开百度,输入内容搜索,代码如下: package com.gs.selenium; import org.op ...