梯度下降法
使用梯度下降法的目的和原因
目的
梯度下降法(Gradient Descent)是一个算法。不是像多元线性回归那样是一个具体做回归人物的算法,而是通用的优化算法帮助机器学习算法求解最优解。且所有优化算法的目的都是期望以最快的速度把模型参数θ求解出来,梯度下降法是一种经典常用的优化算法。
思想

这里的θ它会随机取值,对于θ=W1, …, Wn 这里θ是指一组向量W,根据公式
y
^
\hat{y}
y^ =
X
{X}
X
θ
{θ}
θ,计算
y
^
\hat{y}
y^和真实y之前的损失比(MSE),再调整θ计算MSE。
这里
θ
{θ}
θ在调整的时候可以调大,可以调小,也可以一部分调大另一部分挑小,第一次
θ
{\theta}
θ可以得到第一次的MSE,即Loss0, 调整第二次就是Loss1.直到MSE我们找到最小值时计算出来的
θ
^
\hat{θ}
θ^就是我们的最优解.
梯度下降法公式

这里Wj就是θ种的某一个j= 0…n,这里的η就是上面图中的learning step,也就是学习率learning rate,优势后用
α
\alpha
α表示。
对于学习率而言一般都是证书,在左侧梯度是负的,那么这个负号会把W往大了调,在右侧梯度就是正的,负号就会把W往小了调,每次Wj调整的幅度就是
η
\eta
η*gradient。
如果特征或维度越多,那么这个公式用的次数就越多,也就是每次迭代要应用的这个式子 n+1 次,所以其实上面的图不是特别准,因为θ对应的是很多维度,应该每一个维度都可以画一个这样的图,或者是一个多维空间的图。
W
0
t
+
1
{W}_0^{t+1}
W0t+1 =
W
0
t
−
{W}_0^{t} -
W0t−
η
\eta
η
g
r
a
d
i
e
n
t
0
{gradient}_0
gradient0
W
1
t
+
1
{W}_1^{t+1}
W1t+1 =
W
1
t
−
{W}_1^{t} -
W1t−
η
\eta
η
g
r
a
d
i
e
n
t
1
{gradient}_1
gradient1
W
j
t
+
1
{W}_j^{t+1}
Wjt+1 =
W
j
t
−
{W}_j^{t} -
Wjt−
η
\eta
η
g
r
a
d
i
e
n
t
j
{gradient}_j
gradientj
W
n
t
+
1
{W}_n^{t+1}
Wnt+1 =
W
n
t
−
{W}_n^{t} -
Wnt−
η
\eta
η
g
r
a
d
i
e
n
t
n
{gradient}_n
gradientn

在上述图中,我们可以发现不是某一个
θ
0
\theta_0
θ0或
θ
1
\theta_1
θ1找到最小值就是最优解,而是一起找到J最小的时候才是最优解
学习率(gradient)
学习率
η
\eta
η不宜过大,因为每次调整的时候Wj调整的幅度就越大,小一点
η
\eta
ηWj每次调整的幅度就小。所以当
η
\eta
η过大的时候,会使得整体的迭代次数增加



学习率一般设置的为比较小的正整数, 0.1, 0.01, 0.001,0.0001,学习率在整体迭代中是不变的数。

全局最优解

上图中可以看出如果损失函数是非凸函数,梯度下降法是有可能落到局部最小值的,所以其实步长不能设置的太小太稳健,那样就很容易落入局部最优解。
流程
- 选取随机的一组数值W0, W1, …, Wn
- 求梯度,也就是曲线某点上切线的斜率
- if g<0, theta 变大,if g>0, theta 变小
- 判断是否收敛 convergence,如果收敛跳出迭代,如果没有达到收敛,回第 2 步继
续

损失函数的导函数
θ \theta θ = θ \theta θ - α \alpha α * ∂ J ( θ ) ∂ ( θ ) \frac{\partial J(θ)}{\partial (θ)} ∂(θ)∂J(θ)

