6.3L1正则、L2正则学习笔记

我们已经知道了模型误差 = 偏差 + 方差 + 不可避免的误差,且在机器学习领域中最重要就是解决过拟合的问题,也就是降低模型的方差。在上一篇文章《ML/DL重要基础概念:偏差和方差》已经列出了如下方法:

  • 降低模型复杂度
  • 减少数据维度;降噪
  • 增加样本数
  • 使用验证集

其实还有一个降低方差的重要方法:模型正则化。本文从理论及代码两个方面对L1正则、L2正则进行了介绍,帮助大家了解其背后的原理以及实际的使用方法。

1.学习模型正则化

1.1 什么是模型正则化

模型正则化(Regularization),对学习算法的修改,限制参数的大小,减少泛化误差而不是训练误差。我们在构造机器学习模型时,最终目的是让模型在面对新数据的时候,可以有很好的表现。当你用比较复杂的模型比如神经网络,去拟合数据时,很容易出现过拟合现象(训练集表现很好,测试集表现较差),这会导致模型的泛化能力下降,这时候,我们就需要使用正则化,降低模型的复杂度。

正则化的策略包括:约束和惩罚被设计为编码特定类型的先验知识 偏好简单模型 其他形式的正则化,如:集成的方法,即结合多个假说解释训练数据

在实践中,过于复杂的模型不一定包含数据的真实的生成过程,甚至也不包括近似过程,这意味着控制模型的复杂程度不是一个很好的方法,或者说不能很好的找到合适的模型的方法。实践中发现的最好的拟合模型通常是一个适当正则化的大型模型。

1.2 模型的过拟合

准备一下数据

import numpy as np
import matplotlib.pyplot as plt

x = np.random.uniform(-3, 3, size=100)
X = x.reshape(-1, 1)
y = 0.5 + x**2 + x + 2 + np.random.normal(0, 1, size=100)
plt.scatter(x, y)
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RDExbSrD-1586108677642)(output_6_0.png)]

下面我们要使用多项式回归过拟合一个样本,生成的曲线非常弯曲、陡峭。前面的参数会非常大,正则化要完成的,就是要限制这些系数的大小。

from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

lin_reg = LinearRegression()
def PolynomialRegression(degree):
    return Pipeline([
        ('poly',PolynomialFeatures(degree)),
        ('std_scaler',StandardScaler()),
        ('lin_reg',lin_reg)
    ])
np.random.seed(666)
X_train, X_test, y_train, y_test = train_test_split(X,y)

poly30_reg = PolynomialRegression(degree=30)
poly30_reg.fit(X_train,y_train)
y30_predict = poly30_reg.predict(X_test)
mean_squared_error(y_test,y30_predict)
# 输出:2.8492121876294063
X_plot = np.linspace(-3,3,100).reshape(100,1)
y_plot = poly30_reg.predict(X_plot)
plt.scatter(X,y)
plt.plot(X_plot[:,0],y_plot,color='r')
plt.axis([-3,3,0,10])
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnb5FQ7F-1586108677644)(output_8_0.png)]

在拟合完之后,就是非常明显的过拟合的效果,即目标函数为了尽可能地去拟合数据,减小模型和样本的误差,使得曲线变得很陡峭,在数学上就表示为线性方程前面的系数很大。

那么模型正则化如何解决上述问题呢?

2. L1正则化

2.1L1正则使用

我们利用第一节得到的数据来对比使用LASSO回归进行正则化的方式。

在sklearn中,包含了一个方法:Lasso。下面我们以Pipeline的方式去封装一个LASSO回归的过程:

from sklearn.linear_model import Lasso

def LassoRegression(degree,alpha):
    return Pipeline([
        ('poly',PolynomialFeatures(degree=degree)),
        ('std_scaler',StandardScaler()),
        ('lasso_reg',Lasso(alpha=alpha))
    ])

在封装好了一个LASSO回归函数后,传入dregree参数和alpha参数,就可以验证LASSO回归的效果了:

lasso_reg1 = LassoRegression(30,0.0001)
lasso_reg1.fit(X_train,y_train)
y1_predict=lasso_reg1.predict(X_test)
mean_squared_error(y_test,y1_predict)
C:\Users\86139\AppData\Local\Continuum\anaconda3\lib\site-packages\sklearn\linear_model\coordinate_descent.py:475: ConvergenceWarning: Objective did not converge. You might want to increase the number of iterations. Duality gap: 31.681767315909042, tolerance: 0.0818236841775706
  positive)





1.5785363435784816
plot_model(lasso_reg1)

可以看到,在加入L1正则后,均方误差比原来小,且曲线光滑了很多,效果比较好。

2.2 调参效果

我们保持degree参数不变,调整alpha参数,让其变大,也就是将L1正则项的比重放大,即让参数 θ \theta θ变小:

lasso_reg2 = LassoRegression(30,0.1)
lasso_reg2.fit(X_train,y_train)
y2_predict=lasso_reg2.predict(X_test)
mean_squared_error(y_test,y2_predict)
1.682308247042419
plot_model(lasso_reg2)

我们发现曲线更加的平滑了,相应的均方误差也变得更小了,说明结果更优了。那么如果继续放大alpha系数呢?

lasso_reg3 = LassoRegression(30,10)
lasso_reg3.fit(X_train,y_train)
y3_predict=lasso_reg3.predict(X_test)
mean_squared_error(y_test,y3_predict)
13.18826674495336
plot_model(lasso_reg3)

很明显,我们正则化得有些过了,变成一条直线了。因此,我们需要找到合适的alpha系数,使正则化效果最好。

3.L2正则化

3.1 L2正则的使用及调参

我们利用第一节得到的数据来对比使用岭回归进行正则化的方式。

在sklearn中,包含了一个岭回归的方法:Ridge。下面我们以Pipeline的方式去封装一个岭回归的过程:

from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
# 需要传入一个多项式项数的参数degree以及一个alpha值
def ridgeregression(degree,alpha):
    return Pipeline([
        ("poly", PolynomialFeatures(degree=degree)),
        ("standard", StandardScaler()),
        ("ridge_reg", Ridge(alpha=alpha))   #alpha值就是正则化那一项的系数
    ])

在封装好了一个岭回归函数后,就可以验证岭回归的效果了:

ridge1_reg = ridgeregression(degree=30,alpha=0.0001)
ridge1_reg.fit(X_train,y_train)
y1_predict = ridge1_reg.predict(X_test)
mean_squared_error(y_test,y1_predict)
1.581865011636001
plot_model(ridge1_reg)

我们可以看到输出的均方误差在1左右,比以前的2点多变好了。且通过画图可以看到,曲线变平滑了。

如果我们调整系数,将其变大,意味着对参数的约束又变强了,曲线会更加光滑:

ridge2_reg = ridgeregression(degree=30,alpha=1)
ridge2_reg.fit(X_train,y_train)
y2_predict = ridge2_reg.predict(X_test)
mean_squared_error(y_test,y2_predict)
1.7020981450451667
plot_model(ridge2_reg)

如果我们继续增大 α \alpha α系数的话,就会正则化得有些过了,其均方误差也会变小。

ridge3_reg = ridgeregression(degree=30,alpha=100)
ridge3_reg.fit(X_train,y_train)
y3_predict = ridge3_reg.predict(X_test)
mean_squared_error(y_test,y3_predict)
3.6974659684812554
plot_model(ridge3_reg)

可见LASSO回归和岭回归类似,取值过大反而会导致误差增加,拟合曲线为直线。但是LASSO更趋向于使得一部分的值为0,拟合曲线更趋向于直线,所以可以作为特征选择来使用,去除一些模型认为不需要的特征。LASSO可能会去除掉正确的特征,从而降低准确度,但如果特征特别大,使用LASSO可以使模型变小。

总结

L1正则化就是在损失函数后边所加正则项为L1范数,加上L1范数容易得到稀疏解(0比较多),一般来说L1正则化较常使用。

L2正则化就是损失后边所加正则项为L2范数,加上L2正则相比于L1正则来说,得到的解比较平滑(不是稀疏),但是同样能够保证解中接近于0(但不是等于0,所以相对平滑)的维度比较多,降低模型的复杂度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值