#引言
在机器学习中,特征缩放和学习率是两个非常重要的概念,它们对模型的性能和训练速度有显著影响。
特征缩放是指将数据集中的特征值缩放到一个固定的范围内,通常是在0到1之间或者标准化到均值为0、方差为1。特征缩放对于模型的训练至关重要,因为它可以防止某些特征在模型中占据主导地位,从而影响模型的性能。
学习率是梯度下降算法中的一个超参数,它控制每次迭代中参数更新的大小。学习率的选择对算法的收敛速度和性能有重要影响。
文章目录
- 一、梯度下降函数如何判断收敛
- 1.1 **梯度的范数**
- 1.2 **目标函数值的变化**
- 1.3 **迭代次数**
- 1.4 **收敛曲线图**
- 二、如何调整学习率
- 2.1 **固定学习率**
- 2.2 **学习率衰减**
- 2.3 **手动调整**
- 2.4 **使用学习率查找**
- 2.5 **学习率调度器**
- 2.6 **自适应方法**
- 三、特征缩放和学习率的调整
- 3.1 工具
- 3.2 问题陈述
- 3.3 多变量梯度下降
- 3.4 学习率
- 3.4.1 𝛼 = 9.9e-7
- 3.4.2 𝛼 = 9e-7
- 3.4.3 𝛼 = 1e-7
- 3.5 特征缩放
- 3.5.1 详情
- 3.5.2 Z-分数标准化
- 3.5.3 实现
- 3.5.4 预测
- 3.5.5 成本轮廓
- 四、总结
一、梯度下降函数如何判断收敛
在机器学习中,判断梯度下降算法是否收敛通常有以下几种方法:
1.1 梯度的范数
当梯度的范数趋近于零时,可以认为算法已经收敛。此时,梯度已经无法对目标函数进行更好的优化。通常,可以通过设置一个非常小的阈值来判断梯度的范数是否小于此阈值。
1.2 目标函数值的变化
当目标函数值的变化小到一定程度时,可以认为算法已经收敛。可以比较当前迭代步骤的目标函数值与前一个步骤的目标函数值,如果二者之间的差异小于一个预定义的小值(比如一个非常小的阈值),则可判定为收敛。
1.3 迭代次数
设定一个最大迭代次数,当达到最大迭代次数时,算法可以被认为已经收敛。这种判断方法没有考虑实际的优化进展情况,但可以作为一个迭代的上限。
1.4 收敛曲线图
记录每次迭代的目标函数值,并将其绘制成曲线图。通过观察曲线图的趋势,可以大致判断算法是否收敛。如果曲线趋于平缓并趋近于目标函数的极小值点,可以认为算法已经收敛。
收敛性并不意味着找到了全局最优解,而只是指算法达到了一定停止条件。因此,在实际应用中,需要根据问题的具体情况和需求来选择合适的判断方法,并对结果进行进一步验证和分析
二、如何调整学习率
调整学习率是机器学习中优化算法的一个重要方面。以下是一些常用的方法来调整学习率:
2.1 固定学习率
这是最简单的方法,即在整个训练过程中保持学习率不变。但这种方法可能不会在所有情况下都有效,因为它可能太慢而不能快速收敛,或者太大而导致无法收敛。
2.2 学习率衰减
- 步进衰减:每经过一定的迭代次数后,学习率乘以一个衰减因子(例如0.1)。
- 指数衰减:学习率以指数形式衰减,例如每一步乘以一个小于1的常数(例如0.99)。
- 逆时间衰减:学习率与迭代次数的倒数成比例,例如学习率 = l r i n i t i a l 1 + d e c a y × e p o c h \frac{lr_{initial}}{1 + decay \times epoch} 1+decay×epochlrinitial。
2.3 手动调整
根据经验或观察训练过程中的损失函数值手动调整学习率。
2.4 使用学习率查找
- 网格搜索:在预定义的学习率范围内,通过尝试不同的学习率并选择最佳的一个。
- 随机搜索:在可能的学习率范围内随机选择学习率,并评估其性能。
2.5 学习率调度器
- ReduceLROnPlateau:当指标停止改进时减少学习率。
- Warm Restarts(如SGDR):周期性地重新启动学习率。
2.6 自适应方法
- Adam、RMSprop等优化器:这些优化器会根据训练过程中的统计信息自动调整学习率。
选择合适的学习率调整策略通常依赖于具体问题和数据集。以下是一些通用建议: - 开始时可以使用较小的学习率,以避免训练过程中的不稳定。
- 使用学习率衰减策略可以帮助算法在训练初期快速学习,在后期细化权重。
- 可以通过监控验证集的性能来调整学习率,当性能不再提升时降低学习率。
- 使用学习率查找和学习率调度器可以自动化这一过程,但可能需要更多的计算资源。
调整学习率是一个需要根据实际情况进行实验和调整的过程
三、特征缩放和学习率的调整
3.1 工具
使用上一个实验中开发的函数以及matplotlib和NumPy
# 导入numpy库
import numpy as np
np.set_printoptions(precision=2)
# 导入matplotlib库
import matplotlib.pyplot as plt
# 定义颜色变量
dlblue = '#0096ff'; dlorange = '#FF9300'; dldarkred='#C00000'; dlmagenta='#FF40FF'; dlpurple='#7030A0';
# 设置绘图风格
plt.style.use('./deeplearning.mplstyle')
# 从lab_utils_multi导入函数
from lab_utils_multi import load_house_data, compute_cost, run_gradient_descent
from lab_utils_multi import norm_plot, plt_contour_multi, plt_equal_scale, plot_cost_i_w
符号表示
通用符号表示 | 描述 | Python |
---|---|---|
𝑎 | 标量,非粗体 | |
𝐚 | 向量,粗体 | |
𝐀 | 矩阵,粗体大写 | |
回归 | ||
𝐗 | 训练示例矩阵 | X_train |
𝐲 | 训练示例目标 | y_train |
𝐱(𝑖), 𝑦(𝑖) | 第𝑖个训练示例 | X[i], y[i] |
m | 训练示例的数量 | m |
n | 每个示例中的特征数量 | n |
𝐰 | 参数:权重 | w |
𝑏 | 参数:偏置 | b |
𝑓𝐰,𝑏(𝐱(𝑖)) | 在𝐱(𝑖)处由𝐰,𝑏参数化的模型评估结果:𝑓𝐰,𝑏(𝐱(𝑖))=𝐰⋅𝐱(𝑖)+𝑏 | f_wb |
∂𝐽(𝐰,𝑏)∂𝑤𝑗 | 关于参数𝑤𝑗的成本的梯度或偏导数 | dj_dw[j] |
∂𝐽(𝐰,𝑏)∂𝑏 | 关于参数𝑏的成本的梯度或偏导数 | dj_db |
3.2 问题陈述
与之前的实验一样,将使用房价预测的激励示例。训练数据集包含许多示例,每个示例有4个特征(大小、卧室数量、楼层和房龄),如下表所示。
注意,在本实验中,Size特征是以平方英尺为单位。我们希望建立一个线性回归模型,使用这些值来预测其他房屋的价格——比如说,一个1200平方英尺、3个卧室、1层、40年房龄的房屋
数据集:
Size/平方英尺 | 卧室数量 | 楼层 | 房龄 | 价格/千美元 |
---|---|---|---|---|
952 | 2 | 1 | 65 | 271.5 |
1244 | 3 | 2 | 64 | 232 |
1947 | 3 | 2 | 17 | 509.8 |
# 加载数据集
X_train, y_train = load_house_data()
X_features = ['size(sqft)','bedrooms','floors','age']
# 让我们通过绘制每个特征与价格的关系来查看数据集及其特征
fig,ax=plt.subplots(1, 4, figsize=(12, 3), sharey=True)
for i in range(len(ax)):
ax[i].scatter(X_train[:,i],y_train)
ax[i].set_xlabel(X_features[i])
ax[0].set_ylabel("Price (1000's)")
plt.show()
输出结果:
绘制每个特征与目标价格的关系图,可以提供一些指示,哪些特征对价格的影响最大
- 房屋大小的增加也导致了价格的上升
- 卧室数量和楼层似乎对价格没有太大影响
- 新房子比旧房子的价格要高
3.3 多变量梯度下降
以下是在上一个实验中您开发的关于多变量梯度下降的方程式:
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}&\text{ until convergence:} \; \lbrace \newline\; & w_j := w_j - \alpha \frac{\partial J(\mathbf{w},b)}{\partial w_j} \tag{1} \; & \text{for j = 0..n-1}\newline &b\ \ := b - \alpha \frac{\partial J(\mathbf{w},b)}{\partial b} \newline \rbrace \end{align*}
repeat} until convergence:{wj:=wj−α∂wj∂J(w,b)b :=b−α∂b∂J(w,b)for j = 0..n-1(1)
其中,n是特征的数量,参数𝑤𝑗, 𝑏同时更新,并且
∂
J
(
w
,
b
)
∂
w
j
=
1
m
∑
i
=
0
m
−
1
(
f
w
,
b
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
∂
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)} \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)=m1i=0∑m−1(fw,b(x(i))−y(i))(2)(3)
m是数据集中的训练示例数量
f
w
,
b
(
x
(
i
)
)
f_{\mathbf{w},b}(\mathbf{x}^{(i)})
fw,b(x(i))是模型的预测,而
y
(
i
)
y^{(i)}
y(i)是目标值
3.4 学习率
讲座中讨论了设置学习率𝛼的一些问题。学习率控制参数更新的大小。见上面的方程式(1)。它被所有参数共享。
让我们在数据集上运行梯度下降,并尝试几种𝛼的设置
3.4.1 𝛼 = 9.9e-7
# 将alpha设置为9.9e-7
_, _, hist = run_gradient_descent(X_train, y_train, 10, alpha = 9.9e-7)
输出结果:
学习率太高了,解决方案没有收敛,成本在增加而不是减少。让我们绘制结果:
plot_cost_i_w(X_train, y_train, hist)
绘制结果:
右边的图显示了参数 w 0 w_0 w0的值。在每次迭代中,它都超过了最佳值,结果成本增加而不是接近最小值。请注意,这并不是一个完全准确的画面,因为每次传递时有4个参数被修改,而不仅仅是一个。这个图只显示了 w 0 w_0 w0,而其他参数固定在良性值。在此图和后续图中,您可能会注意到蓝色和橙色线条略有偏差。
3.4.2 𝛼 = 9e-7
让我们尝试一个稍小的值,看看会发生什么
# 将alpha设置为9e-7
_,_,hist = run_gradient_descent(X_train, y_train, 10, alpha = 9e-7)
输出结果:
成本在运行过程中一直在减少,表明𝛼不是太大
plot_cost_i_w(X_train, y_train, hist)
绘制结果:
在左边,您可以看到成本正在减少,这是应该的。在右边,您可以看到
w
0
w_0
w0仍然在最小值周围震荡,但每次迭代都在减少而不是增加。注意上面dj_dw[0]
在每次迭代时都会改变符号,因为w[0]
跳过了最佳值。这个alpha值将会收敛。可以改变迭代次数来看看它的行为
3.4.3 𝛼 = 1e-7
让我们尝试一个更小的值作为𝛼,看看会发生什么
# 将alpha设置为1e-7
_,_,hist = run_gradient_descent(X_train, y_train, 10, alpha = 1e-7)
输出结果:
成本在运行过程中一直在减少,表明𝛼不是太大。
plot_cost_i_w(X_train,y_train,hist)
绘制结果:
在左边,您可以看到成本正在减少,这是应该的。在右边,您可以看到
w
0
w_0
w0在减少,没有越过最小值。注意上面dj_w0
在整个运行过程中都是负的。这个解决方案也会收敛,尽管不如前一个例子快。
3.5 特征缩放
讲座描述了调整数据集的重要性,使特征具有相似的范围。下面的部分将介绍如何实现特征缩放
3.5.1 详情
讲座讨论了三种不同的技术:
- 特征缩放,基本上是将每个特征除以用户选择的值,以得到-1和1之间的范围
- 均值标准化: x i : = x i − μ i m a x − m i n x_i := \dfrac{x_i - \mu_i}{max - min} xi:=max−minxi−μi
- 我们将在下面探索的Z-分数标准化。
3.5.2 Z-分数标准化
在Z-分数标准化之后,所有特征都将具有均值为0和标准差为1。
要实现Z-分数标准化,请按照以下公式调整输入值:
x
j
(
i
)
=
x
j
(
i
)
−
μ
j
σ
j
(4)
x^{(i)}_j = \dfrac{x^{(i)}_j - \mu_j}{\sigma_j} \tag{4}
xj(i)=σjxj(i)−μj(4)
其中
j
j
j选择特征或X矩阵中的列。
µ
j
µ_j
µj是特征(j)的所有值均值,
σ
j
\sigma_j
σj是特征(j)的标准差。
μ
j
=
1
m
∑
i
=
0
m
−
1
x
j
(
i
)
σ
j
2
=
1
m
∑
i
=
0
m
−
1
(
x
j
(
i
)
−
μ
j
)
2
\begin{align} \mu_j &= \frac{1}{m} \sum_{i=0}^{m-1} x^{(i)}_j \tag{5}\\ \sigma^2_j &= \frac{1}{m} \sum_{i=0}^{m-1} (x^{(i)}_j - \mu_j)^2 \tag{6} \end{align}
μjσj2=m1i=0∑m−1xj(i)=m1i=0∑m−1(xj(i)−μj)2(5)(6)
实现说明:在标准化特征时,重要的是要存储用于标准化的值 - 用于计算的均值和标准差。在学习模型的参数后,我们通常想要预测我们之前未见过的房屋的价格。给定一个新的x值(客厅面积和卧室数量),我们必须首先使用我们从训练集中先前计算的均值和标准差来规范化x。
3.5.3 实现
def zscore_normalize_features(X):
"""
计算X,按列Z-score标准化
参数:
X (ndarray): 形状(m,n)的输入数据,m个示例,n个特征
返回:
X_norm (ndarray): 形状(m,n)的输入按列规范化
mu (ndarray): 形状(n,)的每个特征的均值
sigma (ndarray): 形状(n,)的每个特征的标准差
"""
# 找到每列/特征的均值
mu = np.mean(X, axis=0) # mu将具有形状(n,)
# 找到每列/特征的标准差
sigma = np.std(X, axis=0) # sigma将具有形状(n,)
# 逐元素地,从每个示例中减去该列的mu,然后除以该列的std
X_norm = (X - mu) / sigma
return (X_norm, mu, sigma)
# 检查我们的工作
# from sklearn.preprocessing import scale
# scale(X_orig, axis=0, with_mean=True, with_std=True, copy=True)
# 让我们看看Z-分数标准化的步骤。下面的图显示了分步转换
mu = np.mean(X_train,axis=0)
sigma = np.std(X_train,axis=0)
X_mean = (X_train - mu)
X_norm = (X_train - mu)/sigma
fig,ax=plt.subplots(1, 3, figsize=(12, 3))
ax[0].scatter(X_train[:,0], X_train[:,3])
ax[0].set_xlabel(X_features[0]); ax[0].set_ylabel(X_features[3]);
ax[0].set_title("unnormalized"); ax[0].axis('equal')
ax[1].scatter(X_mean[:,0], X_mean[:,3])
ax[1].set_xlabel(X_features[0]); ax[0].set_ylabel(X_features[3]);
ax[1].set_title(r"X - μ"); ax[1].axis('equal')
ax[2].scatter(X_norm[:,0], X_norm[:,3])
ax[2].set_xlabel(X_features[0]); ax[0].set_ylabel(X_features[3]);
ax[2].set_title(r"Z-score normalized")
ax[2].axis('equal')
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
fig.suptitle("distribution of features before, during, after normalization")
plt.show()
输出结果:
上面的图显示了训练集中两个参数,"年龄"和"平方英尺"之间的关系。这些是在等比例尺下绘制的。
- 左图:未标准化:'size(sqft)'特征的值范围或方差远大于年龄。
- 中间图:第一步找到并从每个特征中减去均值或平均值。这使得特征围绕零中心。对于’年龄’特征,很难看出差异,但’size(sqft)'特征明显围绕零。
- 右图:第二步除以方差。这使得两个特征都围绕零中心,具有相似的尺度。
让我们对数据进行标准化,并与原始数据进行比较
# 对原始特征进行标准化
X_norm, X_mu, X_sigma = zscore_normalize_features(X_train)
print(f"X_mu = {X_mu}, \nX_sigma = {X_sigma}")
print(f"原始X中每列的峰值到峰值范围:{np.ptp(X_train,axis=0)}")
print(f"标准化X中每列的峰值到峰值范围:{np.ptp(X_norm,axis=0)}")
输出结果:
通过标准化,每列的峰值到峰值范围从数千减少到2-3。
fig,ax=plt.subplots(1, 4, figsize=(12, 3))
for i in range(len(ax)):
norm_plot(ax[i],X_train[:,i],)
ax[i].set_xlabel(X_features[i])
ax[0].set_ylabel("count");
fig.suptitle("distribution of features after normalization")
plt.show()
fig,ax=plt.subplots(1,4,figsize=(12,3))
for i in range(len(ax)):
norm_plot(ax[i],X_norm[:,i],)
ax[i].set_xlabel(X_features[i])
ax[0].set_ylabel("count");
fig.suptitle(f"distribution of features after normalization布");
plt.show()
绘制结果:
注意,上述图中,标准化数据的范围围绕零中心,大致在+/-1左右。最重要的是,每个特征的范围相似
让我们用标准化数据重新运行我们的梯度下降算法。注意alpha的值要大得多。这将加速下降。
w_norm, b_norm, hist = run_gradient_descent(X_norm, y_train, 1000, 1.0e-1, )
输出结果:
标准化特征能够更快地获得非常准确的结果
请注意,在这次相当短的运行结束时,每个参数的梯度都非常小。对于具有标准化特征的回归,0.1的学习率是一个不错的开始。让我们绘制我们的预测与目标值。注意,预测是使用标准化特征进行的,而图是使用原始特征值显示的。
# 使用标准化特征预测目标
m = X_norm.shape[0]
yp = np.zeros(m)
for i in range(m):
yp[i] = np.dot(X_norm[i], w_norm) + b_norm
# 使用原始特征值绘制预测和目标
fig,ax=plt.subplots(1,4,figsize=(12, 3),sharey=True)
for i in range(len(ax)):
ax[i].scatter(X_train[:,i],y_train, label = 'target')
ax[i].set_xlabel(X_features[i])
ax[i].scatter(X_train[:,i],yp,color=dlorange, label = 'predict')
ax[0].set_ylabel("Price"); ax[0].legend();
fig.suptitle("target versus prediction using z-score normalized model")
plt.show()
输出结果:
结果看起来不错。几个需要注意的点:
- 对于多个特征,我们不能再有一个显示结果与特征的单图。
- 在生成图表时,使用了标准化特征。使用从标准化训练集中学习的参数进行的任何预测也必须进行标准化。
3.5.4 预测
我们生成模型的目的是为了使用它来预测数据集中不存在的房屋价格。让我们预测一个具有1200平方英尺、3个卧室、1层、40年历史的房屋的价格。记住,您必须使用在训练数据标准化时获得的均值和标准差来规范化数据
# 首先,规范化示例数据。
x_house = np.array([1200, 3, 1, 40])
x_house_norm = (x_house - X_mu) / X_sigma
print(x_house_norm)
x_house_predict = np.dot(x_house_norm, w_norm) + b_norm
print(f"predicted price of a house with 1200 sqft, 3 bedrooms, 1 floor, 40 years old =)= ${x_house_predict*1000:0.0f}")
输出结果:
3.5.5 成本轮廓
以另一种方式看待特征缩放,就是成本轮廓。当特征缩放不匹配时,成本与参数在轮廓图中的关系是不对称的。
在下面的图中,参数的缩放匹配。左图是w[0],平方英尺与w[1],卧室数量在特征标准化前的成本轮廓图。这个图非常不对称,以至于完成轮廓的曲线都看不见。相比之下,当特征被标准化时,成本轮廓变得更加对称。结果是,在梯度下降期间,参数的更新可以对每个参数做出相同的进步。
plt_equal_scale(X_train, X_norm, y_train)
plt_equal_scale(X_train, X_norm, y_train)
绘制结果:
四、总结
- 利用在之前的实验中开发的用于多特征线性回归的例程
- 探索学习率α对收敛的影响
- 使用Z-分数标准化加速收敛的特征缩放的价值