3 BP之梯度下降
梯度下降算法的目标是找到使损失函数L最小的参数,核心是沿着损失函数梯度的负方向更新参数,逐步逼近局部或者全局最优解,使模型更好地拟合训练数据。
1 数学描述
$$
w_{ij}^{new}= w_{ij}^{old} - \alpha \frac{\partial E}{\partial w_{ij}}
$$
α是学习率。
学习率要随着训练的进行而变化。
过程阐述
①.初始化参数:
$$
随机初始化模型的参数 \theta ,如权重 W和偏置 b。
$$
②.计算梯度:
$$
损失函数 L(\theta)对参数 \theta 的梯度 \nabla_\theta L(\theta),表示损失函数在参数空间的变化率。
$$
③.更新参数:
$$
按照梯度下降公式更新参数:\theta := \theta - \alpha \nabla_\theta L(\theta),其中,\alpha 是学习率,用于控制更新步长。
$$
④.迭代更新:
重复②-③,直到某个终止条件(梯度接近0,不再收敛,完成迭代次数等)
2 传统下降方式
根据计算梯度时数据量不同
1. 批量梯度下降-BGD
Batch Gradient Descent BGD
特点:每次更新参数时,使用整个训练集来计算梯度。
优点:收敛稳定,能准确地沿着损失函数的真实梯度方向下降
适用于小型数据集
缺点:对于大型数据集,更新速度慢
需要大量内存来存储整个数据集
公式:
$$
\theta := \theta - \alpha \frac{1}{m} \sum_{i=1}^{m} \nabla_\theta L(\theta; x^{(i)}, y^{(i)})
$$
$$
其中,m 是训练集样本总数,x^{(i)}, y^{(i)} 是第 i个样本及其标签。
$$
2.随机梯度下降-SGD
Stochastic Gradient Descent, SGD
特点:每次更新参数时,仅使用一个样本来计算梯度
优点:更新频率高,计算快,适合大规模数据集
能够跳出局部最小值,有助于找到全局最优解
缺点:收敛不稳定,容易震荡(每个样本的梯度可能都不完全代表整体方向)
需要较小的学习率来缓解震荡
公式:
$$
\theta := \theta - \alpha \nabla_\theta L(\theta; x^{(i)}, y^{(i)})
$$
$$
其中,x^{(i)}, y^{(i)} 是当前随机抽取的样本及其标签。
$$
3.小批量梯度下降-MGBD
Mini-batch Gradient Descent MGBD
特点:每次更新参数时,使用一小部分训练集(小批量)来计算梯度
优点:在计算效率和收敛稳定性直接取得平衡
能够利用向量化加速硬件,适合现代硬件(GPU)
缺点:选择合适的批量比较困难:太小接近SGD,太大接近BGD
根据硬件算力设置为2的次方
公式:
$$
\theta := \theta - \alpha \frac{1}{b} \sum_{i=1}^{b} \nabla_\theta L(\theta; x^{(i)}, y^{(i)})
$$
$$
其中,b 是小批量的样本数量,也就是 batch\_size。
$$
3问题
鞍点:导数为0,但不是极值点
收敛速度慢:BGD和MBGD使用固定学习率,太大会导致震荡,太小会收敛缓慢
局部最小值和鞍点问题:SGD遇见局部最小值或鞍点时容易停滞,导致模型难以达到全局最优
训练不稳定:SGD中的噪声容易导致训练过程中不稳定,使训练陷入震荡或者不收敛
4 优化梯度下降方式
1.指数加权平均
加权平均指的是给每个数赋予不同的权重求得平均数。
移动平均数,指的是计算最近邻的 N 个数来获得平均数。
指数移动加权平均(Exponential Moving Average简称EMA)则是参考各数值,并且各数值的权重都不同,距离越远的数字对平均数计算的贡献就越小(权重较小),距离越近则对平均数的计算贡献就越大(权重越大)。
公式:
$$
\ S_t = \begin{cases} Y_1, & t=0\\ \beta*S_{t-1} +(1-\beta)*Y_t, & t>0 \end{cases}
$$
-
St 表示指数加权平均值(EMA);
-
Yt 表示 t 时刻的值;
-
$$
\beta是平滑系数,取值范围为 0\leq \beta < 1。\beta 越接近1表示对历史数据依赖性越高;越接近0则越依赖当前数据。该值越大平均数越平缓
$$
import numpy as np
import matplotlib as plt
def test01():
np.random.seed(0)
x=np.arange(30)
print(x)
y=np.random.randint(5,40,30)
print(y)
plt.plot(x,y,c='b')
plt.scatter(x,y,c='r')
plt.show()
def test02(beta=0.9):
np.random.seed(0)
x=np.arange(30)
y=np.random.randint(5,40,30)
y_e