梯度下降是一种常用的优化算法,它通过不断迭代来最小化一个损失函数。根据不同的损失函数和迭代方式,梯度下降可以被分为批量梯度下降(Batch Gradient Descent,BGD)、随机梯度下降(Stochastic Gradient Descent,SGD)、小批量梯度下降(Mini-batch Gradient Descent)、共轭梯度法(Conjugate Gradient,CG)等。
批量梯度下降(Batch Gradient Descent,BGD)是一种非常常见的梯度下降算法,它通过在每一次迭代中计算所有训练样本的梯度来更新模型参数。其具体算法参见上一篇博文:线性回归 梯度下降原理与基于Python的底层代码实现
GD 的优点包括:
BGD 的缺点包括:
随机梯度下降(Stochastic Gradient Descent,SGD)是一种常用的梯度下降算法,它通过在每一次迭代中计算一个训练样本的梯度来更新模型参数。
SGD 的优点包括:
SGD 的缺点包括:
随机梯度下降算法适合处理大规模、稀疏或实时数据流问题,并且能够跳出局部最优解。但是,对于小规模、稠密或需要保证全局最优解的问题,SGD 的表现可能会不如批量梯度下降算法。同时,SGD 的收敛速度可能会受到震荡或抖动的影响,需要进行一些额外的优化或调整。
小批量梯度下降(Mini-batch Gradient Descent,MBGD)是一种介于批量梯度下降(Batch Gradient Descent,BGD)和随机梯度下降(Stochastic Gradient Descent,SGD)之间的梯度下降算法,它通过在每一次迭代中计算一小部分训练样本的梯度来更新模型参数。
MBGD 的优点包括:
MBGD 的缺点包括:
小批量梯度下降算法是一种折中的梯度下降算法,可以在一定程度上平衡计算效率和收敛速度,适用于大部分深度学习模型的训练。但是,需要根据具体情况来选择小批量大小,以获得最好的效果。
共轭梯度法(Conjugate Gradient,CG)是一种针对特殊的矩阵结构进行求解的迭代方法,它可以快速收敛到全局最优解。CG 方法是一种迭代算法,每次更新的方向不同于梯度方向,但会沿着前一次更新方向和当前梯度方向的线性组合方向进行更新。CG 算法的迭代过程可以描述为以下步骤:
CG 算法的优点包括:
CG 算法的缺点包括:
共轭梯度法适用于对称、正定的矩阵结构,可以快速收敛到全局最优解,并且不需要进行线搜索。但是,对于非凸优化问题和大规模问题,CG 的表现可能会受到一些限制。
此处我们假定数据集仅x一个变量,x与y的关系为y = 8 x y=8xy=8x。下面将构造100个数据,x的取值范围为range(0, 10, 0.1)。
EXAMPLE_NUM = 100
BATCH_SIZE = 10
TRAIN_STEP = 150
LEARNING_RATE = 0.0001
X_INPUT = np.arange(EXAMPLE_NUM) * 0.1
Y_OUTPUT_CORRECT = 8 * X_INPUT + np.random.uniform(low=-10, high=10)
def train_func(X, K):
result = K * X
return result
此处EXAMPLE_NUM为数据个数;BATCH_SIZE为小批量梯度下降每次使用的数据个数;TRAIN_STEP为迭代次数;X_INPUT为构造的x取值范围;Y_OUTPUT_CORRECT为对应的y真实值,这里根据xy的映射关系,在数据集上加入了(-10,10)的噪音。同时构造了train_func,用于后面梯度下降寻找最佳k值的使用。
k_BGD = 0.0
k_BGD_RECORD = [0]
for step in range(TRAIN_STEP):
SUM_BGD = 0
for index in range(len(X_INPUT)):
SUM_BGD += (train_func(X_INPUT[index], k_BGD) - Y_OUTPUT_CORRECT[index]) * X_INPUT[index]
k_BGD -= LEARNING_RATE * SUM_BGD
k_BGD_RECORD.append(k_BGD)
k_BGD为给定的初始k值,k_BGD_RECORD用于记录梯度下降过程中K值的变化。第一个循环为在150次训练中的循环,第二个循环为依次计算每一个数据的梯度,并将所有计算结果求和。这里SUM_BGD为损失函数的导数。
损失函数为:
对损失函数求导后得:
在代码中没有写出 ,是因为其本身也是一个常数,可以整合到学习速率之中。(因此相比于随机梯度下降,批量梯度下降的学习速率可以小一些,否则会学习过快)
k_SGD = 0.0
k_SGD_ECORD = [0]
for step in range(TRAIN_STEP*10):
index = np.random.randint(len(X_INPUT))
SUM_SGD = (train_func(X_INPUT[index], k_SGD) - Y_OUTPUT_CORRECT[index]) * X_INPUT[index]
k_SGD -= LEARNING_RATE * SUM_SGD
if step%10==0:
k_SGD_RECORD.append(k_SGD)
SGD就只有一个循环了,因为SGD每次只使用一个数据,同时考虑到训练速度,对其训练周期进行了10倍扩增。每计算一个数据的梯度之后,都会对k进行更新。由于k的更新较慢,因此我们采取每隔10次才记录一次k的变化值。
k_MBGD = 0.0
k_MBGD_RECORD = [0]
for step in range(TRAIN_STEP):
SUM_MBGD = 0
index_start = np.random.randint(len(X_INPUT) - BATCH_SIZE)
for index in np.arange(index_start, index_start+BATCH_SIZE):
SUM_MBGD += (train_func(X_INPUT[index], k_MBGD) - Y_OUTPUT_CORRECT[index]) * X_INPUT[index]
k_MBGD -= LEARNING_RATE * SUM_MBGD
k_MBGD_RECORD.append(k_MBGD)
MGD与BGD的代码很类似,只是每个step的数据只有BATCH_SIZE个。需要注意在随机选择数据起点时,其范围是0至len(X_INPUT) - BATCH_SIZE,以免数据的选择范围超出数据量。
plt.plot(np.arange(TRAIN_STEP+1), np.array(k_BGD_RECORD), label='BGD')
plt.plot(np.arange(TRAIN_STEP+1), k_SGD_RECORD, label='SGD')
plt.plot(np.arange(TRAIN_STEP+1), k_MBGD_RECORD, label='MBGD')
plt.legend()
plt.ylabel('K')
plt.xlabel('step')
plt.show()
可以看到BGD的训练效果最快,这是因为BGD的数据量比另外两种多了10倍。通常情况下,BGD的曲线会更加平滑,另外两种方法会有偶尔的偏离正确值的情况。但BGD无法避开局部最优,由于本函数不存在局部最优,因此三种效果的拟合方法都还不错。
阅读量:2023
点赞量:0
收藏量:0