2.2.1 梯度下降算法
梯度下降算法是神经网络中流行的优化算法之一,它能够很好地解决一系列问题。该算法通过迭代地更新参数,可以使整体网络的误差最小化。
梯度下降算法的参数更新公式如下:
其中,η是学习率,θt是第t轮的参数,J(θt)是损失函数,∇J(θt)是梯度。
为了简便,常令gt=∇J(θt),所以梯度下降算法可以表示为:
该算法在损失函数的梯度上迭代地更新权重参数,直至达到最小值。换句话说,我们沿着损失函数的斜坡方向下坡,直至到达山谷。梯度下降算法的基本思想大致如图2-7所示。
图2-7 梯度下降算法的基本思想
从图2-7可知,如果偏导数为负,则增加权重(见图2-7a),如果偏导数为正,则减少权重(见图2-7b)。
梯度下降算法中一个重要的参数是步长,超参数学习率的值决定了步长的大小。如果学习率太小,必须经过多次迭代,算法才能收敛,这是非常耗时的。如果学习率太大,你将跳过最低点,到达山谷的另一面,可能下一次的值比这一次还要大,使得算法是发散的,函数值变得越来越大,永远不可能找到一个好的答案。如图2-8所示。
图2-8 学习率过小或过大时的梯度下降
梯度下降算法有三种不同的形式:批量梯度下降(Batch Gradient Descent,BGD)、随机梯度下降(Stochastic Gradient Descent,SGD)以及小批量梯度下降(Mini-Batch Gradient Descent,MBGD)。其中,小批量梯度下降法也常用在深度学习中进行模型的训练。接下来,我们将详细介绍这三种不同的梯度下降算法。
1. 批量梯度下降算法
批量梯度下降是最原始的形式,是指在每一次迭代时使用所有样本来进行梯度的更新。批量梯度下降算法的优点如下:
- 一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。
- 由全部数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,批量梯度下降算法一定能够得到全局最优。
批量梯度下降算法的主要缺点是,当样本数目很大时,每迭代一次都需要对所有样本进行计算,训练过程会很慢。
为了便于理解,这里我们使用只含有一个特征的线性回归,并使用批量梯度下降算法求解。本例中我们使用三个不同的学习率进行1000次迭代得到最优模型。图2-9展示了三个不同学习率进行批量梯度下降的前10次迭代的结果(实线是最优拟合直线,代码见本书的代码资源中的gradient_descent.R)。
图2-9 不同学习率的批量梯度下降
从图2-9可知,图2-9a的学习率是最小的,算法在经过10次迭代后几乎不能求出最后的结果,而且会花费大量的时间。图2-9b的学习率表现得不错,在经过10次迭代后几乎能找到不错的拟合直线。图2-9c的学习率太大了,算法是发散的,跳过了所有的训练样本,同时每一次迭代都离正确的结果更远。
2. 随机梯度下降算法
随机梯度下降算法不同于批量梯度下降算法,是每次迭代只使用一个样本来对参数进行更新,加快训练速度。
随机梯度下降算法的优点如下:
由于损失函数不是基于全部训练数据,而是在每次迭代中随机优化某一条训练数据,使得每一次参数的更新速度大大加快。
缺点如下:
- 准确率下降,即使在目标函数为强凸函数的情况下,随机梯度下降算法仍旧无法做到线性收敛。
- 可能会收敛到局部最优,因为单个样本并不能代表全体样本的趋势。
- 不易于并行实现。
虽然随机性可以很好地跳过局部最优值,但它却不能达到最小值。解决这个难题的一个办法是逐渐降低学习率。开始时,走的每一步较大(这有助于在快速前进的同时跳过局部最小值),然后越来越小,从而使算法达到全局最小值。决定每次迭代的学习率的函数称为learning_schedule。如果学习速度降低得过快,你可能会陷入局部最小值,甚至在达到最小值的半路就停止了。如果学习速度降低得太慢,你可能在最小值的附近长时间摆动,同时如果过早停止训练,最终只会出现次优解。
下面的代码使用一个简单的learning_schedule来实现随机梯度下降,并绘制前10次迭代的拟合直线和最优直线(加粗实线)。结果如图2-10所示。
> # 随机梯度下降 > set.seed(100) > m <- dim(X_b)[1] > n_epochs <- 50 > t0 <- 5;t1 <- 50 # learning_schedule的超参数 > learning_schedule <- function(t){ + return(t0/(t+t1)) + } > theta <- rnorm(2) > > plot(X,y,col='blue',pch=16,main = "Stochastic Gradient Descent") > > for(epoch in 1:n_epochs){ + for (i in 1:m){ + if (epoch==1 & i <=10){ + y_predict <- theta[1] + theta[2]*X + lines(X,y_predict,col='green',lwd=1) + } + random_index <- sample(1:m,1) # 随机抽取一个样本 + xi <- X_b[random_index,] + yi <- y[random_index] + gradients <- 2*xi %*% ((xi %*% theta) - yi) + eta <- learning_schedule(epoch*m + i) + theta <- theta - eta * gradients + } + } > y_predict <- theta[1] + theta[2]*X > lines(X,y_predict,col='red',lwd=2) > text(2,10,pos = 2,font = 2, + labels = paste("y=",round(theta[1,1],2),"+", + abs(round(theta[2,1],2)),"*X"))
图2-10 随机梯度下降的前10次迭代
3. 小批量梯度下降算法
小批量梯度下降算法是对批量梯度下降及随机梯度下降的一个折中办法。其思想是:每次迭代使用batch_size个样本来对参数进行更新。小批量梯度下降融合了批量梯度下降和随机梯度下降的优点,具体如下:
- 通过矩阵运算,每次在一个batch上优化神经网络参数并不会比单个数据慢太多。
- 每次使用一个batch可以大大减少收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。
- 可实现并行化。