文章目录
1 概述
线性回归模型是使用最广泛的学习算法,让我们从一个可以使用线性回归解决的问题开始。
1.1 案例
下图展示了美国波特兰市的房屋大小和价格数据集,其中横轴是以平方英尺为单位的房屋大小,纵轴是以千美元为单位的房屋价格,每个数据点使用小十字架表示。
现在,假设您是波特兰的一名房地产经纪人,您正在帮助一位客户出售她的房子。她问你这套房子能卖多少钱?该数据集会帮助您估算她可以获得的价格:
- 你先测量房子的大小,结果房子是 1,250 平方英尺。
- 接下来,使用数据集构建一个线性回归模型,将数据拟合一条直线,如下图所示。
- 根据这条与数据拟合的直线,1,250 平方英尺对应的价格大约 220,000 美元。,
除了将数据可视化为图表外,还有另一种查看有用数据的方法,即数据表。
例如,表格的第一行是一个面积为 2,104 平方英尺的房子,售价是 400,000 美元,也就是在这附近。表格的第一行绘制为此处的数据点。
1.2 分析
在机器学习中,
-
x x x:表示输入的标准符号,称之为输入变量,也称为特征或输入特征。
例如,对于训练集中的第一个房子, x x x 是房子的大小,因此 x x x 等于 2,104。
-
y y y:尝试预测的输出变量(有时也称为目标变量)。
在本案例中, y y y 是房子的价格,对于第一个训练示例,它等于 400,所以 y y y 等于 400。
-
m m m:表示训练示例的总数。
在本案例中, m m m 等于 47。
-
( x , y ) (x, y) (x,y):表示单个训练样本。
对于第一个训练示例 ( x , y ) (x, y) (x,y),这对数字是 ( 2104 , 400 ) (2104, 400) (2104,400)。
注意:
X ( i ) X^{(i)} X(i) 中的上标 i i i 不是求幂,而是表示第 i i i 组数据。
监督学习中的训练集包括输入特征(例如房屋大小)和输出目标(例如房屋价格)。输出目标是我们将从中学习的模型的正确答案。要训练模型,需要将训练集(包括输入特征和输出目标)提供给学习算法。我们将这个算法函数写成小写的 f f f,其中 f f f 代表函数。
历史上,函数 f f f 曾经被称为假设,但我在这个类中只是将它称为函数 f f f。
f f f 的工作是采用新的输入 x x x 和输出并进行估计或预测,我将其称为 y ^ \hat{y} y^(y-hat)。
在机器学习中,
- x x x:称为输入或输入特征。
- f f f:称为模型。
- y y y:指目标,即训练集中的实际真实值。
- y ^ \hat{y} y^(y-hat): y y y 的估计或预测。
一个关键问题是,我们将如何表示函数 f f f ?
在线性回归模型中,
f
f
f 是一条直线。函数可以写成
f
w
,
b
(
x
)
=
w
x
+
b
f_{w,b}(x)=wx+b
fw,b(x)=wx+b
该公式表示
f
f
f 是一个以
x
x
x 作为输入的函数,并根据
w
w
w 和
b
b
b 的值,输出预测
y
^
\hat{y}
y^ 值。
因此,只要知道
w
w
w 和
b
b
b,即可根据输入特征
x
x
x 确定预测
y
^
\hat{y}
y^。有时我们会只写 f 而没有明确地将
w
w
w 和
b
b
b 包含在下标中,但其含义与
f
w
,
b
f_{w,b}
fw,b 完全相同:
f
(
x
)
=
w
x
+
b
f(x)=wx+b
f(x)=wx+b

