线性模型正则化

寵の児 提交于 2020-01-25 19:56:07

一、正则线性模型

减少过度拟合的一个好办法就是对模型正则化(即约束它):它拥有的自由度越低,就越不容易过度拟合数据。比如,将多项式模型正则化的简单方法就是降低多项式的阶数。

对线性模型来说,正则化通常通过约束模型的权重来实现。常见的对权重进行约束的方法有:岭回归(Ridge Regression)、套索回归(lasso Regression)及弹性网络(Elastic Regression)。

二、岭回归

岭回归(也叫作吉洪诺夫正则化)是线性回归的正则化版:在成本函数中添加一个等于αi=1nθi2\alpha\sum_{i=1}^n\theta_i^2的正则项。这使得学习中的算法不仅需要拟合数据,同时还要让模型权重保持最小。

  • 正则项只能在训练的时候添加到成本函数中,一旦训练完成,我们需要使用未经正则化的性能指标来评估模型性能。

超参数α\alpha控制的是对模型进行正则化的程度。如果α=0\alpha=0,则岭回归就是线性模型。如果α\alpha非常大,那么所有的权重都将非常接近于零,结果是一条穿过数据平均值的水平线。

岭回归的成本函数:
J(θ)=MSE(θ)+α12i=1nθi2J(\theta)=MSE(\theta)+\alpha\frac12\sum_{i=1}^n\theta_i^2
注意,这里偏置项θ0\theta_0没有正则化(求和从i=1i=1开始,不是i=0i=0)。如果我们将ww定义为特征权重的向量(θ1\theta_1θn\theta_n),那么正则项即等于12(w2)2\frac12(||w||_2)^2其中w2||w||_2为权重向量的l2l_2范数。而对于梯度下降,只需要在MSE梯度向量上添加αw\alpha w即可。

  • 在执行岭回归之前,必须对数据进行缩放,因为它对输入特征的大小非常敏感。大多数正则化模型都是如此。
    与线性回归一样,我们也可以在计算闭市方程或者执行梯度下降时,执行岭回归。利弊都一样。

闭式解的岭回归(其中AA是一个nXn的单位矩阵,除了左上单元格为0,其他与偏置项对应):
θ^=(XTX+αA)1XTy\hat{\theta}=(X^T\cdot X+\alpha A)^{-1}\cdot X^T\cdot y
下面是如何使用Scikit-Learn执行闭式解的岭回归:
首先随机生成一些含有噪声的数据:

import numpy as np
import matplotlib.pyplot as plt
X=3*np.random.rand(100,1)
y=3+2*X+np.random.randn(100,1)
plt.plot(X,y,'b.')
plt.show()

在这里插入图片描述

训练模型(使用的是闭式解公式的一种变体,利用Andre-Louis Cholesky的矩阵因式分解法):

from sklearn.linear_model import Ridge
ridge_reg=Ridge(alpha=1,solver='cholesky')
ridge_reg.fit(X,y)
Ridge(alpha=1, copy_X=True, fit_intercept=True, max_iter=None,
   normalize=False, random_state=None, solver='cholesky', tol=0.001)
ridge_reg.intercept_,ridge_reg.coef_
(array([ 3.02790174]), array([[ 1.907145]]))
ridge_reg.predict([[1.5]])
array([[ 5.88861924]])

使用随机梯度下降:

from sklearn.linear_model import SGDRegressor
sgd_reg=SGDRegressor(penalty='l2')
sgd_reg.fit(X,y.ravel())
D:\Anaconda\lib\site-packages\sklearn\linear_model\stochastic_gradient.py:128: FutureWarning: max_iter and tol parameters have been added in <class 'sklearn.linear_model.stochastic_gradient.SGDRegressor'> in 0.19. If both are left unset, they default to max_iter=5 and tol=None. If tol is not None, max_iter defaults to max_iter=1000. From 0.21, default max_iter will be 1000, and default tol will be 1e-3.
  "and default tol will be 1e-3." % type(self), FutureWarning)





SGDRegressor(alpha=0.0001, average=False, epsilon=0.1, eta0=0.01,
       fit_intercept=True, l1_ratio=0.15, learning_rate='invscaling',
       loss='squared_loss', max_iter=None, n_iter=None, penalty='l2',
       power_t=0.25, random_state=None, shuffle=True, tol=None, verbose=0,
       warm_start=False)

超参数penalty设置的是使用正则项的类型。设为“l2l2”表示希望SGD在成本函数中添加一个正则项,等于权重向量的l2l2范数的平方的一半,即岭回归。

sgd_reg.intercept_,sgd_reg.coef_
(array([ 1.91897045]), array([ 2.51547769]))
sgd_reg.predict([[1.5]])
array([ 5.69218699])

三、套索回归

线性回归的另一种正则化,叫作最小绝对收缩和选择算子回归(Least Absolute Shrinkage and Selection Operator Regression,简称Lasso回归,或套索回归)。与岭回归一样,它也是向成本函数增加一个正则项,但是它增加的是权重 向量的l1l1范数,而不是l2l2范数的平方的一半。

