文章目录

  • 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()
  • 手写一下整个过程:
  • python根据epoch绘制loss曲线 pytorch画loss曲线_深度学习

  • 输出的loss与w 之间的关系。
  • python根据epoch绘制loss曲线 pytorch画loss曲线_深度学习_02

  • 输出的一部分结果,可以看出每一步w对loss值的关系。
  • w=0.3000000000000000004,是由于在计算机内,有些十进制小数是无法用有限位的二进制小数表示的。【比如0.1】
  • python根据epoch绘制loss曲线 pytorch画loss曲线_深度学习_03

2 引入梯度下降问题

  • 所谓梯度下降,简单的说,就是找到一种使得目标函数(也就是loss函数)值最小化的方法。
  • 它利用梯度信息,通过不断迭代调整参数来寻找合适的目标值。

在1节中,我们选取的loss函数(损失函数)是MSE函数(求均方差函数),这类函数广泛应用在线性模型中。

根据我们画出的loss函数图像,我们可以明显看出w=2时,loss=0,此时是loss=0,也就是三个预测值=三个真实值的情况,此时的参数w=2是最好的。(当然了,这也不难看出,loss在一般情况下只能是接近于0

python根据epoch绘制loss曲线 pytorch画loss曲线_深度学习_04


当我们P点时,我们需要做的就是从python根据epoch绘制loss曲线 pytorch画loss曲线_人工智能_05点不断向python根据epoch绘制loss曲线 pytorch画loss曲线_随机梯度下降_06点靠近,直到我们降到loss最低的地方。

  • 更新python根据epoch绘制loss曲线 pytorch画loss曲线_随机梯度下降_07的方法,就如下图所示:
  • 其中,python根据epoch绘制loss曲线 pytorch画loss曲线_随机梯度下降_08是学习率,偏导数部分是决定python根据epoch绘制loss曲线 pytorch画loss曲线_tensorflow_09点的移动方向,一般来说我们的python根据epoch绘制loss曲线 pytorch画loss曲线_随机梯度下降_08都取一个比较小的值,例如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()
  • 输出结果:

  • python根据epoch绘制loss曲线 pytorch画loss曲线_随机梯度下降_11
    python根据epoch绘制loss曲线 pytorch画loss曲线_梯度下降_12

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组!