要想了解如何增强机器学习模型性能,我们需要知道如何降低模型的误差。所以首先我们必须明白模型误差是由偏差(Bias)和方差(Variance)组成的。偏差是指样本预测值的平均值与样本真实值的差,而方差是指样本预测值偏离样本预测值平均值的程度。
其中
- 偏差(Bias)可以描述模型的准确性
- 而方差(Variance)可以描述模型的稳定性,一定程度上反映了模型泛化能力。
所以增强机器学习模型性能就意味着需要提高模型的准确性和稳定性。
我们来看看下图,直观的感受一下偏差(Bias)和方差(Variance)对模型的影响,你可以将其想象一个同学的一学期的考试情况,越靠红心代表考试得分越高:
- 右下角同学——学渣,每次考试分数不高,而且成绩还不稳定,属于高偏差高方差的模型。
- 左下角同学——学庸,成绩很稳定,可是每次考试得分都不高,属于方差较小可是偏差较大的模型。
- 右上角的同学——学聪,成绩还不错,可是忽高忽低,不稳定,属于偏差较小可是方差较大的模型。
- 左上角的同学——学霸,成键很棒,而且极其稳定,属于偏差较小,方差也小的模型。
地球人都知道哪种学生最受老师,当然是——左上角的同学,成键很棒,而且极其稳定,对应于偏差较小,方差也小的模型。可到底如何训练我们才能得到这样一个偏差较小,方差也小的学霸模型呢?
之前的文章中笔者将集成学习中Gradient Boosting和深度学习Residual Block联系起来,说明了拟合残差的可以降低模型的偏差(Bias)。今天笔者来尝试将集成学习中Bagging和深度学习中Dropout联系起来去说明如何降低模型的方差(Variance)。
Bagging(short for bootstrap aggregating)
Bootstrap 是统计学中一种采样那个方式,可以指任何一种有放回的均匀抽样,也就是说,每当选中一个样本,它等可能地被再次选中并被再次添加到训练集中。而在机器学习中Bagging的做法分为简单两部:
- 从样本中自助采样一批训练数据训练一个基学习器。
- 最后通过这些基学习器投票产生模型最后的输出。
Bagging的做法如下图所示,最终这些弱的基学习器集成成一个强的学习器。这里有个关键的地方需要注意,就是要每个基学习器差异性越大越好。不同的基学习器擅长不同的事情,这样他们联合起来的威力才是最大的。
在sklearn中可以轻松的调用BaggingClassifier这个API,下方代码采用决策树作为基学习器,同时定义了基学习器的个数为500。
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
bag_clf = BaggingClassifier(
DecisionTreeClassifier(), n_estimators=500,
max_samples=100, bootstrap=True, n_jobs=-1
)
bag_clf.fit(X_train, y_train)
y_pred = bag_clf.predict(X_test)
而上方代码,就等价于下面通过调用RandomForestClassifierAPI构建的随机森林,n_estimators=500表示这个集成模型有500棵决策树。其中随机森林为了增加每棵树的差异性,不仅每颗树训练数据不同,而且还增加了特征的差异性。每颗树选择特征的方法是:随机选择一个特征子集,这个子集可以是少部分特征的集合,也可以由特征组合而来。
from sklearn.ensemble import RandomForestClassifier
rnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, n_jobs=-1)
rnd_clf.fit(X_train, y_train)
y_pred_rf = rnd_clf.predict(X_test)
Dropout
再来看看深度学习中经常采用的防止过拟合的小技巧Dropout。Dropout的细节是在深度神经网络模型做训练时,让网络中某些神经元随机失活——也就是不参与训练。如下图所示,换个角度理解一下这个操作背后的含义:Dropout使得每批训练数据进入神经网络时,神经网络的构型都不同,即每批训练数据训练的网络结构都不同。而做预测Dropout是关闭的状态,代表着做预测时是所有训练时结构不同的神经网络一起做的最后的预测。整个过程就是多个不同神经网络最后投票做决定给出预测值。
下方是keras实现的一个增加Dropout层的神经网络模型。
model = Sequential()
###加dropout
model.add(Dropout(0.2, input_shape=(60,)))
model.add(Dense(60,activation='relu'))
model.add(Dense(1,activation='sigmoid'))
sgd = SGD(lr=0.1, momentum=0.9, decay=0.0, nesterov=False)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
而且由于训练数据和网络结构的不同,导致每个网络——也就是基学习器的差异性也很多样,所以最终使得训练出来的模型稳定性较强,有很好的抗过拟合效果。
结语
至此,我们了解到通过多个差异性的基学习器以投票的方式集成的组合模型能够降低模型的方差。在加上之前我们学习过通过boosting集成模型可以降低模型的偏差。将二者结合,应该就可以训练一个上文提到偏差较小,方差也小的学霸模型了。
参考:
Dropout: A Simple Way to Prevent Neural Networks from Overfitting
https://mp.weixin.qq.com/s/-T4bAGR6acN1uPnmds1AlA