线性函数只是直线的一个奇特术语,由于其相对简单且易于使用,因此使用直线作为基础,最终逐渐学习并理解更复杂的非线性模型。
这个特殊的模型有一个名字,叫做线性回归。更具体地说,这是具有一个变量的线性回归,其中“一个变量”表示只有一个输入变量或特征 x x x,即房屋的大小。
2 代价函数
2.1 代价函数公式
假设我们有一个包含输入特征
x
x
x 和输出目标
y
y
y 的训练集。用于拟合这个训练集的模型是一个线性函数:
f
w
,
b
(
x
)
=
w
x
+
b
f_{w,b}(x)=wx+b
fw,b(x)=wx+b
其中,
w
w
w 和
b
b
b 被称为模型的参数。在机器学习中,模型的参数是在训练期间可以调整的变量,以改进模型的性能。有时,
w
w
w 和
b
b
b 也被称为系数或权重。
回顾线性模型,了解参数 w w w 和 b b b 是如何确定 f f f 的:
对于线性回归,我们的目标是选择合适的参数
w
w
w 和
b
b
b ,使得函数
f
f
f 生成的直线能够很好地拟合训练数据。为了衡量直线与数据的拟合程度,我们需要构建代价函数(Cost Function,也称为成本函数):通过比较预测值
y
^
\hat{y}
y^ 和实际目标值
y
y
y 来计算误差。具体来说,误差是预测值与实际值之间的差值:
e
r
r
o
r
=
y
^
−
y
error=\hat{y}-y
error=y^−y
为了消除误差的正负影响,我们通常计算误差的平方:
e
r
r
o
r
=
(
y
^
−
y
)
2
error=(\hat{y}-y)^2
error=(y^−y)2
接下来,我们对训练集中的所有样本计算平方误差,并取其平均值:
J
(
w
,
b
)
=
1
2
m
∑
i
=
1
m
(
y
^
(
i
)
−
y
(
i
)
)
2
J(w,b)=\frac{1}{2m}\sum^{m}_{i=1}(\hat{y}^{(i)}-y^{(i)})^2
J(w,b)=2m1i=1∑m(y^(i)−y(i))2
- 我们将从 i i i 等于 1,2,3 一直加到 m m m,并记住 m m m 是训练示例的数量,对于这个数据集来说是 47。
- 额外除以 2 只是为了让我们后面的一些计算看起来更整洁,但无论是否包含此除以 2,代价函数仍然有效。
代价函数 J ( w , b ) J(w,b) J(w,b) 衡量了模型预测值与实际值之间的平均误差。我们的目标是通过调整来 w w w 和 b b b 最小化代价函数,从而使模型的预测更加准确。
2.2 理解代价函数
代价函数用于衡量模型预测值与实际值之间的差异。具体来说,线性回归的目标是找到参数
w
w
w 和
b
b
b,使得代价函数
J
(
w
,
b
)
J(w,b)
J(w,b) 最小化。数学上,我们表示为:
minimize
w
,
b
J
(
w
,
b
)
\mathop{\text{minimize}\ }\limits_{w,b}J(w,b)
w,bminimize J(w,b)
为了更直观地理解代价函数,我们暂时简化模型,仅考虑参数
w
w
w,即假设
b
=
0
b=0
b=0。此时,模型变为:
f
w
(
x
)
=
w
⋅
x
f_{w}(x)=w\cdot x
fw(x)=w⋅x
相应的代价函数也简化为:
J
(
w
)
=
1
2
m
∑
i
=
1
m
(
w
⋅
x
(
i
)
−
y
(
i
)
)
2
J(w)=\frac{1}{2m}\sum^{m}_{i=1}(w\cdot x^{(i)}-y^{(i)})^2
J(w)=2m1i=1∑m(w⋅x(i)−y(i))2
假设我们有一个简单的训练集,包含三个数据点:(1, 1)、(2, 2) 和 (3, 3)。
-
w
=
1
w=1
w=1 时
- 模型 f w ( x ) f_{w}(x) fw(x) 是一条斜率为 1 的直线,完美地通过所有数据点。
- 计算代价函数 J(w):J(1) = 0,表示模型完美拟合数据。
-
w
=
0.5
w=0.5
w=0.5 时
- 模型 f w ( x ) f_{w}(x) fw(x) 是一条斜率为 0.5 的直线,未能完全拟合数据。
- 计算代价函数 J(w):J(0.5) ≈ 0.58,表示模型拟合效果较差。
-
w
=
0
w=0
w=0 时
- 模型 f w ( x ) f_{w}(x) fw(x) 是一条水平线,完全偏离数据。
- 计算代价函数 J(w):J(0) ≈ 2.33,表示模型拟合效果非常差。
这就是在线性回归中如何使用代价函数来找到使 J J J 最小化的 w w w 值。在更一般的情况下,我们有参数 w w w 和 b b b 而不仅仅是 w w w,需要找到使 J J J 最小化的 w w w 和 b b b 的值。
2.3 可视化代价函数
现在,我们将回到完整的线性回归模型,同时考虑参数 w w w 和 b b b,并可视化代价函数来深入理解其作用。
假设我们有一个房价预测模型,输入特征
x
x
x 表示房屋的大小,输出目标
y
y
y 表示房屋的价格。我们选择
w
=
0.06
w=0.06
w=0.06 和
b
=
50
b=50
b=50,则模型函数为:
f
w
,
b
(
x
)
=
0.06
⋅
x
+
50
f_{w,b}(x)=0.06\cdot x+50
fw,b(x)=0.06⋅x+50
这个模型对房价的预测效果较差,因为它始终低估了房价。
在此之前,我们将参数 b b b 设为 0 来简化模型,这使得代价函数 J ( w ) J(w) J(w) 成为一个二维的 U 形曲线,形状类似于一个“汤碗”。然而,在完整的线性回归模型中,我们需要同时考虑参数 w w w 和 b b b,这使得代价函数 J ( w , b ) J(w,b) J(w,b) 成为一个三维的曲面。
3 梯度下降
梯度下降是一种通用的优化算法,适用于最小化任何函数,而不仅仅是线性回归的代价函数。为了更全面地讨论梯度下降,我们将其推广到更一般的函数。
例如,假设我们有一个代价函数 J J J,它是参数 w 1 , w 2 , ⋯ , w n w_1,w_2,\cdots,w_n w1,w2,⋯,wn 和 b b b 的函数。我们的目标是通过调整这些参数,使得代价函数 J J J最小化。
- 初始化参数:首先,我们需要为参数 w 和 b 选择初始值。在线性回归中,初始值的选择并不重要,通常可以将它们都设为 0。例如,w=0,b=0。
- 逐步调整参数:梯度下降的核心思想是通过多次迭代,逐步调整参数 w 和 b,以降低代价函数 J(w,b) 的值。每次迭代中,算法会根据当前参数值计算代价函数的梯度(即函数的变化率),并沿着梯度的反方向更新参数。
- 收敛到最小值:通过不断迭代,梯度下降算法会逐渐接近代价函数的最小值。最终,参数 w 和 b 会稳定在或接近最优值。
需要注意的是,梯度下降可能会收敛到局部最小值,而不是全局最小值。局部最小值是指某个区域内代价函数的最小值,但不一定是整个函数的最小值。这种现象在复杂的代价函数中尤为常见。
3.1 实现步骤
梯度下降的核心思想是通过迭代更新参数 w 和 b,使得代价函数 J(w,b) 逐渐减小。具体来说,梯度下降的更新规则如下:
-
更新参数 w w w:
w : = w − α ⋅ ∂ J ( w , b ) ∂ w w:=w-\alpha\cdot\frac{\partial J(w,b)}{\partial w} w:=w−α⋅∂w∂J(w,b)其中,α 是学习率, ∂ J ( w , b ) ∂ w \frac{\partial J(w,b)}{\partial w} ∂w∂J(w,b) 是代价函数对 w 的偏导数。
-
更新参数 b b b:
b : = b − α ⋅ ∂ J ( w , b ) ∂ b b:=b-\alpha\cdot\frac{\partial J(w,b)}{\partial b} b:=b−α⋅∂b∂J(w,b)其中, ∂ J ( w , b ) ∂ w \frac{\partial J(w,b)}{\partial w} ∂w∂J(w,b) 是代价函数对 b 的偏导数。
-
赋值运算符 :=
- 在编程中,:= 表示赋值操作。例如, w : = w − α ⋅ ∂ J ( w , b ) ∂ w w:=w-\alpha\cdot\frac{\partial J(w,b)}{\partial w} w:=w−α⋅∂w∂J(w,b) 表示将 w 更新为右侧表达式的值。
- 这与数学中的等号 = 不同,后者通常用于表示真值断言。
-
学习率 α
- 学习率 α 是一个介于 0 和 1 之间的正数,通常设置为 0.01。
- 学习率决定了每次更新参数的步长。较大的学习率意味着更激进的更新,而较小的学习率则意味着更谨慎的更新。
-
偏导数
-
偏导数表示代价函数在 w 和 b 方向上的变化率。
-
偏导数的作用是告诉我们参数应该朝哪个方向更新,以最快地降低代价函数。
-
在实现梯度下降时,一个关键细节是同步更新参数 w 和 b。这意味着在每次迭代中,我们需要同时计算 w 和 b 的更新值,然后再同时更新它们。上图左边展示了正确的更新步骤,右边则是不推荐的错误做法。
3.2 理解梯度下降
为了更好地理解梯度下降,我们暂时简化问题,仅考虑一个参数 w。此时,代价函数 J(w) 是一个关于 w 的一维函数,其图形是一条曲线。梯度下降的更新规则简化为:
w
:
=
w
−
α
⋅
d
J
(
w
)
d
w
w:=w-\alpha\cdot\frac{d J(w)}{d w}
w:=w−α⋅dwdJ(w)
其中,α 是学习率,
d
J
(
w
)
d
w
\frac{d J(w)}{d w}
dwdJ(w) 是代价函数 J(w) 对 w 的导数,表示代价函数在 w 方向上的变化率。具体来说,导数告诉我们 w 应该如何更新,以最快地降低代价函数。
- 导数为正时
- 如果导数为正,意味着代价函数在当前 w 处是上升的。
- 根据梯度下降的更新规则,w 会减小(即 w:=w−α⋅正数)。
- 在图形上,w 会向左移动,代价函数 J(w) 会逐渐减小。
- 导数为负时
- 如果导数为负,意味着代价函数在当前 w 处是下降的。
- 根据梯度下降的更新规则,w 会增加(即 w:=w−α⋅负数)。
- 在图形上,w 会向右移动,代价函数 J(w) 会逐渐减小。
通过这种方式,导数项引导 w 朝着代价函数的最小值方向移动。
3.3 学习率
(1)学习率过小
如果学习率 α 过小,梯度下降的更新步长会非常小。具体来说:
- 更新步长小:每次更新 w 时,w 的变化量非常小。
- 收敛速度慢:虽然梯度下降最终会收敛到最小值,但需要非常多的迭代步骤。
- 效率低下:计算成本高,尤其是在大规模数据集上。
示例:
假设学习率
α
α
α = 0.0000001,每次更新 w 的步长非常小。虽然 w 会逐渐接近最小值,但需要大量的迭代步骤才能达到目标。
(2)学习率过大
如果学习率 α 过大,梯度下降的更新步长会非常大。具体来说:
- 更新步长大:每次更新 w 时,w 的变化量非常大。
- 可能无法收敛:梯度下降可能在最小值附近振荡,甚至偏离最小值。
- 发散风险:在某些情况下,梯度下降可能完全无法收敛,导致代价函数值不断增加。
示例:
假设学习率
α
α
α = 10,每次更新 w 的步长非常大。梯度下降可能会从最小值的一侧跳到另一侧,甚至偏离最小值,导致代价函数值不断增加。
(3)学习率的自动调整
一个有趣的现象是,即使学习率 α 保持不变,梯度下降在接近最小值时也会自动减小更新步长。这是因为:
- 导数变小:当 w 接近最小值时,导数 d J ( w ) d w \frac{d J(w)}{d w} dwdJ(w) 会逐渐变小。
- 更新步长减小:由于更新步长 α ⋅ d J ( w ) d w \alpha\cdot\frac{d J(w)}{d w} α⋅dwdJ(w) 中的导数项变小,更新步长也会自动减小。
- 稳定收敛:这使得梯度下降在接近最小值时能够稳定地收敛,而不会在最小值附近振荡。
(4)局部最小值
当 w 处于局部最小值时,导数
d
J
(
w
)
d
w
\frac{d J(w)}{d w}
dwdJ(w) 为零。此时,梯度下降的更新规则变为:
w
:
=
w
−
α
⋅
0
=
w
w:=w-\alpha\cdot0=w
w:=w−α⋅0=w
这意味着,如果 w 已经处于局部最小值,梯度下降不会改变 w 的值,算法会保持稳定。
4 最佳实践
4.1 导入数据
首先导入相关库:
import math, copy
import numpy as np
import matplotlib.pyplot as plt
math和copy用于数学运算和深拷贝。numpy用于科学计算,特别是数组操作。matplotlib.pyplot用于绘图。
方便起见,本次数据集中有两个样本,特征 x_train 是房屋的面积(1000平方英尺),目标值 y_train 是房屋的价格(千美元)。
x_train = np.array([1.0, 2.0]) # 特征
y_train = np.array([300.0, 500.0]) # 目标值
4.2 代码实现
(1)代价函数
w和b是线性模型的参数。m是样本数量。f_wb是模型的预测值。total_cost是成本值。
# Function to calculate the cost
def compute_cost(x, y, w, b):
m = x.shape[0]
cost = 0
for i in range(m):
f_wb = w * x[i] + b
cost = cost + (f_wb - y[i]) ** 2
total_cost = 1 / (2 * m) * cost
return total_cost
(2)计算梯度
dj_dw和dj_db分别是 w 和 b 的梯度。
def compute_gradient(x, y, w, b):
"""
Computes the gradient for linear regression
Args:
x (ndarray (m,)): Data, m examples
y (ndarray (m,)): target values
w,b (scalar) : model parameters
Returns
dj_dw (scalar): The gradient of the cost w.r.t. the parameters w
dj_db (scalar): The gradient of the cost w.r.t. the parameter b
"""
# Number of training examples
m = x.shape[0]
dj_dw = 0
dj_db = 0
for i in range(m):
f_wb = w * x[i] + b
dj_dw_i = (f_wb - y[i]) * x[i]
dj_db_i = f_wb - y[i]
dj_db += dj_db_i
dj_dw += dj_dw_i
dj_dw = dj_dw / m
dj_db = dj_db / m
return dj_dw, dj_db
(3)梯度下降算法
alpha是学习率,num_iters是迭代次数。- 每次迭代中,更新 w 和 b,并记录成本值和参数历史。
def gradient_descent(x, y, w_in, b_in, alpha, num_iters, cost_function, gradient_function):
"""
Performs gradient descent to fit w,b. Updates w,b by taking
num_iters gradient steps with learning rate alpha
Args:
x (ndarray (m,)) : Data, m examples
y (ndarray (m,)) : target values
w_in,b_in (scalar): initial values of model parameters
alpha (float): Learning rate
num_iters (int): number of iterations to run gradient descent
cost_function: function to call to produce cost
gradient_function: function to call to produce gradient
Returns:
w (scalar): Updated value of parameter after running gradient descent
b (scalar): Updated value of parameter after running gradient descent
J_history (List): History of cost values
p_history (list): History of parameters [w,b]
"""
w = copy.deepcopy(w_in) # avoid modifying global w_in
# An array to store cost J and w's at each iteration primarily for graphing later
J_history = []
p_history = []
b = b_in
w = w_in
for i in range(num_iters):
# Calculate the gradient and update the parameters using gradient_function
dj_dw, dj_db = gradient_function(x, y, w, b)
# Update Parameters using equation (3) above
b = b - alpha * dj_db
w = w - alpha * dj_dw
# Save cost J at each iteration
if i < 100000: # prevent resource exhaustion
J_history.append(cost_function(x, y, w, b))
p_history.append([w, b])
# Print cost every at intervals 10 times or as many iterations if < 10
if i % math.ceil(num_iters / 10) == 0:
print(f"Iteration {i:4}: Cost {J_history[-1]:0.2e} ",
f"dj_dw: {dj_dw: 0.3e}, dj_db: {dj_db: 0.3e} ",
f"w: {w: 0.3e}, b:{b: 0.5e}")
return w, b, J_history, p_history #return w and J,w history for graphing
(4)运行梯度下降
- 初始化参数 w 和 b 为 0。
- 设置学习率
tmp_alpha和迭代次数iterations。 - 运行梯度下降算法,得到优化后的参数 w 和 b。
# initialize parameters
w_init = 0
b_init = 0
# some gradient descent settings
iterations = 10000
tmp_alpha = 1.0e-2
# run gradient descent
w_final, b_final, J_hist, p_hist = gradient_descent(x_train, y_train, w_init, b_init, tmp_alpha,
iterations, compute_cost, compute_gradient)
print(f"(w,b) found by gradient descent: ({w_final:8.4f},{b_final:8.4f})")
(5)代价函数与迭代次数
- 绘制代价函数随迭代次数的变化图,分为初始阶段(前100次)和结束阶段(后9000次)。
# plot cost versus iteration
fig, (ax1, ax2) = plt.subplots(1, 2, constrained_layout=True, figsize=(12, 4))
ax1.plot(J_hist[:100])
ax2.plot(1000 + np.arange(len(J_hist[1000:])), J_hist[1000:])
ax1.set_title("Cost vs. iteration(start)");
ax2.set_title("Cost vs. iteration (end)")
ax1.set_ylabel('Cost');
ax2.set_ylabel('Cost')
ax1.set_xlabel('iteration step');
ax2.set_xlabel('iteration step')
plt.show()
(6)预测
- 使用优化后的参数 w 和 b 进行预测。
print(f"1000 sqft house prediction {w_final*1.0 + b_final:0.1f} Thousand dollars")
print(f"1200 sqft house prediction {w_final*1.2 + b_final:0.1f} Thousand dollars")
print(f"2000 sqft house prediction {w_final*2.0 + b_final:0.1f} Thousand dollars")
4.3 可视化
可视化函数:
def plt_contour_wgrad(x, y, hist, ax, w_range=[-100, 500, 5], b_range=[-500, 500, 5],
contours=[0.1, 50, 1000, 5000, 10000, 25000, 50000],
resolution=5, w_final=200, b_final=100, step=10):
# 创建w和b的网格
b0, w0 = np.meshgrid(np.arange(*b_range), np.arange(*w_range))
# 初始化z为0
z = np.zeros_like(b0)
# 遍历w和b的网格,计算每个点的cost
for i in range(w0.shape[0]):
for j in range(w0.shape[1]):
z[i][j] = compute_cost(x, y, w0[i][j], b0[i][j])
# 绘制等高线图
CS = ax.contour(w0, b0, z, contours, linewidths=2,
colors=[dlblue, dlorange, dldarkred, dlmagenta, dlpurple])
# 添加等高线标签
ax.clabel(CS, inline=1, fmt='%1.0f', fontsize=10)
# 设置x轴和y轴标签
ax.set_xlabel("w");
ax.set_ylabel("b")
# 设置标题
ax.set_title('Contour plot of cost J(w,b), vs b,w with path of gradient descent')
# 设置w和b的初始值
w = w_final;
b = b_final
# 绘制w和b的初始值
ax.hlines(b, ax.get_xlim()[0], w, lw=2, color=dlpurple, ls='dotted')
ax.vlines(w, ax.get_ylim()[0], b, lw=2, color=dlpurple, ls='dotted')
# 设置起始点
base = hist[0]
# 遍历hist,绘制梯度下降路径
for point in hist[0::step]:
# 计算两点之间的距离
edist = np.sqrt((base[0] - point[0]) ** 2 + (base[1] - point[1]) ** 2)
# 如果距离大于resolution或者point是hist的最后一个点,则绘制箭头
if (edist > resolution or point == hist[-1]):
# 如果point在ax的范围内,则绘制箭头
if inbounds(point, base, ax.get_xlim(), ax.get_ylim()):
plt.annotate('', xy=point, xytext=base, xycoords='data',
arrowprops={'arrowstyle': '->', 'color': 'r', 'lw': 3},
va='center', ha='center')
# 更新base为point
base = point
return
def plt_divergence(p_hist, J_hist, x_train, y_train):
# 初始化x、y、v三个数组,长度为p_hist的长度
x = np.zeros(len(p_hist))
y = np.zeros(len(p_hist))
v = np.zeros(len(p_hist))
# 遍历p_hist,将p_hist中的值赋给x、y、v
for i in range(len(p_hist)):
x[i] = p_hist[i][0]
y[i] = p_hist[i][1]
v[i] = J_hist[i]
# 创建一个大小为12x5的图形
fig = plt.figure(figsize=(12, 5))
# 设置子图之间的间距
plt.subplots_adjust(wspace=0)
# 添加一个1行5列的网格
gs = fig.add_gridspec(1, 5)
# 设置图形的标题
fig.suptitle(f"Cost escalates when learning rate is too large")
# ===============
# First subplot
# ===============
# 添加一个子图
ax = fig.add_subplot(gs[:2], )
# Print w vs cost to see minimum
# 设置b的值为100
fix_b = 100
# 创建一个从-70000到70000,步长为1000的数组
w_array = np.arange(-70000, 70000, 1000)
# 创建一个与w_array相同长度的数组,用于存储cost
cost = np.zeros_like(w_array)
# 遍历w_array,计算cost
for i in range(len(w_array)):
tmp_w = w_array[i]
cost[i] = compute_cost(x_train, y_train, tmp_w, fix_b)
# 绘制w vs cost的图像
ax.plot(w_array, cost)
# 绘制p_hist中的点
ax.plot(x, v, c=dlmagenta)
# 设置子图的标题
ax.set_title("Cost vs w, b set to 100")
# 设置y轴的标签
ax.set_ylabel('Cost')
# 设置x轴的标签
ax.set_xlabel('w')
# 设置x轴的刻度
ax.xaxis.set_major_locator(MaxNLocator(2))
# ===============
# Second Subplot
# ===============
# 创建一个从-35000到35000,步长为500的数组
tmp_b, tmp_w = np.meshgrid(np.arange(-35000, 35000, 500), np.arange(-70000, 70000, 500))
# 创建一个与tmp_b、tmp_w相同大小的数组,用于存储cost
z = np.zeros_like(tmp_b)
# 遍历tmp_b、tmp_w,计算cost
for i in range(tmp_w.shape[0]):
for j in range(tmp_w.shape[1]):
z[i][j] = compute_cost(x_train, y_train, tmp_w[i][j], tmp_b[i][j])
# 添加一个3D子图
ax = fig.add_subplot(gs[2:], projection='3d')
# 绘制3D图像
ax.plot_surface(tmp_w, tmp_b, z, alpha=0.3, color=dlblue)
# 设置x轴的刻度
ax.xaxis.set_major_locator(MaxNLocator(2))
# 设置y轴的刻度
ax.yaxis.set_major_locator(MaxNLocator(2))
# 设置x轴的标签
ax.set_xlabel('w', fontsize=16)
# 设置y轴的标签
ax.set_ylabel('b', fontsize=16)
# 设置z轴的标签
ax.set_zlabel('\ncost', fontsize=16)
# 设置子图的标题
plt.title('Cost vs (b, w)')
# Customize the view angle
ax.view_init(elev=20., azim=-65)
ax.plot(x, y, v, c=dlmagenta)
return
(1)梯度下降路径
等高线图展示了 cost(w,b) 在 w 和 b 一定范围内的变化。成本水平通过环形等高线表示。叠加在等高线图上的红色箭头表示梯度下降的路径。
- 路径朝着目标稳步(单调)前进。
- 初始步骤的步长比接近目标时的步长要大得多。
fig, ax = plt.subplots(1, 1, figsize=(12, 6))
plt_contour_wgrad(x_train, y_train, p_hist, ax)
(2)增加学习率
大幅增加学习率后,观察梯度下降的收敛性和发散性。
# initialize parameters
w_init = 0
b_init = 0
# set alpha to a large value
iterations = 10
tmp_alpha = 8.0e-1
# run gradient descent
w_final, b_final, J_hist, p_hist = gradient_descent(x_train, y_train, w_init, b_init, tmp_alpha,
iterations, compute_cost, compute_gradient)
plt_divergence(p_hist, J_hist, x_train, y_train)
plt.show()
在上图中,w 和 b 在正负之间来回波动,且绝对值随着每次迭代而增大。此外,每次迭代中 d J ( w ) d w \frac{d J(w)}{d w} dwdJ(w) 的符号都会改变,而成本值不断增加而不是减少。这表明学习率过大,导致解发散,如下图所示。
1318

被折叠的 条评论
为什么被折叠?



