PyTorch 深度学习实践
03. Gradient Descent
刘二大人视频学习笔记,2023年07月08日。
本章是对梯度下降算法的介绍,做一些重要内容的记录,共勉。
(🥺我在电脑用Typora写,最终要存在CSDN上,所以截图很麻烦,尽量以文字形式记录)
0.前言
回忆上一节所讲的题目,采用了线性模型构建一个学习时间和得分之间的学习系统。但是利用穷举法来进行计算,无可避免会被“维度的诅咒”所影响。
所以不用穷举法,而采用分治法,先进行稀疏的搜索,在二维平面先取16个均匀点,然后在最小值处在进行分16个但如此寻找。但是这个方法只适用于光滑的凸函数,对于不规则曲线来说还是很难得到正解。
1.梯度下降算法
1)梯度的定义
用目标函数对权重进行求导数,这样就得到了目标函数的上升方向。(比如导数为负,说明函数向负方向为上升方向)
对于问题,我们要找的是
ω
\omega
ω最小值,也即下降方向所以对权重的更新为:
ω
=
ω
−
α
∂
c
o
s
t
∂
ω
\omega = \omega - \alpha\frac{\partial cost}{\partial \omega}
ω=ω−α∂ω∂cost
其中
α
\alpha
α为学习率,这个学习率通常取小数。
每次迭代都朝着下降最快的方向前进,所以这是一种贪心算法。
其实可以形象的看成在函数图形上放置一个小球,在没有惯性的情况下的运动(我感觉)。但是这样就会引出贪心的一个缺陷,会得到错误的解。
上面这种函数称为非凸函数,函数中会存在多个最优点,分为局部最优点和全局最优点。(由图可见)
但是梯度下降仍然是广为采用的一种方法,是因为在深度神经网络很少存在局部最优点。
但是在这里面又引出另一个问题——鞍点
鞍点的梯度为0,根据公式,当权重优化到鞍点时,迭代将永远在鞍点死循环,无法进行正常迭代。
梯度的具体算式:
∂ c o s t ∂ ω = ∂ ∂ ω 1 N ∑ n = 1 N ( x n ω − y n ) 2 = 1 N ∑ n = 1 N ∂ ∂ ω ( x n ω − y n ) 2 = 1 N ∑ n = 1 N 2 ( x n ω − y n ) ∂ ( x n ω − y n ) ∂ ω = 1 N ∑ n = 1 N 2 x n ( x n ω − y n ) \frac{\partial cost}{\partial \omega} = \frac{\partial}{\partial \omega}\frac{1}{N}\sum^N_{n=1}(x_n\omega-y_n)^2\\ =\frac{1}{N}\sum^N_{n=1}\frac{\partial}{\partial \omega}(x_n\omega-y_n)^2\\ =\frac{1}{N}\sum^N_{n=1}2(x_n\omega-y_n)\frac{\partial (x_n\omega-y_n)}{\partial \omega}\\ =\frac{1}{N}\sum^N_{n=1}2x_n(x_n\omega-y_n) ∂ω∂cost=∂ω∂N1n=1∑N(xnω−yn)2=N1n=1∑N∂ω∂(xnω−yn)2=N1n=1∑N2(xnω−yn)∂ω∂(xnω−yn)=N1n=1∑N2xn(xnω−yn)
所以可以带回原来的公式得到:
ω
=
ω
−
α
1
N
∑
n
=
1
N
2
x
n
(
x
n
ω
−
y
n
)
\omega = \omega - \alpha\frac{1}{N}\sum^N_{n=1}2x_n(x_n\omega-y_n)
ω=ω−αN1n=1∑N2xn(xnω−yn)
2)代码实现
import numpy as np
import matplotlib.pyplot as plt
# prepare the training set
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# initial guess of weight
w = 1.0
# y-hat
def forward(x):
return x * w
# cost/MSE
def cost(xs, ys):
cost = 0
for x, y in zip(xs, ys):
y_pred = forward(x)
cost += (y_pred - y) ** 2
return cost / len(xs)
# gradient
def gradient(xs, ys):
grad = 0
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y)
return grad / len(xs)
cost_list = []
e_list = []
print('Predict (before training)', 4, forward(4))
# do the update epoch-迭代次数,学习率为0.01
for epoch in range(100):
cost_val = cost(x_data, y_data)
grad_val = gradient(x_data, y_data)
w -= 0.01 * grad_val
print('Epoch', epoch, 'w=', w, 'loss=', cost_val)
cost_list.append(cost_val)
e_list.append(epoch)
print('Predict (after training)', 4, forward(4))
plt.plot(e_list, cost_list)
plt.ylabel('cost')
plt.xlabel('epoch')
plt.show()
实际情况曲线不会这么平滑,会存在局部震荡。所以一般绘图的时候用指数加权均值的方法,来光滑函数。
指数加权均值光滑:
Cost的值为: c 0 , c 1 , … c_0,c_1,\dots c0,c1,…
更新之后的值为: c 0 ′ , c 1 ′ , … c^{\prime}_0,c^{\prime}_1,\dots c0′,c1′,…
则有:
c 0 ′ = c 0 … c i ′ = β c i + c i − 1 c^{\prime}_0 = c_0\\ \dots\\ c^{\prime}_i = \beta c_i + c_{i-1} c0′=c0…ci′=βci+ci−1
但如果函数有向上趋势,并不认为最低点是最小值,说明训练发散,可能是学习率取太大了,需要重新训练。
2.随机梯度下降
一般应用的是梯度下降算法的一个变体,就是随机梯度下降。梯度下降计算是用平均损失来计算,而随机梯度下降是随机从N中选取一个损失进行计算。
ω
=
ω
−
α
∂
l
o
s
s
∂
ω
∂
l
o
s
s
n
∂
ω
=
2
⋅
x
n
⋅
(
x
n
⋅
ω
−
y
n
)
\omega = \omega - \alpha\frac{\partial loss}{\partial \omega}\\ \frac{\partial loss_n}{\partial \omega}=2 \cdot x_n\cdot(x_n\cdot \omega-y_n)
ω=ω−α∂ω∂loss∂ω∂lossn=2⋅xn⋅(xn⋅ω−yn)
这样面对鞍点的问题,就可以通过产生一个随机误差(或者说从噪声数据拿到的随机噪声)来推动函数越过鞍点。这种方法是被证明有效的一种方法。
import numpy as np
import matplotlib.pyplot as plt
# prepare the training set
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# initial guess of weight
w = 1.0
# y-hat
def forward(x):
return x * w
# calculate loss
def loss(x, y):
y_pred = forward(x)
return (y_pred - y) ** 2
# gradient
def gradient(x, y):
return 2 * x * (x * w - y)
cost_list = []
e_list = []
print('Predict (before training)', 4, forward(4))
# update weight by every grad of sample of train set
for epoch in range(100):
for x,y in zip(x_data,y_data):
grad_val = gradient(x, y)
w -= 0.01 * grad_val
print('\tgrad:',x,y,grad_val)
l = loss(x,y)
print('progress:',epoch,'w=',w,'loss=',l)
print('Predict (after training)', 4, forward(4))
但是在真正的深度学习过程中会遇到这样的问题:
对于随机梯度下降来说, f ( x i ) 和 f ( x i + 1 ) f(x_i)和f(x_{i+1}) f(xi)和f(xi+1)互不相关,所以在计算梯度的时候是可以并行计算的(因为用的COST是总体得来的)。但是对于随机梯度下降的时候,由于每次的 ω \omega ω是由上次计算结果得来的,所以不能并行(因为每次计算用的随机的LOSS)。
梯度下降算法 | 随机梯度下降算法 | |
---|---|---|
性能 | 低 | 高 |
时间 | 快 | 慢 |
所以在深度学习过程中会采用折中的算法,采用Batch。
Batch:批量的随机梯度下降。将样本几个一组,进行随机梯度下降。一般Batch指的是全部样本,所以这种方法也叫做Mini(小批量)-Batch。