在上式公式中J(θ)是损失函数,q j 是某个特征维度 Xj 对应的权值系数,也可以写成 Wj。
所以损失函数是 MSE,所以上面公式表达的是因为我们的 MSE 中 X、y 是已知的,θ是未知的,而θ不是一个变量而是一堆变量,所以我们只能对含有一推变量的函数 MSE 中的一个变量求导,即偏导。
h
θ
X
h_{θ}{X}
hθX 就是
W
T
X
W^{T} {X}
WTX 也可以换算成
w
0
x
0
w_{0}x_{0}
w0x0 +
w
1
x
1
w_{1}x_{1}
w1x1+…+
w
n
x
n
w_{n}x_{n}
wnxn,也可换算成
∑
i
=
0
n
w
i
x
i
\sum_{i=0}^{n} w_{i}x_{i}
i=0∑nwixi
所以到这里对
θ
j
\theta{j}
θj求偏导,和
W
j
W_{j}
Wj没关系的可以忽略不计。只剩下
x
j
x_{j}
xj。
我们可以得到结论就是θj 对应的 gradient 与预测值
y
^
\hat{y}
y^ 和真实值 y 有关,这里
y
^
\hat{y}
y^ 和 y 是
列向量,同时还与θj 对应的特征维度 Xj 有关,这里 Xj 是原始数据集矩阵的第 j 列。如果我们分别去对每个维度 W0…Wn 求偏导,即可得到所有维度对应的梯度值.
g
0
g_{0}
g0 = (
h
θ
x
h_{θ}{x}
hθx - y) *
X
0
X_0
X0
g
1
g_{1}
g1 = (
h
θ
x
h_{θ}{x}
hθx - y) *
X
1
X_1
X1
g
2
g_{2}
g2 = (
h
θ
x
h_{θ}{x}
hθx - y) *
X
2
X_2
X2
g
3
g_{3}
g3 = (
h
θ
x
h_{θ}{x}
hθx - y) *
X
3
X_3
X3
故
θ
j
t
+
1
\theta_j^{t+1}
θjt+1 =
θ
j
t
\theta_j^{t}
θjt -
η
\eta
η
g
j
g_j
gj =
θ
j
t
\theta_j^t
θjt -
η
\eta
η(
h
θ
(
x
)
h_{θ}{(x)}
hθ(x) -
y
y
y)*
x
j
x_j
xj
三种梯度下降法

