引言
在机器学习中,正则化(Regularization)是一种技术,用于减少模型复杂度,防止过拟合,并提高模型的泛化能力。通过在损失函数中添加一个额外的惩罚项,正则化鼓励模型学习更简单、更平滑的函数,从而在未见过的数据上表现得更好
文章目录
- 引言
- 一、正则化
- 1.1 正则化的形式
- 1.1.1 L1 正则化(Lasso 回归)
- 1.1.2 L2 正则化(Ridge 回归)
- 1.1.3 Elastic Net 正则化
- 1.2 正则化的优点
- 1.2.1 防止过拟合
- 1.2.1 特征选择
- 1.2.1 参数稳定性
- 1.3 正则化的缺点
- 1.3.1 增加模型复杂度
- 1.3.2 参数选择
- 二、正则化成本和梯度
一、正则化
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 目标
- 将先前的线性回归和对数几率回归的成本函数扩展一个正则化项
- 在添加了正则化项后,重新运行之前过拟合的示例
python">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 循环
python">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.dotcost = cost + (f_wb_i - y[i])**2 #scalar cost = cost / (2 * m) #scalar reg_cost = 0for j in range(n):reg_cost += (w[j]**2) #scalarreg_cost = (lambda_/(2*m)) * reg_cost #scalartotal_cost = cost + reg_cost #scalarreturn total_cost #scalar
运行下面的代码以查看它的效果
python">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没有被正则化,这是标准做法
python">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.shapecost = 0.for i in range(m):z_i = np.dot(X[i], w) + b #(n,)(n,)=scalar, see np.dotf_wb_i = sigmoid(z_i) #scalarcost += -y[i]*np.log(f_wb_i) - (1-y[i])*np.log(1-f_wb_i) #scalarcost = cost/m #scalarreg_cost = 0for j in range(n):reg_cost += (w[j]**2) #scalarreg_cost = (lambda_/(2*m)) * reg_cost #scalartotal_cost = cost + reg_cost #scalarreturn total_cost #scalar
运行下面的代码以查看它的效果
python">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 正则化逻辑回归的梯度函数
python">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.shapedj_dw = np.zeros((n,)) #(n,)dj_db = 0.0 #scalarfor i in range(m):f_wb_i = sigmoid(np.dot(X[i],w) + b) #(n,)(n,)=scalarerr_i = f_wb_i - y[i] #scalarfor j in range(n):dj_dw[j] = dj_dw[j] + err_i * X[i,j] #scalardj_db = dj_db + err_idj_dw = dj_dw/m #(n,)dj_db = dj_db/m #scalarfor j in range(n):dj_dw[j] = dj_dw[j] + (lambda_/m) * w[j]return dj_db, dj_dw
运行下面的代码以查看它的效果
python">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 正则化逻辑回归的梯度函数
python">
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.shapedj_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_idj_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
运行以下代码以查看效果
python">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 重新运行过拟合示例:
python">plt.close("all")
display(output)
ofit = overfit_example(True)
在上面的图表中,尝试对之前的示例使用正则化。特别是:
分类(逻辑回归):
-
将多项式次数设置为6,正则化参数lambda设置为0(无正则化),拟合数据
输出结果:
-
现在将lambda设置为1(增加正则化),拟合数据,注意差异
输出结果:
回归(线性回归):
-
将多项式次数设置为6,正则化参数lambda设置为0(无正则化),拟合数据
输出结果:
-
现在将lambda设置为1(增加正则化),拟合数据,注意差异
输出结果:
2.10 总结
- 为线性回归和逻辑回归添加了成本和梯度例程的示例
- 发展出一些关于正则化如何减少过拟合的直觉