Lasso回归成本函数:

J(θ)=MSE(θ)+αi=1nθiJ(\theta)=MSE(\theta)+\alpha\sum_{i=1}^n|\theta_i|
Lasso回归的一个重要特点是它倾向于完全消除掉最不重要特征的权重(也就是将它们设置为零)。换句话说,Lasso回归会自动执行特征选择并输出一个稀疏模型(即只有很少的特征有非零权重)。

下面是一个使用Scikit-Learn的Lasso类的例子,我们也可以用SGDRegression(penalty=’l1l1’):

from sklearn.linear_model import Lasso
lasso_reg=Lasso(alpha=0.1)
lasso_reg.fit(X,y)
Lasso(alpha=0.1, copy_X=True, fit_intercept=True, max_iter=1000,
   normalize=False, positive=False, precompute=False, random_state=None,
   selection='cyclic', tol=0.0001, warm_start=False)
lasso_reg.intercept_,lasso_reg.coef_
(array([ 3.18622698]), array([ 1.79448133]))
lasso_reg.predict([[1.5]])
array([ 5.87794898])

四、弹性网络

弹性网络是岭回归与Lasso回归之间的中间地带。其正则项就是岭回归和Lasso回归的正则项的混合,混合比例通过r来控制。当r=0时,弹性网络即等同于岭回归,而当r=1时,即相当于Lasso回归。

弹性网络成本函数:
J(θ)=MSE(θ)+rαi=1nθi+1r2αi=1nθi2J(\theta)=MSE(\theta)+r\alpha\sum_{i=1}^n|\theta_i|+\frac{1-r}{2}\alpha\sum_{i=1}^n\theta_i^2
下面是一个使用Scikit-Learn的ElasticNet的例子(l1_ratiol1\_ratio对应混合比例rr):

from sklearn.linear_model import ElasticNet
elastic_net=ElasticNet(alpha=0.1,l1_ratio=0.5)
elastic_net.fit(X,y)
ElasticNet(alpha=0.1, copy_X=True, fit_intercept=True, l1_ratio=0.5,
      max_iter=1000, normalize=False, positive=False, precompute=False,
      random_state=None, selection='cyclic', tol=0.0001, warm_start=False)
elastic_net.intercept_,elastic_net.coef_
(array([ 3.25888406]), array([ 1.74277881]))
elastic_net.predict([[1.5]])
array([ 5.87305228])
  • 那么,到底如何选用线性回归、岭回归、Lasso回归和弹性回归呢?通常来说,有正则化——哪怕是很小,总是比没有更可取一些。所以大多数情况下,我们应该避免使用纯线性回归。岭回归是个不错的默认选择,但是如果你觉得实际用到的特征只有少数几个,那就更倾向于Lasso回归或是弹性网络,因为它们会将无用特征的权重降为零。一般而言,弹性网络优于Lasso回归,因为当特征数量超过训练实例数量,又或者是几个特征强相关时,Lasso回归的表现可能非常不稳定。

五、早期停止法

对于梯度下降这一类迭代学习的算法,还有一个与众不同的正则化方法,就是在验证误差达到最小值时停止训练,该方法叫作早期停止法。通过早期停止法,一旦验证误差达到最小值就立刻停止训练。这是一个非常简单而有效的正则化技巧,所以Geoffery Hinton(神经网络之父)称其为“美丽的免费午餐”。

对随机梯度下降和小批量梯度下降来说,曲线没有那么平滑,所以很难知道是否已经达到最小值。一种解决办法是等验证误差超过最小值一段时间之后再停止,然后将模型参数回滚到验证误差最小时的位置。

下面是早期停止法的基本实现:

from sklearn.base import clone
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
sgd_reg=SGDRegressor(n_iter=1,warm_start=True,penalty=None,learning_rate='constant',eta0=0.0005)
minimum_val_error=float('inf')
best_epoch=None
best_model=None
X_train,X_val,y_train,y_val=train_test_split(X,y,test_size=0.2)
for epoch in range(1000):
    sgd_reg.fit(X_train,y_train)
    y_val_predict=sgd_reg.predict(X_val)
    val_error=mean_squared_error(y_val_predict,y_val)
    if val_error<minimum_val_error:
        minimum_val_error=val_error
        best_epoch=epoch
        best_model=clone(sgd_reg)

当warm_start=True时,调用fit()方法,会从停下的地方继续开始训练,而不会重新开始。

看下最终结果:

best_epoch
324

算法迭代到第324轮验证误差已经达到最小值。

再看下最终得到的最佳模型:

best_model
SGDRegressor(alpha=0.0001, average=False, epsilon=0.1, eta0=0.0005,
       fit_intercept=True, l1_ratio=0.15, learning_rate='constant',
       loss='squared_loss', max_iter=None, n_iter=1, penalty=None,
       power_t=0.25, random_state=None, shuffle=True, tol=None, verbose=0,
       warm_start=True)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!