理解模型正則化:L1正則、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)

下面我們要使用多項式回歸過擬合一個樣本,生成的曲線非常彎曲、陡峭。前面的參數會非常大,正則化要完成的,就是要限制這些系數的大小。
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()

在擬合完之后,就是非常明顯的過擬合的效果,即目標函數為了盡可能地去擬合數據,減小模型和樣本的誤差,使得曲線變得很陡峭,在數學上就表示為線性方程前面的系數很大。
那么模型正則化如何解決上述問題呢?
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,表示只有少數特征對這個模型有貢獻,絕大部分特征是沒有貢獻的,即使去掉對模型也沒有什么影響,此時我們就可以只關注系數是非零值的特征。
這相當於對模型進行了一次特征選擇,只留下一些比較重要的特征,提高模型的泛化能力,降低過擬合的可能。
假設在二維參數空間中,損失函數的等高線如下圖所示

此時,L1正則化為,對應的等高線是一個菱形(我們可以畫出多個這樣的菱形):

首先來看一下不加L1正則的情況:我們使用梯度下降法去優化損失函數,隨機選擇一點,沿着梯度方向下降,得到一個近似的最優解M:

下面加上L1正則,情況則會有所不同。
兩點在同一等高線上,即P與Q兩個點的損失函數這一項上是相同的。但是
的距離要大於
距離:

可以得到經驗損失函數(損失函數+正則項):
因為點的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)

可以看到,在加入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)

我們發現曲線更加的平滑了,相應的均方誤差也變得更小了,說明結果更優了。那么如果繼續放大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)

很明顯,我們正則化得有些過了,變成一條直線了。因此,我們需要找到合適的alpha
系數,使正則化效果最好。
3 L2正則化
3.1 嶺回歸思路
除了如L1正則化一般,將參數累加()以外,很自然地聯想到,我們也可以用平方和來做正則項。
即將為:
使盡可能小。
同樣地,要使盡可能小,就要綜合考慮兩項,要考慮讓
的平方和盡可能小。
該模型正則化的方式被稱為“嶺回歸”
3.2 L2正則防止過擬合
同樣地,在二維參數空間中,L2正則項為:。即L2等高線是一個個的同心圓。

二維平面下L2正則化的函數圖形是個圓,與方形相比,被磨去了棱角。因此等高線與損失函數相交於點時,
都不為0,但是仍然比較靠近坐標軸。因此這也就是我們說的,L2范數能讓解比較小(靠近0),但是比較平滑(不等於0)且不具有稀疏性。
此時和w2都不為0. 所以L2范式得到的不是稀疏解

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)

我們可以看到輸出的均方誤差在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)

如果我們繼續增大系數的話,就會正則化得有些過了,其均方誤差也會變小。
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)

可見LASSO回歸和嶺回歸類似,取值過大反而會導致誤差增加,擬合曲線為直線。但是LASSO更趨向於使得一部分的
值為0,擬合曲線更趨向於直線,所以可以作為特征選擇來使用,去除一些模型認為不需要的特征。 LASSO可能會去除掉正確的特征,從而降低准確度,但如果特征特別大,使用LASSO可以使模型變小。
總結
L1正則化就是在loss function后邊所加正則項為L1范數,加上L1范數容易得到稀疏解(0比較多)。
L2正則化就是loss function后邊所加正則項為L2范數的平方,加上L2正則相比於L1正則來說,得到的解比較平滑(不是稀疏),但是同樣能夠保證解中接近於0(但不是等於0,所以相對平滑)的維度比較多,降低模型的復雜度。