首页 > 编程笔记 > Python笔记 阅读:2

梯度下降算法详解(附带实例)

机器学习中较常使用的优化算法是梯度下降算法,在梯度下降算法求解过程中,只需要求解损失函数的一阶导数,因此其计算的代价比较小。

梯度下降算法的基本思想可以理解为:从山上的某一点出发,找一个最陡的坡走一步(即找梯度方向),到达一个点之后,再找最陡的坡,再走一步,不断地走,直到走到最低点(最小花费的函数收敛点)。

梯度下降算法有三种不同的形式:
其中小批量梯度下降算法也常用在深度学习中进行模型的训练。接下来将对这三种不同的梯度下降算法进行介绍。

为了便于理解,这里将使用只含有一个特征的线性回归来展开。线性回归的假设函数为:


其中,i=1,2,…,m 表示样本数。对应的目标函数(代价函数)即为:

批量梯度下降算法

批量梯度下降算法是最原始的形式,它是指在每一次迭代时使用所有样本来进行梯度的更新。从数学上理解如下:

1) 对目标函数求偏导:


其中,i=1,2,…,m 表示样本数,j=0,1 表示特征数,此处使用了偏置项:


2) 每次迭代对参数进行更新:


注意,此处在更新时存在一个求和函数,即为对所有样本进行计算处理,可与下文随机梯度下降算法进行比较。

该算法主要有以下优点:
但同时该算法也存在缺点,当样本数目 m 很大时,每迭代一步都需要对所有样本计算,训练过程会很慢。

下图为批量梯度下降算法过程:


图 6 批量梯度下降算法过程

【实例】利用批量梯度下降算法对数据集进行训练。
import numpy as np

#创建数据集X,y
np.random.seed(1)
X=np.random.rand(100, 1)
y=4+3 * X+np.random.randn(100, 1)
X_b=np.c_[np.ones(100, 1), X]
#创建超参数
n_iterations=10000
t0,t1=5,500
#定义一个函数来动态调整学习率
def learning_rate_schedule(t):
    return t0/(t+t1)
#初始化θ,W0,…,Wn,标准正态分布创建W
theta=np.random.randn(2, 1)
#判断是否收敛,不设定阈值,而是直接采用设置相对大的迭代次数保证可以收敛
for i in range(n_iterations):
    #求梯度,计算gradients
    gradients=X_b.T.dot(X_b.dot(theta)-y)
    #应用梯度下降算法的公式去调整θ值,θ(t+1)=θ(t)-η * gradients
    learning_rate=learning_rate_schedule(i)
    theta=theta-learning_rate * gradients
print(theta)
运行程序,输出如下:

[[4.23695725]
[2.68492509]]

随机梯度下降算法

随机梯度下降算法不同于批量梯度下降算法,随机梯度下降算法是每次迭代使用一个样本来对参数进行更新,使得训练速度加快。

对于一个样本的目标函数为:


1) 对目标函数求偏导:


2) 参数更新:

这里不再有求和符号。

下图为随机梯度下降算法过程:


图 10 随机梯度下降算法过程

随机梯度下降算法的优点为,由于不是在全部训练数据上的损失函数,而是在每轮迭代中随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大幅加快。

该算法的缺点主要表现在:
【实例】利用随机梯度下降算法对数据集进行训练。
import numpy as np

#创建数据集
X=2 * np.random.rand(100, 1)
y=4+3 * X+np.random.randn(100, 1)
X_b=np.c_[np.ones(100, 1), X]
#创建超参数
n_epochs=10000
m=  100
t0,t1=5, 500

#定义一个函数来调整学习率
def learning_rate_schedule(t):
    return t0/(t+t1)

theta=np.random.randn(2, 1)
for epoch in range(n_epochs):
    #在双层for循环之间,每一轮开始分批次迭代之前打乱数据索引顺序
    arr=np.arange(len(X_b))
    np.random.shuffle(arr)
    X_b=X_b[arr]
    y=y[arr]
    for i in range(m):
        xi=X_b[i:i+1]
        yi=y[i:i+1]
        gradients=xi.T.dot(xi.dot(theta)-yi)
        learning_rate=learning_rate_schedule(epoch * m+        i)
        theta=theta-learning_rate * gradients
print(theta)
运行程序,输出如下:

[[3.67474671]
 [3.31921676]]

小批量梯度下降算法

小批量梯度下降算法综合了批量梯度下降算法与随机梯度下降算法,在每次更新速度与更新次数中间取得一个平衡,其每次更新从训练集中随机选择 batch_size(batch_size<m) 个样本进行学习。其目标函数为:


下图为小批量梯度下降算法过程:


图:随机梯度下降算法与小批量梯度下降算法过程对比

从图中可看出,相对于随机梯度下降算法,小批量梯度下降算法降低了收敛波动性,即降低了参数更新的方差,使得更新更加稳定。相对于批量梯度下降算法,小批量梯度下降算法提高了每次学习的速度,并且不用担心内存瓶颈,从而可以利用矩阵运算进行高效计算。

普遍来说,每次更新随机选择 50~256 个样本进行学习,但是也要根据具体问题而选择,实践中可以进行多次试验,选择一个更新速度与更次次数都较适合的样本数。

小批量梯度下降算法的优点主要表现在:
该算法的缺点主要是 batch_size 的不当选择可能会带来一些问题。

batch_size 的选择带来的影响如下:
1) 在合理范围内,增大 batch_size 的好处:
2) 盲目增大 batch_size 也存在坏处,表现在:
【实例】利用小批量梯度下降算法对数据集进行训练。
import numpy as np

#创建数据集X,y
X=2 * np.random.rand(100, 1)
y=4+3 * X+np.random.randn(100, 1)
X_b=np.c_[np.ones(100, 1)), X]
#创建超参数
t0,t1=5,500

#定义一个函数来动态调整学习率
def learning_rate_schedule(t):
    return t0/(t+t1)

n_epochs=100000
m=100
batch_size=10
num_batches= int(m/batch_size)
theta=np.random.randn(2, 1)
for epoch in range(n_epochs):
    arr=np.arange(len(X_b))
    np.random.shuffle(arr)
    X_b=X_b[arr]
    y=y[arr]
    for i in range(num_batches):
        x_batch=X_b[i * batch_size:i * batch_size+batch_size]
        y_batch=y[i * batch_size:i * batch_size+batch_size]
        gradients=x_batch.T.dot(x_batch.dot(theta)-y_batch)
         learning_rate=learning_rate_schedule(epoch * m+         i)
        theta=theta-learning_rate * gradients
print(theta)
运行程序,输出如下:

[[4.19657912]
 [2.70863262]]

梯度下降算法的调优

当选择好了使用 BGD、SGD、MBGD 中一个梯度下降方式后,接下就要对下降梯度算法进行调优,那么应该从哪些方面进行调优呢?

1) 学习率α调优

在 θ 迭代计算公式中,其中的偏导数的系数 α 是学习率,且α>0。

① 固定的 α,α 太大,导致迭代次数变少(因为 θ 增量变大),学习率变快,训练快。但是 α 不是越大越好,如果 α 太大,会导致梯度下降算法在图形的上坡和下坡上面来回震荡计算,严重的结果可能无法收敛。

② 固定的 α,α 太小,导致迭代次数变多(因为 θ 增量变小),学习率变慢,训练慢。但是 α 不是越小越好,如果 α 太小,会导致梯度下降算法在图形迭代到最优点处整个过程需要训练很长时间,就算取得最优 θ,但训练太慢了。

③ 变化的 α,当梯度大时,学习率变大,梯度小时,学习率变小。则学习率和梯度是一个正相关,可以提高下降算法的收敛速度。α 和梯度的正相关有一个比例系数,称为固定学习率(fixed learning rate)。固定学习率一般取 0.1 或者 0.1 附近的值,可能不是最好但是一定不会太差。

2) 选取最优的初始值θ

首先,初始值 θ 不同,获得的代价函数的最小值也可能不同,因为每一步梯度下降求得的只是当前局部最小值而已,所以需要多次进行梯度下降算法的训练,每次初始值 θ 都不同,然后选取代价函数取得的最小值的那组当作初始值 θ。

3) 特征数据归一化处理

如果样本不相同,那么特征值的取值范围也一定不同。因为特征值的取值范围可能会导致迭代很慢,所以就要采取措施减少特征值取值范围对迭代的影响,这个措施就是对特征数据归一化。

数据归一化方法有两种,分别为:
一般图像处理时使用线性归一化方法,如将灰度图像的灰度数据由 [0,255] 范围归一化到 [0,1] 范围。如果原始数据集的分布近似为正态(高斯)分布,那么可以使用均值归一化对数据集进行归一化,归一化为均值为 0、方差为 1 的数据集。

这里面采用均值归一化,均值归一化的公式如下所示:


其中,μ 是原始数据集的均值,σ 是原始数据的标准差。求出来的归一化数据是均值为 0、方差为 1 的数据集。

经过特征数据归一化后,梯度下降算法会在期望值为 0、标准差为 1 的归一化特征数据上进行迭代计算 θ,这样迭代会大幅加快。

相关文章