pytorch l2正则化_20 (理论+代码)理解模型正则化:L1正则、L2正则

9c8929485d3f1a82e9892b2f6bcb4065.png

目录:

  • 0 前言
  • 1 学习模型正则化
    • 1.1 什么是模型正则化
    • 1.2 模型的过拟合
  • 2 L1正则化
    • 2.1 LASSO回归思路
    • 2.2 L1正则化项与稀疏性
    • 2.3 L1正则使用
    • 2.4 调参效果
  • 3 L2正则化
    • 3.1 岭回归思路
    • 3.2 L2正则防止过拟合
    • 3.3 L2正则的使用及调参
  • 总结

0 前言

我们已经知道了模型误差 = 偏差 + 方差 + 不可避免的误差,且在机器学习领域中最重要就是解决过拟合的问题,也就是降低模型的方差。在上一篇文章《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)

821b342b023e0286f71d633d727cb5ef.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()

570e3a6f6bbe16dfbc9a66a4606899dc.png

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

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

2 L1正则化

所谓的L1正则化,就是在目标函数中加了L1范数这一项。使用L1正则化的模型建叫做LASSO回归。

2.1 LASSO回归思路

线性回归问题去怎样求最优解,其目标相当于:

使
尽可能小。

这也就是等同于求原始数据

和使用参数
预测的
的均方误差尽可能的小:
使
尽可能小。

如果模型过拟合的话,参数

就会非常大。为了限制参数
,我们改变损失函数,加入模型正则化,即将其改为:
使
尽可能小。

这样的话,要使

尽可能小,就要综合考虑两项,对于第二项来说,是
的绝对值,因此我们要考虑让
尽可能小。这样参数
就限制住了,曲线也就没有那么陡峭了,这就是一种模型正则化的基本原理。

该模型正则化的方式被称为“LASSO回归”(Least Absolute Shrinkage and Selection Operator Regression)

在这里有几个细节需要注意:

  • ,取值范围是1~n,即不包含
    。这是因为,
    不是任何一个参数的系数,是截距。反映到图形上就是
    反映了曲线的高低,而不决定曲线每一部分的陡峭与缓和。所以模型正则化时不需要。
  • 对于超参数alpha系数,在模型正则化的新的损失函数中,要让每个
    都尽可能小的程度占整个优化损失函数程度的多少。即
    alpha的大小表示优化的侧重。

2.2 L1正则化项与稀疏性

我们说,LASSO回归的全称是:Least Absolute Shrinkage and Selection Operator Regression.

这里面有一个特征选择的部分,或者说L1正则化可以使得参数稀疏化,即得到的参数是一个稀疏矩阵。

所谓稀疏性,说白了就是模型的很多参数是0。通常机器学习中特征数量很多,例如文本处理时,如果将一个词组(term)作为一个特征,那么特征数量会达到上万个(bigram)。在预测或分类时,那么多特征显然难以选择,但是如果代入这些特征得到的模型是一个稀疏模型,很多参数是0,表示只有少数特征对这个模型有贡献,绝大部分特征是没有贡献的,即使去掉对模型也没有什么影响,此时我们就可以只关注系数是非零值的特征

这相当于对模型进行了一次特征选择,只留下一些比较重要的特征提高模型的泛化能力,降低过拟合的可能

假设在二维参数空间中,损失函数的等高线如下图所示

4cb19766145758d73686b0b2e18c3259.png

此时,L1正则化为

,对应的等高线是一个菱形(我们可以画出多个这样的菱形):

3c96a912707d3aa72f8704bc48d789b0.png

首先来看一下不加L1正则的情况:我们使用梯度下降法去优化损失函数,随机选择一点,沿着梯度方向下降,得到一个近似的最优解M:

15d32fc0e7ebcb5d6578b848c005de1f.png

下面加上L1正则,情况则会有所不同。

两点在同一等高线上,即
P与Q两个点的损失函数这一项上是相同的。但是
的距离要大于
距离
:

c67489a84b6e3216591dc30ba85c2b27.png

可以得到经验损失函数(损失函数+正则项):

因为点

的L1范数小于点
的L1范数,因此我们更倾向于选择点
,而不是点

而如果选择点

,在直角的顶点上,对应的参数
,这就体现了稀疏性。
因此L1正则化会产生系数模型,好处是应用的特征比较小,模型更简单,运算更快。

由此可见:加入L1正则项相当于倾向将参数向离原点近的方向去压缩。直观上来说,就是加上正则项,参数空间会被缩小,意味着模型的复杂度会变小。

2.3 L1正则使用

我们利用第一节得到的数据来对比使用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)
# 输出:0.8965099322966458
plot_model(lasso_reg1)

8bdc36c7df3b4ea73b64014ddea0a99b.png

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

2.4 调参效果

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

变小:
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)
# 输出:0.7848672707093821
plot_model(lasso_reg2)

6d934f19d20adbe4fe8ac6a9793fd5f9.png

我们发现曲线更加的平滑了,相应的均方误差也变得更小了,说明结果更优了。那么如果继续放大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)
# 输出:12.007790775597146
plot_model(lasso_reg3)

98af70c58b83a62ed8b20cfecc714375.png

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

3 L2正则化

3.1 岭回归思路

除了如L1正则化一般,将参数累加(

)以外,很自然地联想到,我们也可以用平方和来做正则项。

即将为:

使
尽可能小。

同样地,要使

尽可能小,就要综合考虑两项,要考虑让
的平方和尽可能小。

该模型正则化的方式被称为“岭回归”

3.2 L2正则防止过拟合

同样地,在二维参数空间中,L2正则项为:

。即L2等高线是一个个的同心圆。

4b266de1bd0f8c925ab99e8380203361.png

二维平面下L2正则化的函数图形是个圆,与方形相比,被磨去了棱角。因此等高线与损失函数相交于

点时,
都不为0,但是仍然比较靠近坐标轴。因此这也就是我们说的,
L2范数能让解比较小(靠近0),但是比较平滑(不等于0)且不具有稀疏性。

此时和w2都不为0. 所以L2范式得到的不是稀疏解

88b1cc8e9f8275b061192364c027e7e3.png

3.3 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.00677921937119
plot_model(ridge1_reg)

2f470443f74b488db94735256d1a31a0.png

我们可以看到输出的均方误差在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.0074844695164857
plot_model(ridge2_reg)

2547274149814e95e64c3b1cfd20c9c0.png

如果我们继续增大

系数的话,就会正则化得有些过了,其均方误差也会变小。
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.4183903466684176
plot_model(ridge3_reg)

0cb10b04749b26b307facfb75dd18c79.png

可见LASSO回归和岭回归类似,

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

总结

L1正则化就是在loss function后边所加正则项为L1范数,加上L1范数容易得到稀疏解(0比较多)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值