《PyTorch深度学习实践》- 刘二大人p3 - 梯度下降算法

梯度下降算法(Gradient_Descent_Algorithm)

《PyTorch深度学习实践》- 刘二大人p3

image-20220913154654478

红点的x轴取值为一开始ω随机取值,曲线最低点为实际最优点,那此时ω该取左边或右边(取小或大一点值)呢?可使用梯度下降算法。

梯度下降算法:

image-20220913154707893

对红点处求导,导数大于0,则说明该点右侧是向上增加的,导数小于0,则说明该点右侧是向下递减的,则w下一次取小点的数。

更新权重w:

公式:

image-20220913154720206

w:权重

α:学习率 (不要取大了,不然w也会跟着取太大了)

缺点:只能找到局部最优点,而不是全局最优点。

对下面这种非凸函数,w取值可能会靠向红点凹处(称为局部最优点),而离实际的最低点还差很多。

image-20220913154737618

特殊:导数(梯度)等于0。此处公式无法使用。

鞍点:

image-20220913154754087

该点处即是最小点,又是最大点。

公式简化:

image-20220913154808585

红圈为梯度,Update即为最新公式。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import numpy as np
import matplotlib.pyplot as plt

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

w = 1.0
#初始猜测w = 1.0

def forward(x):
return x * w

#求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)

#求梯度函数
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 = []
epoch_list = []

print('Predict (before trraining)', 4 , forward(4))

for epoch in range(1000): #训练1000次
epoch_list.append(epoch)
cost_val = cost(x_data, y_data)
cost_list.append(cost_val)
#cost_val为MSE,损失
grad_val = gradient(x_data, y_data)
#grad_val为梯度
w -= 0.01 * grad_val
#更新w的公式,其中α设为0.01
print('Epoch:', epoch, 'w=', w, 'cost=', cost_val)
print('Predict (after training', 4, forward(4))

plt.plot(epoch_list, cost_list)
plt.ylabel('Cost')
plt.xlabel('Epoch')
plt.show()

结果图:

image-20220913154825667

正确的,cost趋近于0。如果后面还抬上去了,变成凹函数,说明训练发散了,可能α取太大了,而不是最低点是最优点。

改进版:随机梯度下降算法(SGD)

image-20220913154845815

使用原因:

1、上面算法是取了一个样本,可能最终到A点后就停止了(如上面训练1000此后w接近2,不再变化),但此处并不是最低点,使用随机在所有样本取点,可能训练后到B点,再训练后继续前进到达最低点!

2、大样本学习时,若采用所有样本的的损失,计算量太大,训练很久。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

w = 1.0

def forward(x):
return x * w


def loss(x, y):
y_pred = forward(x)
return (y_pred - y) ** 2

def gradient(x, y):
return 2 * x * (x * w - y)


print('Predict (before trraining)', 4 , forward(4))

for epoch in range(1000): #训练1000次
for x, y in zip(x_data, y_data):
grad = gradient(x, y)
w -= 0.01 * grad
print("\tgrand:", x, y, grad)
l = loss(x, y)

print('progress:', epoch, 'w=', w, 'loss=', l)
文章作者: CasimiBreidin
文章链接: https://blognotes.cn/posts/17128.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Casimi’Blog