与标准梯度下降相比,随机梯度下降如何节省时间?


15

标准梯度下降将为整个训练数据集计算梯度。

for i in range(nb_epochs):
  params_grad = evaluate_gradient(loss_function, data, params)
  params = params - learning_rate * params_grad

对于预定义的时期数,我们首先使用参数向量参数为整个数据集计算损失函数的梯度向量weights_grad。

相反,随机梯度下降为每个训练示例x(i)和标签y(i)执行参数更新。

for i in range(nb_epochs):
  np.random.shuffle(data)
  for example in data:
    params_grad = evaluate_gradient(loss_function, example, params)
    params = params - learning_rate * params_grad

SGD据说要快得多。但是,我不明白如果仍然对所有数据点进行循环,那么如何更快。GD中梯度的计算是否比分别为每个数据点计算GD慢得多?

代码来自这里


1
在第二种情况下,您将花费一小批时间来近似整个数据集。这通常效果很好。因此,令人困惑的部分可能是两种情况下的纪元数都相同,但是在第二种情况下您不需要那么多纪元。这两种方法的“超参数”将有所不同:GD nb_epochs!= SGD nb_epochs。出于参数目的,我们说:GD nb_epochs = SGD示例* nb_epochs,这样循环的总数是相同的,但是在SGD中梯度的计算要快得多。
尼玛·穆萨维

这个关于简历的答案是一个很好且相关的答案
朱巴卜

Answers:


23

简短答案:

  • 在许多大数据设置中(例如数百万个数据点),计算成本或梯度需要很长时间,因为我们需要对所有数据点求和。
  • 我们不需要精确的梯度来降低给定迭代的成本。梯度的一些近似值可以正常工作。
  • 随机梯度体面(SGD)仅使用一个数据点近似梯度。因此,与对所有数据求和相比,评估梯度可节省大量时间。
  • 通过“合理的”迭代次数(该数目可能是几千,并且远小于数据点的数目(可能是数百万)),随机梯度样例可能会得到一个合理的好的解决方案。

长答案:

我的记法遵循NG Andrew的机器学习Coursera课程。如果您不熟悉它,可以在这里查看讲座系列。

假设损失平方回归,成本函数为

Ĵθ=12一世=1HθX一世-ÿ一世2

梯度是

dĴθdθ=1一世=1HθX一世-ÿ一世X一世

对于梯度像样(GD),我们将参数更新为

θñËw=θØd-α1一世=1HθX一世-ÿ一世X一世

1/X一世ÿ一世节省了时间。

θñËw=θØd-αHθX一世-ÿ一世X一世

这就是我们节省时间的原因:

假设我们有10亿个数据点。

  • 在GD中,为了一次更新参数,我们需要具有(精确)梯度。这要求将这十亿个数据点加起来以执行1个更新。

  • 在SGD中,我们可以将其视为试图获得近似梯度而不是精确梯度。近似值来自一个数据点(或称为迷你批处理的几个数据点)。因此,在SGD中,我们可以非常快速地更新参数。另外,如果我们“循环”所有数据(称为一个时期),则实际上有10亿次更新。

诀窍在于,在SGD中,您不需要进行10亿次迭代/更新,而无需进行多次迭代/更新,比如说进行100万次迭代,就可以使用“足够好”的模型。


我正在编写代码来演示这个想法。我们首先通过正规方程求解线性系统,然后使用SGD对其进行求解。然后,我们根据参数值和最终目标函数值比较结果。为了稍后可视化,我们将有2个参数需要调整。

set.seed(0);n_data=1e3;n_feature=2;
A=matrix(runif(n_data*n_feature),ncol=n_feature)
b=runif(n_data)
res1=solve(t(A) %*% A, t(A) %*% b)

sq_loss<-function(A,b,x){
  e=A %*% x -b
  v=crossprod(e)
  return(v[1])
}

sq_loss_gr_approx<-function(A,b,x){
  # note, in GD, we need to sum over all data
  # here i is just one random index sample
  i=sample(1:n_data, 1)
  gr=2*(crossprod(A[i,],x)-b[i])*A[i,]
  return(gr)
}

x=runif(n_feature)
alpha=0.01
N_iter=300
loss=rep(0,N_iter)

for (i in 1:N_iter){
  x=x-alpha*sq_loss_gr_approx(A,b,x)
  loss[i]=sq_loss(A,b,x)
}

结果:

as.vector(res1)
[1] 0.4368427 0.3991028
x
[1] 0.3580121 0.4782659

124.1343123.0355

这是迭代中的成本函数值,我们可以看到它可以有效地减少损失,这说明了这一想法:我们可以使用数据子集来近似梯度并获得“足够好”的结果。

在此处输入图片说明

在此处输入图片说明

1000sq_loss_gr_approx3001000


我认为关于“速度”的争论更多是关于要收敛到局部最优值需要多少次操作/迭代?(而且随机梯度下降趋向于收敛到更好的最优值。)
GeoMatt22 '16

据我了解,在python代码中,我提供的“数据”变量是相同的。迷你批处理梯度体面的代码与SDG不同(恰好在那儿,他仅使用一小部分数据)。同样,在您提供的说明中,尽管我们摆脱了SDG的总和,但仍会为每个数据点计算更新。我仍然不明白如何在遍历每个数据点时更新参数比一次对所有数据点求和要快。
阿丽娜

@ GeoMatt22在我提供的链接中指出:“另一方面,这最终会使收敛趋于精确到最小,因为SGD会不断超调。” 意味着它不能收敛到更好的最优状态。还是我弄错了?
阿丽娜

@Tonja我不是专家,但是例如,这篇在深度学习中很有影响力的论文为随机梯度下降提供了“更快更可靠的训练”的论点。请注意,它不使用“原始”版本,而是使用各种曲率估计来设置(取决于坐标的)学习率。
GeoMatt22 '16

1
@Tonja,是的。梯度的任何“弱”近似都将起作用。您可以检查“梯度提升”,这是类似的想法。另一方面,我正在编写一些代码来演示这个想法。准备好后,我会发布它。
海涛杜
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.