AI初学笔记 2
前言
上次设计的训练模型是使用穷举的方式,列出范围内所有可能性,最后寻找出最优解,但这种方式显然不能应对复杂场景,过于庞大的数据是无法列出所有可能性的,所以需要设计一种方法,让模型更有针对性的,自动的去寻找最优解,向最优解靠拢。
一、梯度下降算法
梯度下降算法的核心思想就是利用函数曲线的导数,也就是斜率,对模型下一次计算的方向进行引导,最终指向导数为0,也就是曲线的最低点,损失最小点。
实现的公式推导过程如下:
如图所示在曲线红点位置,导数为正,所以需要w减小,反向调整以达到最低点,公式中 α 表示学习率,即每次调整的幅度。求导过程中需要注意的是偏导数的链式法则,具体可以详见:高等数学同济版第九章——多元函数微分法及其应用。
二、代码实现
1.数据
代码如下:
import numpy as np
import matplotlib.pyplot as plt
x_data = [1, 2, 3]
y_data = [2, 4, 6]
w = 1
cost = 0
l_list = []
epoch_list = []
数据与上次相同,为x_data,y_data,目的仍为求w最佳值,只不过此次不是使用穷举法,而是利用梯度下降,自动寻找最低点。
2.定义函数
代码如下:
def foward(x):
return w * x
def loss(x, y):
y_pred = foward(x)
return (y_pred - y) ** 2
def gradient(x, y):
return 2 * x * (w * x - y)
新增梯度下降函数:gradient(x, y),具体的更新过程由后续代码实现,此处仅为梯度计算。
3.主要流程
代码如下:
for epoch in range(100):
l = 0
l_sum = 0
for x, y in zip(x_data, y_data):
w -= 0.01 * gradient(x, y)
print('w = ', w)
l = loss(x, y)
l_sum += l
cost = l_sum / 3
epoch_list.append(epoch)
l_list.append(cost)
print('epoch = ', epoch, '\ncost = ', cost)
定义epoch,一般深度学习都是以每个epoch为小集体进行训练,本次代码中共使用100个epoch,使用for循环对epoch进行遍历,并在每个epoch中嵌套使用for循环对数据集x_data,y_data,进行遍历。
使用 w -= 0.01 * gradient(x, y) 对w进行更新,如果梯度为正,w会逐渐减小,如果梯度为负,w会逐渐增大,直到梯度为0时,w会不增不减,此时w为最佳值,损失值也是最小。(仅为简单曲线时,复杂数据还需要使用特定方法克服梯度消失梯度爆炸等问题,日后有待学习)。
编写程序时 l_sum += l 这一句出过一个小问题,运行后报错显示 ‘+=’ 无法使 ‘int’ 和 ‘str’ 不同形式相加,报错的原因在于我想把损失 l 的科学计数法表示成小数,结果导致 l_sum 和 l 形式不统一。
总结
梯度下降算法可以通过梯度对w进行有方向的调整,而不用列举所有可能性,但这里仍存在一些问题,比如如果曲线有一段梯度为0,之后曲线继续下降,则梯度为0的时候,w无法更新,后续低点也不能探索到,如果波动较大的曲线,可以尝试提高学习率,这样有可能跳过梯度为0的点,但也有可能错过低点,应视实际情况进行调整(我好像有点理解为什么ai从业者外号叫做调参侠了……)。