0 前言
梯度下降法的使用,一个非常重要的步骤是:我们要求出定义的损失函数某一点上对应的梯度是什么。在复杂函数的情况下,求导得到梯度并不容易。如果我们梯度的计算错误了,在后续的程序中也不会报错。那么我们如何去发现这个错误呢?
介绍一种简单的方法,能够对梯度下降法中求梯度的公式推导进行调试。
1 调试原理
以一维为例,求某一点(红色)相应的梯度值(导数),就是曲线在这个点上切线的斜率。我们可以使用距离该点左右两侧的两个蓝色点的连线的斜率,作为红点处切线斜率。
15754467107669.jpg这样就可以将近似地得到点的梯度为,两个蓝点纵向坐标差除以横向坐标差:
推广到多维函数中,对于点,则对损失函数进行求导,为:。
在计算时,要分别计算每个维度上的点,以维度为例,得到在该维度上距离该店非常距离非常近的左右两点:、。这样可以得到:。
对于每一个维度,都按照上述的方法计算梯度,最后再组合起来,得到最终的梯度。但是这样的求法,从数学上来看比较直观。但是因为每个维度上都要求两次带入,因此时间复杂度变高了。
这种方法作为一个调试的手段,在还未完成时,可以使用小数据量,进行计算,得到最终结果。然后再通过推导公式的方式得到的梯度结果,是否和其相同。
2 使用展示
下面我们在一组数据上,分别使用数学公式法和调试法来计算梯度,主要观察其结果与所消耗的时间。
# 首先定义损失函数
def J(theta, X_b, y):
try:
return np.sum((y - X_b.dot(theta))**2) / len(X_b)
except:
return float('inf')
# 使用数学公式推导的方式,求损失函数J在参数theta上的梯度
def dJ_math(theta, X_b, y):
return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)
# 使用上文提到的梯度调试的方法
def dJ_debug(theta, X_b, y, epsilon=0.01):
# 先创建一个与参数组等长的向量
res = np.empty(len(theta))
# 对于每个梯度,求值
for i in range(len(theta)):
theta_1 = theta.copy()
theta_1[i] += epsilon
theta_2 = theta.copy()
theta_2[i] -= epsilon
res[i] = (J(theta_1, X_b, y) - J(theta_2, X_b, y)) / (2 * epsilon)
return res
# 梯度下降的过程
def gradient_descent(dJ, X_b, y, initial_theta, eta, n_iters = 1e4, epsilon=1e-8):
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - eta * gradient
if(abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
cur_iter += 1
return theta
然后我们先调用函数,看看正确的梯度结果是什么。
X_b = np.hstack([np.ones((len(X), 1)), X])
initial_theta = np.zeros(X_b.shape[1])
eta = 0.01
%time theta = gradient_descent(dJ_debug, X_b, y, initial_theta, eta)
theta
15755568341916.jpg
然后我们再调用,来检验我们的求导公式对不对:
%time theta = gradient_descent(dJ_math, X_b, y, initial_theta, eta)
theta
15755568929237.jpg
最终发现,我们求得的梯度公式得到的答案是正确的。
但是观察到,使用debug的方式要比用求导公式的执行时间慢很多,如果在真实数据集上,可能会差的更多了。因此我们在求梯度的时候,可以用这种通用的debug方式先在小数据集上对求导公式进行检验。
3 对梯度下降法的总结
在之前的系列文章中,我们介绍了两种梯度下降法:
- 批量梯度下降法 Batch Gradient Descent
- 随机梯度下降法 Stochastic Gradient Descent
批量梯度下降法每次对所有样本都看一遍,缺点是慢,缺点是稳定。随机梯度下降法每次随机看一个,优点是快,缺点是不稳定。
其实还有一种中和二者优缺点的方法小批量梯度下降法 MBGD(Mini-Batch Gradient Descent):在每次更新时用b个样本,其实批量的梯度下降就是一种折中的方法,用一些小样本来近似全部。优点:减少了计算的开销量,降低了随机性。
在机器学习领域,“随机”具有非常大的意义,因为计算速度很快。对于复杂的损失函数来说,随机可以跳出局部最优解,并且有更快的速度。
网友评论