全批量梯度下降(Batch Gradient Descent)
θ
j
t
+
1
\theta_j^{t+1}
θjt+1 =
θ
j
t
\theta_j^{t}
θjt -
η
\eta
η
∑
i
=
1
m
\sum_{i=1}^{m}
∑i=1m(
h
θ
(
x
(
i
)
)
−
y
(
i
)
h_θ(x^{(i)}) - y^{(i)}
hθ(x(i))−y(i))
x
j
(
i
)
x_j^{(i)}
xj(i)
全量梯度下降每次学习都使用整个训练集,因此其优点在于每次更新都会朝着正确的方向进行,最后能够保证收敛于极值点(凸函数收敛于全局极值点,非凸函数可能会收敛于局部极值点,但是其缺点在于每次学习时间过长,并且如果训练集很大以至于需要消耗大量的内存,并且全量梯度下降不能进行在线模型参数更新。

import numpy as np
np.random.seed(1)
X = 2 * np.random.rand(100, 1)
y = 5 + 4 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# 超参数
learning_rate = 0.001
n_iterations = 10000
# 初始化θ
theta = np.random.randn(2, 1)
for _ in range(n_iterations):
# 2, 求梯度 gradient
gradients = X_b.T.dot(X_b.dot(theta) - y)
# 3. 调整θ值
theta = theta - learning_rate * gradients
print(theta)
随机梯度下降(Stochastic Gradient Descent)
θ
j
t
+
1
\theta_j^{t+1}
θjt+1 =
θ
j
t
\theta_j^{t}
θjt -
η
\eta
η(
h
θ
(
x
(
i
)
)
−
y
(
i
)
h_θ(x^{(i)}) - y^{(i)}
hθ(x(i))−y(i))*
x
j
(
i
)
x_j^{(i)}
xj(i)
梯度下降算法每次从训练集中随机选择一个样本来进行学习。批量梯度下降算法每次都会使用全部训练样本,因此这些计算是冗余的,因为每次都使用完全相同的样本集。而随机梯度下降算法每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并且可以进行在线更新。随机梯度下降最大的缺点在于每次更新可能并不会按照正确的方向进行,因此可以带来优化波动(扰动)
不过从另一个方面来看,随机梯度下降所带来的波动有个好处就是,对于类似盆地区域(即很多局部极小值点)那么这个波动的特点可能会使得优化的方向从当前的局部极小值点跳到另一个更好的局部极小值点,这样便可能对于非凸函数,最终收敛于一个较好的局部极值点,甚至全局极值点。由于波动,因此会使得迭代次数(学习次数)增多,即收敛速度变慢。不过最终其会和全量梯度下降算法一样,具有相同的收敛性,即凸函数收敛于全局极值点,非凸损失函数收敛于局部极值点。

import numpy as np
X = 2*np.random.rand(100, 1)
y = 4 + 3*X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
n_epoch = 10000
m = 100 # yangben
learning_rate = 0.001
theta = np.random.randn(2, 1)
for epoch in range(n_epoch):
# 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序
arr = np.arange(len(X_b))
np.random.shuffle(arr) # 打乱顺序
X_b = X_b[arr]
y = y[arr]
for i in range(m):
# random_index = np.random.randint(m)
xi = X_b[i:i+1]
yi = y[i:i+1]
gradients = xi.T.dot(xi.dot(theta) - yi)
theta = theta - learning_rate * gradients
print(theta)
小批量梯度下降法(Mini-Batch Gradient Descent)
θ
j
t
+
1
\theta_j^{t+1}
θjt+1 =
θ
j
t
\theta_j^{t}
θjt -
η
\eta
η
∑
i
=
1
b
a
t
c
h
s
i
z
e
\sum_{i=1}^{batchsize}
∑i=1batchsize(
h
θ
(
x
(
i
)
)
−
y
(
i
)
h_θ(x^{(i)}) - y^{(i)}
hθ(x(i))−y(i))*
x
j
(
i
)
x_j^{(i)}
xj(i)
Mini-Batch梯度下降综合了batch梯度下降与stochastic梯度下降,在每次更新速度与更新次数中间取得一个平衡,其每次更新从训练集中随机选择batch_size,batch_size<m个样本进行学习。相对于随机梯度下降算法,小批量梯度下降算法降低了收敛波动性,即降低了参数更新的方差,是的更新更加稳定。相对于全量梯度下降其提高了每次学习的速度。并且不用担心内存瓶颈利用矩阵运算进行高效运算。一般而言每次更新随机选择[50, 256]个样本进行学习。

import numpy as np
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# learning_rate = 0.0001
t0, t1 = 5, 500 # 超参数
def learning_schedult(t):
return t0/(t+t1)
n_epochs = 10000
m = 100
batch_size = 10
num_batches = int(m/batch_size)
theta = np.random.randn(2, 1)
for epoch in range(n_epochs):
arr = np.arange(len(X_b))
np.random.shuffle(arr)
X_b = X_b[arr]
y = y[arr]
for i in range(num_batches):
x_batch = X_b[i*batch_size:i*batch_size+batch_size]
y_train = y[i*batch_size:i*batch_size+batch_size]
gradients = x_batch.T.dot(x_batch.dot(theta)-y_train)
learning_rate = learning_schedult(epoch*m+i)
theta = theta - learning_rate*gradients
print(theta)
代码优化的点:(读者自己思考)
对于随机梯度下降和小批量梯度下降这种方式,有些数据会不会取不到?如何改进?
怎么实现让学习率随着迭代次数增多而逐渐变小?
轮次和批次
轮次:epoch,轮次顾名思义是把我们已有的训练集数据学习多少轮
批次:batch,批次这里指的的我们已有的训练集数据比较多的时候,一轮要学习太多数据,那就把一轮次要学习的数据分成多个批次,一批一批数据的学习
总结
以上就是本文所讲的梯度下降法中的内容,前者我们通过一个场景,来推导出梯度下降的公式。另外我们知道梯度下降一般应用于凸函数中,而那个驻点一般就是我们求得θ的最优解。另外列出了梯度下降法的一些步骤。梯度下降法在选取值的时候首先要随机选取,然后求得gradient,在代入公式中,最终能求得θ的最优解公式。本文还介绍了3种梯度下降方法,它们的区别,以及代码实现。
1616

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



