b站视频连接:https://www.bilibili.com/video/BV1Y7411d7Ys?p=3
上一节我们用穷举法
列举出了所有的可能的k,并且计算了损失函数,损失越小,说明我们的k就越接近,这一次我们用梯度下降,继续计算损失,而不是穷举法了。
cost(w)=1/n∑(y`-y)^2
明显cost对w是一个二次函数,我们只要找到二次函数的最低点即可
不论我们在那边,只要沿着梯度的方向即可找到局部最优解(非二次函数可能有多个最优解),也就是极小值。
代码:
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
# define the model linear model y = w*x
def forward(x):
return x * w
# define the cost function MSE
# cost(w)=1/n∑(y`-y)^2
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)
# define the gradient function gd
# cost(w)=1/n∑(y`-y)^2
# αcost/αw,也就是cost对w的导数
# 计算所有样本梯度的均值
def gradient(xs, ys):
grad = 0
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y)
return grad / len(xs)
epoch_list = []
cost_list = []
# 训练过程w=w-α*gradient
print('predict (before training)', 4, forward(4)) # 未训练前,当x=4时,y=4
for epoch in range(100):
cost_val = cost(x_data, y_data) # 其实不算也可以,为了画图
grad_val = gradient(x_data, y_data)
w -= 0.01 * grad_val # 0.01 learning rate
print('epoch:', epoch, 'w=', w, 'loss=', cost_val)
epoch_list.append(epoch)
cost_list.append(cost_val)
print('predict (after training)', 4, forward(4)) # 训练后,w=2,当x=4时,y=8
plt.plot(epoch_list, cost_list)
plt.ylabel('cost')
plt.xlabel('epoch')
plt.show()
随机梯度下降法
随机梯度下降法在神经网络中被证明是有效的。梯度下降容易进入鞍点,所以采用随机梯度,不是直接走向最低点,但总的大方向还是向最低点走。
效率较低(时间复杂度较高),学习性能较好。
随机梯度下降法和梯度下降法的主要区别在于:
1、损失函数由cost()更改为loss()。cost是计算所有训练数据的损失,loss是计算一个训练函数的损失。对应于源代码则是少了两个for循环。
2、梯度函数gradient()由计算所有训练数据的梯度更改为计算一个训练数据的梯度。
代码:
import matplotlib.pyplot as plt
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# 初始猜测为1
w = 1.0
def forward(x):
return x * w
# 随机梯度用的更多
# 与梯度下降不同的是,cost变为了loss,少了一个for循环求和
# 梯度下降是用所有样本的损失,而随机梯度是用单个样本的损失
def loss(x, y):
y_pred = forward(x)
return (y_pred - y) ** 2
# define the gradient function sgd
# 注意区分普通梯度下降,少了一个for循环求和
# 因为只用了一个样本的梯度,没有用所有样本的梯度,所以没有求和
def gradient(x, y):
return 2 * x * (x * w - y)
epoch_list = []
loss_list = []
print('predict (before training)', 4, forward(4))
for epoch in range(100):
for x, y in zip(x_data, y_data): # 其实这里应该随机取这三个里面的某一个,而不是三个都用来更新,这才体现了随机
grad = gradient(x, y)
w = w - 0.01 * grad # update weight by every grad of sample of training set
print("\tgrad:", x, y, grad)
l = loss(x, y)
print("progress:", epoch, "w=", w, "loss=", l)
epoch_list.append(epoch)
loss_list.append(l)
# SGD不能并行,但单次运算快
# GD可以并行,但单次慢
# 所以折中用Batch GD,批量随机梯度下降Mini-Batch
print('predict (after training)', 4, forward(4))
plt.plot(epoch_list, loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()