机器学习入门系列(2)–如何构建一个完整的机器学习项目,第九篇!
该系列的前八篇文章:
常用机器学习算法汇总比较的最后一篇,介绍提升(Boosting)算法、GBDT、优化算法和卷积神经网络的基本原理、优缺点。
提升方法(boosting)是一种常用的统计学习方法,在分类问题中,它通过改变训练样本的权重,学习多个分类器,并将这些分类器进行线性组合,提供分类的性能。
boosting 和 bagging 都是集成学习(ensemble learning)领域的基本算法,两者使用的多个分类器的类型是一致的。
bagging也叫自助汇聚法(bootstrap aggregating),比如原数据集中有 N 个样本,我们每次从原数据集中有放回的抽取,抽取 N 次,就得到了一个新的有 N 个样本的数据集,然后我们抽取 S 个 N 次,就得到了 S 个有 N 个样本的新数据集,然后拿这 S 个数据集去训练 S 个分类器,之后应用这 S 个分类器进行分类,选择分类器投票最多的类别作为最后的分类结果。一般来说自助样本的包含有 63% 的原始训练数据,因为:
假设共抽取 N 个样本,则 N 次都没有抽到的概率是 p = ( 1 − 1 N ) N p=(1-\frac{1}{N})^N p=(1−N1)N
则一个样本被抽到的概率有 p = 1 − ( 1 − 1 N ) N p = 1- (1- \frac{1}{N})^N p=1−(1−N1)N
所以,当 N 很大时有: p = 1 − 1 e = 0.632 p = 1- \frac{1}{e} = 0.632 p=1−e1=0.632。
这样,在一次 bootstrap 的过程中,会有 36% 的样本没有被采样到,它们被称为 out-off-bag(oob),这是自助采样带给 bagging
的里一个优点,因为我们可以用 oob
进行**“包外估计”(out-of-bag estimate)**。
bagging 通过降低基分类器的方差改善了泛化误差,bagging 的性能依赖于基分类器的稳定性。如果基分类器是不稳定的,bagging 有助于减少训练数据的随机波动导致的误差,如果基分类器是稳定的,即对训练数据集中的微小变化是鲁棒的,则组合分类器的误差主要由基分类器偏移所引起的,这种情况下,bagging 可能不会对基分类器有明显的改进效果,甚至可能降低分类器的性能。
AdaBoost 是 boosting 方法中最流行的版本
AdaBoost(adaptive boosting)是元算法,通过组合多个弱分类器来构建一个强分类器。
我们为训练数据中的每一个样本都赋予其一个权重,这些权重构成了向量 D,一开始,这些权重都初始化成相等值,然后每次添加一个弱分类器对样本进行分类,从第二次分类开始,将上一次分错的样本的权重提高,分对的样本权重降低,持续迭代。
此外,对于每个弱分类器而言,每个分类器也有自己的权重,取决于它分类的加权错误率,加权错误率越低,则这个分类器的权重值 α 越高,最后综合多个弱分类器的分类结果和其对应的权重 α 得到预测结果,AdaBoost 是最好的监督学习分类方法之一。
GBDT 是一个基于迭代累加的决策树算法,它通过构造一组弱的学习器(树),并把多颗决策树的结果累加起来作为最终的预测输出。
GBDT中的树是回归树,不是分类树。
LogLoss
等xgboost 是 boosting Tree 的一个很牛的实现,它在 Kaggle 比赛中大放异彩。它有以下几个优良的特性:
在项目实测中使用发现,Xgboost 的训练速度要远远快于传统的 GBDT 实现,10 倍量级。
下面给出简单使用xgboost这个框架的例子。
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.01, random_state=1729)
print(X_train.shape, X_test.shape)
#模型参数设置
xlf = xgb.XGBRegressor(max_depth=10,
learning_rate=0.1,
n_estimators=10,
silent=True,
objective='reg:linear',
nthread=-1,
gamma=0,
min_child_weight=1,
max_delta_step=0,
subsample=0.85,
colsample_bytree=0.7,
colsample_bylevel=1,
reg_alpha=0,
reg_lambda=1,
scale_pos_weight=1,
seed=1440,
missing=None)
xlf.fit(X_train, y_train, eval_metric='rmse', verbose = True, eval_set = [(X_test, y_test)],early_stopping_rounds=100)
# 计算 auc 分数、预测
preds = xlf.predict(X_test)
常见的最优化方法有梯度下降法、牛顿法和拟牛顿法、共轭梯度法等等
梯度下降法是最早最简单,也是最为常用的最优化方法。
梯度下降法实现简单,当目标函数是凸函数时,梯度下降法的解是全局解。
一般情况下,其解不保证是全局最优解,梯度下降法的速度也未必是最快的。
梯度下降法的优化思想是用当前位置负梯度方向作为搜索方向,因为该方向为当前位置的最快下降方向,所以也被称为是”最速下降法“。最速下降法越接近目标值,步长越小,前进越慢。
梯度下降法的搜索迭代示意图如下图所示:
其缺点是:
(1)靠近极小值时收敛速度减慢,如下图所示;
(2)直线搜索时可能会产生一些问题;
(3)可能会“之字形”地下降。
从上图可以看出,梯度下降法在接近最优解的区域收敛速度明显变慢,利用梯度下降法求解需要很多次的迭代。
在机器学习中,基于基本的梯度下降法发展了三种梯度下降方法:
其中小批量梯度下降法是前两种方法的一个折中,也是目前最常用的梯度下降法,它即避免了批量梯度下降法需要计算整个训练集的缺点,也不会像随机梯度下降法一样会出现训练震荡,不稳定的缺点。当然,它相比前两种方法的缺点就是比较容易陷入局部最小值中。
牛顿法是一种在实数域和复数域上近似求解方程的方法。方法使用函数 f(x) 的泰勒级数的前面几项来寻找方程 f(x) = 0 的根。
它是二阶算法,它使用了 Hessian 矩阵求权重的二阶偏导数,目标是采用损失函数的二阶偏导数寻找更好的训练方向。
牛顿法最大的特点就在于它的收敛速度很快。
牛顿法是基于当前位置的切线来确定下一次的位置,所以牛顿法又被很形象地称为是"切线法"。牛顿法的搜索路径(二维情况)如下图所示:
牛顿法搜索动态示例图:
关于牛顿法和梯度下降法的效率对比:
注:红色的牛顿法的迭代路径,绿色的是梯度下降法的迭代路径。
二阶收敛,收敛速度快;
拟牛顿法的本质思想是改善牛顿法每次需要求解复杂的 Hessian 矩阵的逆矩阵的缺陷,它使用正定矩阵来近似 Hessian 矩阵的逆,从而简化了运算的复杂度。
拟牛顿法和最速下降法一样只要求每一步迭代时知道目标函数的梯度。通过测量梯度的变化,构造一个目标函数的模型使之足以产生超线性收敛性。这类方法大大优于最速下降法,尤其对于困难的问题。
另外,因为拟牛顿法不需要二阶导数的信息,而是在每次迭代的时候计算一个矩阵,其逼近海塞矩阵的逆。最重要的是,该逼近值只是使用损失函数的一阶偏导来计算,所以有时比牛顿法更为有效。
如今,优化软件中包含了大量的拟牛顿算法用来解决无约束,约束,和大规模的优化问题。
共轭梯度法是介于最速下降法与牛顿法之间的一个方法,**它仅需利用一阶导数信息,但克服了最速下降法收敛慢的缺点,又避免了牛顿法需要存储和计算Hesse矩阵并求逆的缺点,**共轭梯度法不仅是解决大型线性方程组最有用的方法之一,也是解大型非线性最优化最有效的算法之一。在各种优化算法中,共轭梯度法是非常重要的一种。其优点是所需存储量小,具有收敛快,稳定性高,而且不需要任何外来参数。
在共轭梯度训练算法中,因为是沿着共轭方向(conjugate directions)执行搜索的,所以通常该算法要比沿着梯度下降方向优化收敛得更迅速。共轭梯度法的训练方向是与海塞矩阵共轭的。
共轭梯度法已经证实其在神经网络中要比梯度下降法有效得多。并且由于共轭梯度法并没有要求使用海塞矩阵,所以在大规模神经网络中其还是可以做到很好的性能。
启发式方法指人在解决问题时所采取的一种根据经验规则进行发现的方法。其特点是在解决问题时,利用过去的经验,选择已经行之有效的方法,而不是系统地、以确定的步骤去寻求答案。启发式优化方法种类繁多,包括经典的模拟退火方法、遗传算法、蚁群算法以及粒子群算法等等。
还有一种特殊的优化算法被称之多目标优化算法,它主要针对同时优化多个目标(两个及两个以上)的优化问题,这方面比较经典的算法有 NSGAII 算法、MOEA/D 算法以及人工免疫算法等。
这个方法可以参考文章 拉格朗日乘数法
Levenberg-Marquardt 算法
Levenberg-Marquardt 算法,也称之为衰减最小二乘法(damped least-squares method),该算法的损失函数采用平方误差和的形式。该算法的执行也不需要计算具体的海塞矩阵,它仅仅只是使用梯度向量和雅可比矩阵(Jacobian matrix)。
Levenberg-Marquardt 算法是为平方误差和函数所定制的。这就让使用这种误差度量的神经网络训练地十分迅速。然而 Levenberg-Marquardt 算法还有一些缺点:
下图展示了所有上文所讨论的算法,及其收敛速度和内存需求。其中收敛速度最慢的是梯度下降算法,但该算法同时也只要求最少的内存。相反,Levenberg-Marquardt 算法可能是收敛速度最快的,但其同时也要求最多的内存。比较折衷方法是拟牛顿法。
总而言之:
CNN 可以应用在场景分类,图像分类,现在还可以应用到自然语言处理(NLP)方面的很多问题,比如句子分类等。
LeNet 是最早的CNN结构之一,它是由大神 Yann LeCun 所创造的,主要是用在字符分类问题。
卷积神经网络主要包含四种不同的网络层,分别是卷积层,非线性层(也就是使用了ReLU函数),Pooling层,全连接层,下面将一一介绍这几种网络层。
CNN的名字由来就是因为其使用了卷积运算的缘故。卷积的目的主要是为了提取图片的特征。卷积运算可以保持像素之间的空间关系。
每张图片可以当做是一个包含每个像素值的矩阵,像素值的范围是 0~255,0 表示黑色,255 是白色。下面是一个 5 × 5 大小的矩阵例子,它的值是 0 或者 1。
接下来是另一个 3 × 3 矩阵:
上述两个矩阵通过卷积,可以得到如下图右侧粉色的矩阵结果。
黄色的矩阵在绿色的矩阵上从左到右,从上到下,每次滑动的步进值是1个像素,所以得到一个 3 × 3 的矩阵。
在CNN中,黄色的矩阵被叫做滤波器(filter)或者核(kernel)或者是特征提取器,而通过卷积得到的矩阵则是称为“特征图(Feature Map)”或者“Activation Map”。
另外,使用不同的滤波器矩阵是可以得到不同的 Feature Map ,例子如下图所示:
上图通过滤波器矩阵,实现了不同的操作,比如边缘检测,锐化以及模糊操作等。
在实际应用中,CNN 是可以在其训练过程中学习到这些滤波器的值,不过我们需要首先指定好滤波器的大小,数量以及网络的结构。使用越多的滤波器,可以提取到更多的图像特征,网络也就能够有更好的性能。
Feature Map 的尺寸是由以下三个参数来决定的:
卷积是大自然中最常见的运算,一切信号观测、采集、传输和处理都可以用卷积过程实现,其用公式表达如下:
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲ Y(m,n) & =X(m,…
上述公式中 H ( m , n ) H(m,n) H(m,n) 表示卷积核。
在 CNN 中的卷积层的计算步骤与上述公式定义的二维卷积有点差异,首先是维度升至三维、四维卷积,跟二维卷积相比多了一个**“通道”(channel)**,每个通道还是按照二维卷积方式计算,而多个通道与多个卷积核分别进行二维卷积,得到多通道输出,需要“合并”为一个通道;其次是卷积核在卷积计算时没有“翻转”,而是与输入图片做滑动窗口“相关”计算。用公式重新表达如下:
Y l ( m , n ) = X k ( m , n ) ∗ H k l ( m , n ) = ∑ k = 0 K − 1 ∑ i = 0 I − 1 ∑ j = 0 J − 1 X k ( m + i , n + j ) H k l ( i , j ) Y^l(m,n) =X^k(m,n)*H^{kl}(m,n) = \sum_{k=0}^{K-1}\sum_{i=0}^{I-1}\sum_{j=0}^{J-1}X^k(m+i,n+j)H^{kl}(i,j) Yl(m,n)=Xk(m,n)∗Hkl(m,n)=k=0∑K−1i=0∑I−1j=0∑J−1Xk(m+i,n+j)Hkl(i,j)
这里假定卷积层有 L 个输出通道和 K 个输入通道,于是需要有 K×L 个卷积核实现通道数目的转换。其中 X^k 表示第 k 个输入通道的二维特征图,Y^l 表示第 l 个输出通道的二维特征图,H^{kl} 表示第 k 行、第 l 列二维卷积核。
假定卷积核大小是 I×J,每个输出通道的特征图大小是 M×N,则该层每个样本做一次前向传播时卷积层的计算量是
Calculations(MAC)=I×J×M×N×K×L。
卷积层的学习参数,也就是卷积核数目乘以卷积核的尺寸– P a r a m s = I × J × K × L Params = I×J×K×L Params=I×J×K×L。
这里定义计算量-参数量之比是CPR= C a l c u l a t i o n s / P a r a m s = M × N Calculations/Params=M×N Calculations/Params=M×N。
因此可以得出结论:卷积层的输出特征图尺寸越大,CPR 越大,参数重复利用率越高。若输入一批大小为 B 的样本,则 CPR 值可提高 B 倍。
卷积神经网络通过**『参数减少』与『权值共享』**大大减少了连接的个数,即需要训练的参数的个数。
假设我们的图像是 1000×1000
的,则有 10^6 个隐层神经元,那么它们全连接的话,也就是每个隐层神经元都连接图像的每个像素点,就有 10^12 个连接,也即 10^12 个权值参数需要训练,这显然是不值得的。
但是对于一个只识别特定特征的卷积核,需要大到覆盖整个图像的所有像素点吗?
通常是不需要的,一个特定特征,尤其是第一层需要提取的特征,通常都相当基础,只占图像很小的一部分。所以我们设置一个较小的局部感受区域,比如10*10
,也即每个神经元只需要和这10*10
的局部图像相连接,所以 10^6 个神经元也就有 10^8 个连接。这就叫参数减少。
那什么叫权值共享呢?
在上面的局部连接中,10^6 个神经元,每个神经元都对应 100 个参数,所以是 10^8 个参数,那如果每个神经元所对应的参数都是相同的,那需要训练的参数就只有 100 个。
这后面隐含的道理在于,这 100 个参数就是一个卷积核,而卷积核是提取特征的方式,与其在图像上的位置无关,图像一个局部的统计特征与其他局部的统计特征是一样的,我们用在这个局部抽取特征的卷积核也可以用在图像上的其它任何地方。
而且这 100 个参数只是一种卷积核,只能提取一种特征,我们完全可以采用 100 个卷积核,提取 100 种特征,而所需要训练的参数也不过 10^4,最开始我们训练 10^12 个参数,还只能提取一种特征。选取 100 个卷积核,我们就能得到 100 张特征图,每张特征图可以看做是一张图像的不同通道。
CNN 主要用来识别位移、缩放及其他形式扭曲不变性的二维图形。
由于 CNN 特征检测层通过训练数据进行学习,在使用 CNN 时,避免了显式的特征抽取,而隐式地从训练数据中进行学习;
再者,由于同一个特征图上的神经元权值相同,所以网络可以并行学习,这也是卷积网络相对于神经元彼此相连网络的一大优势。
卷积神经网络以其局部权值共享的特殊结构在语音识别和图像处理方面有着独特的优越性,其布局更接近于实际的生物神经网络,权值共享降低了网络的复杂性,避免了特征提取和分类过程中数据重建的复杂度。
非线性修正函数**ReLU(Rectified Linear Unit)**如下图所示:
这是一个对每个像素点实现点乘运算,并用 0 来替换负值像素点。
其目的是在 CNN 中加入非线性,因为使用 CNN 来解决的现实世界的问题都是非线性的,而卷积运算是线性运算,所以必须使用一个如ReLU的非线性函数来加入非线性的性质。
其他非线性函数还包括 tanh 和 Sigmoid,但是 ReLU 函数已经被证明在大部分情况下性能最好。
**空间合并(Spatial Pooling)**也可以叫做子采样或者下采样,可以在保持最重要的信息的同时降低特征图的维度。它有不同的类型,如最大化,平均,求和等等。
对于Max Pooling操作,首先定义一个空间上的邻居,比如一个 2×2 的窗口,对该窗口内的经过 ReLU 的特征图提取最大的元素。除了提取最大的元素,还可以使用窗口内元素的平均值或者是求和的值。
不过,Max Pooling 的性能是最好的。例子可以如下图所示:
上图中使用的步进值是 2。
根据相关理论,特征提取的误差主要来自两个方面:
一般来说,mean-pooling 能减小第一种误差,更多的保留图像的背景信息,max-pooling 能减小第二种误差,更多的保留纹理信息。
使用Pooling的原因有如下几点:
全连接层就是一个传统的多层感知器,它在输出层使用一个 softmax 激活函数。
其主要作用就是将前面卷积层提取到的特征结合在一起然后进行分类。
Softmax 函数可以将输入是一个任意实数分数的向量变成一个值的范围是 0~1 的向量,但所有值的总和是 1。
在 CNN 出现之前,最早的深度学习网络计算类型都是全连接形式的。
比较卷积层和全连接层,卷积层在输出特征图维度实现了权值共享,这是降低参数量的重要举措,同时,卷积层局部连接特性(相比全连接)也大幅减少了参数量。
因此卷积层参数量占比小,但计算量占比大,而全连接层是参数量占比大,计算量占比小。所以在进行计算加速优化时,重点放在卷积层;在进行参数优化、权值剪裁时,重点放在全连接层。
CNN的整个训练过程如下所示:
常用的机器学习算法就简单介绍到这里,下一篇会介绍模型的评估方法。
参考:
欢迎关注我的微信公众号–机器学习与计算机视觉,或者扫描下方的二维码,大家一起交流,学习和进步!