引言
在机器学习中,正则化(Regularization)是一种技术,用于减少模型复杂度,防止过拟合,并提高模型的泛化能力。通过在损失函数中添加一个额外的惩罚项,正则化鼓励模型学习更简单、更平滑的函数,从而在未见过的数据上表现得更好
文章目录
一、正则化
1.1 正则化的形式
1.1.1 L1 正则化(Lasso 回归)
- 惩罚项: λ ∑ j = 1 n ∣ w j ∣ \lambda \sum_{j=1}^{n} |w_j| λ∑j=1n∣wj∣
- 效果:不仅减少模型复杂度,还能实现特征选择,自动缩小权重
1.1.2 L2 正则化(Ridge 回归)
- 惩罚项: λ ∑ j = 1 n w j 2 \lambda \sum_{j=1}^{n} w_j^2 λ∑j=1nwj2
- 效果:减少模型复杂度,但不自动缩小权重
1.1.3 Elastic Net 正则化
- 惩罚项: λ ( α ∑ j = 1 n ∣ w j ∣ + ( 1 − α ) ∑ j = 1 n w j 2 ) \lambda \left( \alpha \sum_{j=1}^{n} |w_j| + (1 - \alpha) \sum_{j=1}^{n} w_j^2 \right) λ(α∑j=1n∣wj∣+(1−α)∑j=1nwj2)
- 效果:结合了 L1 和 L2 正则化的优点,可以实现特征选择和减少模型复杂度
1.2 正则化的优点
1.2.1 防止过拟合
通过减少模型复杂度,正则化有助于模型在未见过的数据上表现得更好
1.2.1 特征选择
某些类型的正则化(如 Lasso)可以自动缩小权重,从而实现特征选择
1.2.1 参数稳定性
正则化有助于避免模型对噪声的敏感性,提高参数的稳定性
1.3 正则化的缺点
1.3.1 增加模型复杂度
正则化需要额外的参数(如 lambda),这可能会增加模型的复杂度
1.3.2 参数选择
正则化参数(如 lambda)的选择对模型的性能有很大影响,需要通过交叉验证等方法来确定最佳值
在实际应用中,正则化是一种非常有效的技术,可以显著提高机器学习模型的性能。
二、正则化成本和梯度
2.1 目标
- 将先前的线性回归和对数几率回归的成本函数扩展一个正则化项
- 在添加了正则化项后,重新运行之前过拟合的示例
import numpy as np
%matplotlib widget
import matplotlib.pyplot as plt
from plt_overfit import overfit_example, output
from lab_utils_common import sigmoid
np.set_printoptions(precision=8)
2.2 添加正则化
上图展示了线性回归和对数几率回归的成本和梯度函数
注意:
- 成本:线性回归和对数几率回归的成本函数有显著差异,但向方程中添加正则化的方式是相同的
- 梯度:线性回归和对数几率回归的梯度函数非常相似。它们仅在实现 𝑓𝑤𝑏 时有所不同
2.3带有正则化的成本函数
2.3.1 正则化线性回归的成本函数
正则化线性回归的成本函数方程为:
J
(
w
,
b
)
=
1
2
m
∑
i
=
0
m
−
1
(
f
w
,
b
(
x
(
i
)
)
−
y
(
i
)
)
2
+
λ
2
m
∑
j
=
0
n
−
1
w
j
2
J(\mathbf{w}, b) = \frac{1}{2m} \sum_{i=0}^{m-1} (f_{\mathbf{w}, b}(\mathbf{x}^{(i)}) - y^{(i)})^2 + \frac{\lambda}{2m} \sum_{j=0}^{n-1} w_j^2
J(w,b)=2m1i=0∑m−1(fw,b(x(i))−y(i))2+2mλj=0∑n−1wj2
其中:
f
w
,
b
(
x
(
i
)
)
=
w
⋅
x
(
i
)
+
b
f_{\mathbf{w}, b}(\mathbf{x}^{(i)}) = \mathbf{w} \cdot \mathbf{x}^{(i)} + b
fw,b(x(i))=w⋅x(i)+b
与之前实验中实现的没有正则化的成本函数相比,该函数的形式为:
J
(
w
,
b
)
=
1
2
m
∑
i
=
0
m
−
1
(
f
w
,
b
(
x
(
i
)
)
−
y
(
i
)
)
2
J(\mathbf{w}, b) = \frac{1}{2m} \sum_{i=0}^{m-1} (f_{\mathbf{w}, b}(\mathbf{x}^{(i)}) - y^{(i)})^2
J(w,b)=2m1∑i=0m−1(fw,b(x(i))−y(i))2
- 不同之处在于正则化项,即 λ 2 m ∑ j = 0 n − 1 w j 2 \frac{\lambda}{2m} \sum_{j=0}^{n-1} w_j^2 2mλ∑j=0n−1wj2
包含这个项可以激励梯度下降最小化参数的大小
注意,在这个例子中,参数 b b b没有被正则化,这是标准做法
下面是方程(1)和(2)的实现,对所有 m 个示例进行 for 循环
def compute_cost_linear_reg(X, y, w, b, lambda_ = 1):
"""
计算所有示例的成本
参数:
X (ndarray (m,n)):数据,m 个示例,每个示例有 n 个特征
y (ndarray (m,)):目标值
w (ndarray (n,)):模型参数
b (scalar) :模型参数
lambda_ (scalar) :控制正则化量
返回:
total_cost (scalar):成本
"""
m = X.shape[0]
n = len(w)
cost = 0.
for i in range(m):
f_wb_i = np.dot(X[i], w) + b #(n,)(n,)=scalar, see np.dot
cost = cost + (f_wb_i - y[i])**2 #scalar
cost = cost / (2 * m) #scalar
reg_cost = 0
for j in range(n):
reg_cost += (w[j]**2) #scalar
reg_cost = (lambda_/(2*m)) * reg_cost #scalar
total_cost = cost + reg_cost #scalar
return total_cost #scalar
运行下面的代码以查看它的效果
np.random.seed(1)
X_tmp = np.random.rand(5,6)
y_tmp = np.array([0,1,0,1,0])
w_tmp = np.random.rand(X_tmp.shape[1]).reshape(-1,)-0.5
b_tmp = 0.5
lambda_tmp = 0.7
cost_tmp = compute_cost_linear_reg(X_tmp, y_tmp, w_tmp, b_tmp, lambda_tmp)
print("Regularized cost:", cost_tmp)
输出结果:
预期输出:
正则化成本: 0.07917239320214275
2.3 正则化逻辑回归的成本函数
对于正则化逻辑回归,成本函数的形式为
J
(
w
,
b
)
=
1
m
∑
i
=
0
m
−
1
[
−
y
(
i
)
log
(
f
w
,
b
(
x
(
i
)
)
)
−
(
1
−
y
(
i
)
)
log
(
1
−
f
w
,
b
(
x
(
i
)
)
)
]
+
λ
2
m
∑
j
=
0
n
−
1
w
j
2
J(\mathbf{w}, b) = \frac{1}{m} \sum_{i=0}^{m-1} [-y^{(i)} \log(f_{\mathbf{w}, b}(\mathbf{x}^{(i)})) - (1 - y^{(i)}) \log(1 - f_{\mathbf{w}, b}(\mathbf{x}^{(i)}))] + \frac{\lambda}{2m} \sum_{j=0}^{n-1} w_j^2
J(w,b)=m1i=0∑m−1[−y(i)log(fw,b(x(i)))−(1−y(i))log(1−fw,b(x(i)))]+2mλj=0∑n−1wj2
其中:
f
w
,
b
(
x
(
i
)
)
=
σ
(
w
⋅
x
(
i
)
+
b
)
f_{\mathbf{w}, b}(\mathbf{x}^{(i)}) = \sigma(\mathbf{w} \cdot \mathbf{x}^{(i)} + b)
fw,b(x(i))=σ(w⋅x(i)+b)
与之前实验中实现的没有正则化的成本函数相比,该函数的形式为:
J
(
w
,
b
)
=
1
m
∑
i
=
0
m
−
1
[
−
y
(
i
)
log
(
f
w
,
b
(
x
(
i
)
)
)
−
(
1
−
y
(
i
)
)
log
(
1
−
f
w
,
b
(
x
(
i
)
)
J(\mathbf{w}, b) = \frac{1}{m} \sum_{i=0}^{m-1} [-y^{(i)} \log(f_{\mathbf{w}, b}(\mathbf{x}^{(i)})) - (1 - y^{(i)}) \log(1 - f_{\mathbf{w}, b}(\mathbf{x}^{(i)})
J(w,b)=m1∑i=0m−1[−y(i)log(fw,b(x(i)))−(1−y(i))log(1−fw,b(x(i))
正如在线性回归中一样,差异在于正则化项,即
λ
2
m
∑
j
=
0
n
−
1
w
j
2
\frac{\lambda}{2m} \sum_{j=0}^{n-1} w_j^2
2mλ∑j=0n−1wj2
包含这个项可以激励梯度下降最小化参数的大小,注意,在这个例子中,参数
b
b
b没有被正则化,这是标准做法
def compute_cost_logistic_reg(X, y, w, b, lambda_ = 1):
"""
计算所有示例的成本
参数:
X (ndarray (m,n): 数据,m 个示例,每个示例有 n 个特征
y (ndarray (m,)): 目标值
w (ndarray (n,)): 模型参数
b (scalar) : 模型参数
lambda_ (scalar): 控制正则化量
返回:
total_cost (scalar): 成本
"""
m,n = X.shape
cost = 0.
for i in range(m):
z_i = np.dot(X[i], w) + b #(n,)(n,)=scalar, see np.dot
f_wb_i = sigmoid(z_i) #scalar
cost += -y[i]*np.log(f_wb_i) - (1-y[i])*np.log(1-f_wb_i) #scalar
cost = cost/m #scalar
reg_cost = 0
for j in range(n):
reg_cost += (w[j]**2) #scalar
reg_cost = (lambda_/(2*m)) * reg_cost #scalar
total_cost = cost + reg_cost #scalar
return total_cost #scalar
运行下面的代码以查看它的效果
np.random.seed(1)
X_tmp = np.random.rand(5,6)
y_tmp = np.array([0,1,0,1,0])
w_tmp = np.random.rand(X_tmp.shape[1]).reshape(-1,)-0.5
b_tmp = 0.5
lambda_tmp = 0.7
cost_tmp = compute_cost_logistic_reg(X_tmp, y_tmp, w_tmp, b_tmp, lambda_tmp)
print("正则化成本:", cost_tmp)
结果输出:
预期输出:
正则化成本: 0.6850849138741673
2.4 带有正则化的梯度下降
运行梯度下降的基本算法在正则化后并没有改变,它是:
repeat until convergence:
{
w
j
=
w
j
−
α
∂
J
(
w
,
b
)
∂
w
j
for j := 0..n-1
b
=
b
−
α
∂
J
(
w
,
b
)
∂
b
}
\begin{align*} &\text{repeat until convergence:} \; \lbrace \\ & \; \; \;w_j = w_j - \alpha \frac{\partial J(\mathbf{w},b)}{\partial w_j} \tag{1} \; & \text{for j := 0..n-1} \\ & \; \; \; \; \;b = b - \alpha \frac{\partial J(\mathbf{w},b)}{\partial b} \\ &\rbrace \end{align*}
repeat until convergence:{wj=wj−α∂wj∂J(w,b)b=b−α∂b∂J(w,b)}for j := 0..n-1(1)
在每次迭代中,对所有
w
j
w_j
wj 进行同时更新。
正则化后,变化的是计算梯度的方法。
2.5 带有正则化的梯度计算(线性/逻辑回归)
对于线性回归和逻辑回归,梯度计算几乎相同,仅在计算
f
w
,
b
(
x
)
f_{\mathbf{w}, b}(\mathbf{x})
fw,b(x) 时有所不同
∂
J
(
w
,
b
)
∂
w
j
=
1
m
∑
i
=
0
m
−
1
(
f
w
,
b
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
+
λ
m
w
j
∂
J
(
w
,
b
)
∂
b
=
1
m
∑
i
=
0
m
−
1
(
f
w
,
b
(
x
(
i
)
)
−
y
(
i
)
)
\begin{align*} \frac{\partial J(\mathbf{w},b)}{\partial w_j} &= \frac{1}{m} \sum\limits_{i = 0}^{m-1} (f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)})x_{j}^{(i)} + \frac{\lambda}{m} w_j \tag{2} \\ \frac{\partial J(\mathbf{w},b)}{\partial b} &= \frac{1}{m} \sum\limits_{i = 0}^{m-1} (f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)}) \tag{3} \end{align*}
∂wj∂J(w,b)∂b∂J(w,b)=m1i=0∑m−1(fw,b(x(i))−y(i))xj(i)+mλwj=m1i=0∑m−1(fw,b(x(i))−y(i))(2)(3)
其中:
- m m m 是数据集中的训练示例数
f w , b ( x ) f_{\mathbf{w}, b}(\mathbf{x}) fw,b(x) 是模型的预测,而 y y y是目标
- 对于线性回归模型: f w , b ( x ) = w ⋅ x + b f_{\mathbf{w}, b}(\mathbf{x}) = \mathbf{w} \cdot \mathbf{x} + b fw,b(x)=w⋅x+b
- 对于逻辑回归模型:
z
=
w
⋅
x
+
b
z = \mathbf{w} \cdot \mathbf{x} + b
z=w⋅x+b,
f
w
,
b
(
x
)
=
σ
(
z
)
f_{\mathbf{w}, b}(\mathbf{x}) = \sigma(z)
fw,b(x)=σ(z)
其中 σ ( z ) \sigma(z) σ(z) 是sigmoid
函数: σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
添加正则化的项是 λ m w j \frac{\lambda}{m} w_j mλwj
2.6 正则化逻辑回归的梯度函数
def compute_gradient_logistic_reg(X, y, w, b, lambda_):
"""
计算逻辑回归的梯度
参数:
X (ndarray (m,n): 数据,m 个示例,每个示例有 n 个特征
y (ndarray (m,)): 目标值
w (ndarray (n,)): 模型参数
b (scalar) : 模型参数
lambda_ (scalar): 控制正则化量
返回:
dj_dw (ndarray Shape (n,)): 成本相对于参数 w 的梯度。
dj_db (scalar) : 成本相对于参数 b 的梯度。
"""
m,n = X.shape
dj_dw = np.zeros((n,)) #(n,)
dj_db = 0.0 #scalar
for i in range(m):
f_wb_i = sigmoid(np.dot(X[i],w) + b) #(n,)(n,)=scalar
err_i = f_wb_i - y[i] #scalar
for j in range(n):
dj_dw[j] = dj_dw[j] + err_i * X[i,j] #scalar
dj_db = dj_db + err_i
dj_dw = dj_dw/m #(n,)
dj_db = dj_db/m #scalar
for j in range(n):
dj_dw[j] = dj_dw[j] + (lambda_/m) * w[j]
return dj_db, dj_dw
运行下面的代码以查看它的效果
np.random.seed(1)
X_tmp = np.random.rand(5,3)
y_tmp = np.array([0,1,0,1,0])
w_tmp = np.random.rand(X_tmp.shape[1])
b_tmp = 0.5
lambda_tmp = 0.7
dj_db_tmp, dj_dw_tmp = compute_gradient_logistic_reg(X_tmp, y_tmp, w_tmp, b_tmp, lambda_tmp)
print(f"dj_db: {dj_db_tmp}", )
print(f"Regularized dj_dw:\n {dj_dw_tmp.tolist()}", )
输出结果:
预期输出
dj_db: 0.6648774569425726
正则化 dj_dw:
[0.29653214748822276, 0.4911679625918033, 0.21645877535865857]
2.7 正则化逻辑回归的梯度函数
def compute_gradient_logistic_reg(X, y, w, b, lambda_):
"""
计算线性回归的梯度
参数:
X (ndarray (m,n)): 数据,m个示例,每个示例有n个特征
y (ndarray (m,)): 目标值
w (ndarray (n,)): 模型参数
b (标量) : 模型参数
lambda_ (标量) : 控制正则化的程度
返回
dj_dw (ndarray 形状 (n,)): 成本关于参数w的梯度。
dj_db (标量) : 成本关于参数b的梯度。
"""
m, n = X.shape
dj_dw = np.zeros((n,)) #(n,)
dj_db = 0.0 #标量
for i in range(m):
f_wb_i = sigmoid(np.dot(X[i], w) + b) #(n,)(n,)=标量
err_i = f_wb_i - y[i] #标量
for j in range(n):
dj_dw[j] = dj_dw[j] + err_i * X[i, j] #标量
dj_db = dj_db + err_i
dj_dw = dj_dw / m #(n,)
dj_db = dj_db / m #标量
for j in range(n):
dj_dw[j] = dj_dw[j] + (lambda_ / m) * w[j]
return dj_db, dj_dw
运行以下代码以查看效果
np.random.seed(1)
X_tmp = np.random.rand(5, 3)
y_tmp = np.array([0, 1, 0, 1, 0])
w_tmp = np.random.rand(X_tmp.shape[1])
b_tmp = 0.5
lambda_tmp = 0.7
dj_db_tmp, dj_dw_tmp = compute_gradient_logistic_reg(X_tmp, y_tmp, w_tmp, b_tmp, lambda_tmp)
print(f"dj_db: {dj_db_tmp}")
print(f"Regularized dj_dw:\n {dj_dw_tmp.tolist()}")
输出结果:
预期输出:
dj_db: 0.341798994972791
正则化后的dj_dw:
[0.17380012933994293, 0.32007507881566943, 0.10776313396851499]
2.8 重新运行过拟合示例:
plt.close("all")
display(output)
ofit = overfit_example(True)
在上面的图表中,尝试对之前的示例使用正则化。特别是:
分类(逻辑回归):
-
将多项式次数设置为6,正则化参数lambda设置为0(无正则化),拟合数据
输出结果:
-
现在将lambda设置为1(增加正则化),拟合数据,注意差异
输出结果:
回归(线性回归):
-
将多项式次数设置为6,正则化参数lambda设置为0(无正则化),拟合数据
输出结果:
-
现在将lambda设置为1(增加正则化),拟合数据,注意差异
输出结果:
2.10 总结
- 为线性回归和逻辑回归添加了成本和梯度例程的示例
- 发展出一些关于正则化如何减少过拟合的直觉