在机器学习中,对于很多监督学习模型,需要对原始的模型构建损失函数,接下来便通过优化算法对损失函数进行优化,以方便找到最优的参数。
机器学习中较常使用的优化算法是梯度下降算法,在梯度下降算法求解过程中,只需要求解损失函数的一阶导数,因此其计算的代价比较小。
梯度下降算法的基本思想可以理解为:从山上的某一点出发,找一个最陡的坡走一步(即找梯度方向),到达一个点之后,再找最陡的坡,再走一步,不断地走,直到走到最低点(最小花费的函数收敛点)。
梯度下降算法有三种不同的形式:批量梯度下降(Batch Gradient Descent,BGD)、随机梯度下降(Stochastic Gradient Descent,SGD)及小批量梯度下降(Mini-Batch Gradient Descent,MBGD)。其中小批量梯度下降算法也常用在深度学习中进行模型的训练。接下来将对这三种不同的梯度下降算法进行介绍。
为了便于理解,这里将使用只含有一个特征的线性回归来展开。线性回归的假设函数为
其中, i =1,2,…, m 表示样本数。对应的目标函数(代价函数)即为
批量梯度下降算法是最原始的形式,它是指在每一次迭代时使用所有样本来进行梯度的更新。从数学上理解如下:
(1)对目标函数求偏导。
其中,
i
=1,2,…,
m
表示样本数,
j
=0,1表示特征数,此处使用了偏置项
。
(2)每次迭代对参数进行更新。
注意: 此处在更新时存在一个求和函数,即为对所有样本进行计算处理,可与下文随机梯度下降算法进行比较。
该算法主要有以下优点。
(1)一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。
(2)由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,批量梯度下降算法一定能够得到全局最优。
但同时该算法也存在缺点:当样本数目 m 很大时,每迭代一步都需要对所有样本计算,训练过程会很慢。
图2-14为批量梯度下降算法过程。
图2-14 批量梯度下降算法过程
【例2-2】 利用批量梯度下降算法对数据集进行训练。
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)参数更新。
提示: 这里不再有求和符号。
图2-15为随机梯度下降算法过程。
图2-15 随机梯度下降算法过程
随机梯度下降算法的优点为:由于不是在全部训练数据上的损失函数,而是在每轮迭代中随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大幅加快。
该算法的缺点主要表现在:
(1)准确度下降。即使在目标函数为强凸函数的情况下,随机梯度下降算法仍旧无法做到线性收敛。
(2)可能会收敛到局部最优,因为单个样本并不能代表全体样本的趋势。
(3)不易于并行实现。
【例2-3】 利用随机梯度下降算法对数据集进行训练。
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 )个样本进行学习。其目标函数为
图2-16为小批量梯度下降算法过程。
图2-16 随机梯度下降算法与小批量梯度下降算法过程对比
从图2-16可看出,相对于随机梯度下降算法,小批量梯度下降算法降低了收敛波动性,即降低了参数更新的方差,使得更新更加稳定。相对于批量梯度下降算法,小批量梯度下降算法提高了每次学习的速度,并且不用担心内存瓶颈,从而可以利用矩阵运算进行高效计算。普遍来说,每次更新随机选择50~256个样本进行学习,但是也要根据具体问题而选择,实践中可以进行多次试验,选择一个更新速度与更次次数都较适合的样本数。
小批量梯度下降算法的优点主要表现在:
(1)通过矩阵运算,每次在一个batch上优化神经网络,其参数并不会比单个数据慢太多。
(2)每次使用一个batch,可以大幅度减小收敛所需要的迭代次数,同时可以使收敛的结果更加接近梯度下降的效果。
(3)实现并行化。
该算法的缺点主要是batch_size的不当选择可能会带来一些问题。
batch_size的选择带来的影响如下。
(1)在合理范围内,增大batch_size的好处:
· 内存利用率提高了,大矩阵乘法的并行化效率提高。
· 运行完一次epoch(全数据集)所需的迭代次数减少,对于相同数据量的处理速度进一步加快。
· 在一定范围内,一般来说batch_size越大,其确定的下降方向越准,引起训练的震荡越小。
(2)盲目增大batch_size也存在坏处,表现在:
· 内存利用率提高了,但是内存容量可能撑不住了。
· 运行完一次epoch所需的迭代次数减少,要想达到相同的精度,其所花费的时间大幅增加了,从而对参数的修正也就显得更加缓慢。
· batch_size增大到一定程度,其确定的下降方向已经基本不再变化。
【例2-4】 利用小批量梯度下降算法对数据集进行训练。
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中一个梯度下降方式后,接下就要对下降梯度算法进行调优,那么应该从哪些方面进行调优呢?
在 θ 迭代计算公式中,其中的偏导数的系数 α 是学习率,且 α >0。
(1)固定的 α , α 太大,导致迭代次数变少(因为 θ 增量变大),学习率变快,训练快。但是 α 不是越大越好,如果 α 太大,会导致梯度下降算法在图形的上坡和下坡上面来回震荡计算,严重的结果可能无法收敛。
(2)固定的 α , α 太小,导致迭代次数变多(因为 θ 增量变小),学习率变慢,训练慢。但是 α 不是越小越好,如果 α 太小,会导致梯度下降算法在图形迭代到最优点处整个过程需要训练很长时间,就算取得最优 θ ,但训练太慢了。
(3)变化的 α ,当梯度大时,学习率变大,梯度小时,学习率变小。则学习率和梯度是一个正相关,可以提高下降算法的收敛速度。 α 和梯度的正相关有一个比例系数,称为固定学习率(fixed learning rate)。固定学习率一般取0.1或者0.1附近的值,可能不是最好但是一定不会太差。
首先,初始值 θ 不同,获得的代价函数的最小值也可能不同,因为每一步梯度下降求得的只是当前局部最小值而已,所以需要多次进行梯度下降算法的训练,每次初始值 θ 都不同,然后选取代价函数取得的最小值的那组当作初始值 θ 。
如果样本不相同,那么特征值的取值范围也一定不同。因为特征值的取值范围可能会导致迭代很慢,所以就要采取措施减少特征值取值范围对迭代的影响,这个措施就是对特征数据归一化。
数据归一化方法有两种,分别为:
(1)线性归一化。
(2)均值归一化。
一般图像处理时使用线性归一化方法,如将灰度图像的灰度数据由[0,255]范围归一化到[0,1]范围。如果原始数据集的分布近似为正态(高斯)分布,那么可以使用均值归一化对数据集进行归一化,归一化为均值为0、方差为1的数据集。这里面采用均值归一化,均值归一化的公式如下所示:
其中, μ 是原始数据集的均值, σ 是原始数据的标准差。求出来的归一化数据是均值为0、方差为1的数据集。
经过特征数据归一化后,梯度下降算法会在期望值为0、标准差为1的归一化特征数据上进行迭代计算 θ ,这样迭代会大幅加快。