文章目录
- 1 线性模型计算loss代码分析
- 2 引入梯度下降问题
- 2.1 梯度下降【代码】
- 3 鞍点问题
- 4 解决鞍点问题:引入随机梯度下降
- 4.1 随机梯度下降【代码】
- 5 随机梯度下降vs梯度下降
- 5.1 随机梯度下降
- 5.2 梯度下降
- 6 两者折中解决:batch
- 6.1 举例说明mini-Batch
写在前面:学习pytorch的第二天,今天继续加深loss函数和w参数之间的关系,利用matplot画图表示。可以画出二维图像,也就是参数只有一个的情况。
1 线性模型计算loss代码分析
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]
def forward(x):
return x * w
def loss(x, y):
y_pred = forward(x)
return (y_pred - y)*(y_pred - y)
w_list = []
mse_list = []
for w in np.arange(0.0, 4.1, 0.1): # arange左闭右开 [start, stop)
print('w=', w)
l_sum = 0
for x_val, y_val in zip(x_data, y_data): # 对于每一次w,都去计算一下此时的loss
y_pred_data = forward(x_val) # 记录值,用于输出
loss_val = loss(x_val, y_val)
l_sum += loss_val
print('\t', x_val, y_val, y_pred_data, loss_val)
print('MSE=', l_sum/3) # 除以3 :一次输入了是三个值去算loss
w_list.append(w)
mse_list.append(l_sum/3)
plt.plot(w_list, mse_list)
plt.ylabel('Loss')
plt.xlabel('w')
plt.show()
- 手写一下整个过程:
- 输出的loss与w 之间的关系。
- 输出的一部分结果,可以看出每一步w对loss值的关系。
- w=0.3000000000000000004,是由于在计算机内,有些十进制小数是无法用有限位的二进制小数表示的。【比如0.1】
2 引入梯度下降问题
- 所谓梯度下降,简单的说,就是找到一种使得目标函数(也就是loss函数)值最小化的方法。
- 它利用梯度信息,通过不断迭代调整参数来寻找合适的目标值。
在1节中,我们选取的loss函数(损失函数)是MSE函数(求均方差函数),这类函数广泛应用在线性模型中。
根据我们画出的loss函数图像,我们可以明显看出w=2时,loss=0,此时是loss=0,也就是三个预测值=三个真实值的情况,此时的参数w=2是最好的。(当然了,这也不难看出,loss在一般情况下只能是接近于0)
当我们P点时,我们需要做的就是从点不断向点靠近,直到我们降到loss最低的地方。
- 更新的方法,就如下图所示:
- 其中,是学习率,偏导数部分是决定点的移动方向,一般来说我们的都取一个比较小的值,例如0.001,防止w更新的太快,跳过全局最优。
2.1 梯度下降【代码】
- 这份代码完整可以直接执行
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 # 随机设置的
# forward函数:用于计算y_pred(y的预测值)
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 # 梯度grad归零
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y) # 这里是对(y_pred - y) ** 2对w求导
return grad / len(xs)
epoch_list = []
cost_list = []
print('输出更新w之前,对于x=4的预测值: ', 4, forward(4))
for epoch in range(100):
cost_val = cost(x_data, y_data)
grad_val = gradient(x_data, y_data)
w = w - 0.01 * grad_val # 更新w值
print('Epoch:', epoch, 'w= ', w, 'loss= ', cost_val)
epoch_list.append(epoch)
cost_list.append(cost_val)
print('输出更新w之后,对于x=4的预测值: ', 4, forward(4))
plt.plot(epoch_list, cost_list)
plt.ylabel('Cost')
plt.xlabel('Epoch')
plt.show()
- 输出结果:
…
3 鞍点问题
- 在深度学习中,最大的问题不是局部最优(可以通过随机batch来解决),最大的问题是鞍点问题,一旦陷入鞍点,w就无法继续更新了。
4 解决鞍点问题:引入随机梯度下降
- 在2.1中的代码,我们采用的是梯度下降方式,对于数据集:x=[1.0,2.0,3.0] y=[2.0,4.0,6.0],我们一次性输入并计算出cost值和gradient。
- 而目前机器学习,常用的是随机梯度下降算法,也就是将三组x值和y值分三次输入,一次输入一组值,这样由于值内的噪声,就可以推动loss函数走出鞍点。
- 总的来说,就是对每组样本计算loss和gradient。
观察一下cost函数和gradient函数,上面一个是梯度下降,下面一个是随机梯度下降。
# 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)
def cost(x, y):
y_pred = forward(x)
return (y_pred - y) ** 2
# gradient函数:
def gradient(xs, ys):
grad = 0 # 梯度grad归零
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y) # 这里是对(y_pred - y) ** 2对w求导
return grad / len(xs)
def gradient(x, y):
return 2 * x * (x * w - y)
4.1 随机梯度下降【代码】
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 # 随机设置的
# forward函数:用于计算y_pred(y的预测值)
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)
epoch_list = []
cost_list = []
print('输出更新w之前,对于x=4的预测值: ', 4, forward(4))
for epoch in range(100):
for x, y in zip(x_data, y_data):
loss_val = loss(x, y)
grad_val = gradient(x, y)
w = w - 0.01 * grad_val # 更新w值
print('Epoch:', epoch, 'w= ', w, 'loss= ', loss_val)
epoch_list.append(epoch)
cost_list.append(loss_val)
print('输出更新w之后,对于x=4的预测值: ', 4, forward(4))
plt.plot(epoch_list, cost_list)
plt.ylabel('Cost')
plt.xlabel('Epoch')
plt.show()
- 输出结果:
5 随机梯度下降vs梯度下降
5.1 随机梯度下降
- 优点:
(1)是串行处理的,比如说我们输出了三组x y,那么第一组更新的w,就要到下一组使用,下一组更新的w就会到第三组中使用。
(2)收敛速度快。 - 缺点:
(1)效率不高,时间复杂度太高
5.2 梯度下降
- 优点
(1)并行处理,速度快。 - 缺点:
(1)性能不高。
6 两者折中解决:batch
- Batch:对于 一万个数据 , 我们可以使用若干个一组,也就是Batch,更正式的名字叫做:mini-Batch
6.1 举例说明mini-Batch
- 假设输入数据有 10000个,随机梯度下降太慢,梯度下降性能不好,所以我们可以分成64个一组,也就分成了157组(不整除就进1)。
- 157组全部输入计算完成后,称为1个epoch,如果是100个epoch,那么就是要计算157*100组!