基于向量运算的随机梯度下降?


10

让我们假设我想使用具有N个样本的数据集来训练随机梯度下降回归算法。由于数据集的大小是固定的,因此我将重复使用数据T次。在每次迭代或“纪元”时,在对整个训练集进行随机重新排序后,我都会使用每个训练样本一次。

我的实现基于Python和Numpy。因此,使用向量运算可以显着减少计算时间。提出批量梯度下降的矢量化实现非常简单。但是,在随机梯度下降的情况下,我无法弄清楚如何避免在每个时期迭代所有样本的外部循环。

有人知道随机梯度下降的任何矢量化实现吗?

编辑:有人问我,如果我的数据集大小固定,为什么要使用在线梯度下降。

从[1]中可以看出,在线梯度下降的收敛速度比批量梯度下降的慢,且经验成本最低。但是,它收敛得更快,达到了预期成本的最小值,从而衡量了通用性能。我想通过交叉验证来测试这些理论结果对我的特定问题的影响。没有矢量化的实现,我的在线梯度下降代码要比批处理梯度下降代码慢得多。这显着增加了完成交叉验证过程所需的时间。

编辑:根据ffriend的要求,我在这里包括了我的在线梯度下降实现的伪代码。我正在解决回归问题。

Method: on-line gradient descent (regression)
Input: X (nxp matrix; each line contains a training sample, represented as a length-p vector), Y (length-n vector; output of the training samples)
Output: A (length-p+1 vector of coefficients)

Initialize coefficients (assign value 0 to all coefficients)
Calculate outputs F
prev_error = inf
error = sum((F-Y)^2)/n
it = 0
while abs(error - prev_error)>ERROR_THRESHOLD and it<=MAX_ITERATIONS:
    Randomly shuffle training samples
    for each training sample i:
        Compute error for training sample i
        Update coefficients based on the error above
    prev_error = error
    Calculate outputs F
    error = sum((F-Y)^2)/n
    it = it + 1

[1]“大规模在线学习”,L。Bottou,Y。Le Cunn,NIPS 2003。


2
将数据集拆分为多个小批,然后将模型依次拟合到每个小批中。
ffriend

谢谢@ffriend。但是,那不是纯粹的在线实现。
Pablo Suau 2014年

1
如果您的数据集固定,那么使用“纯在线”实现的原因是什么?SGD仅表示您不需要一次遍历整个数据集,而是可以将其拆分为任意数量的片段(迷你批量)并对其进行逐一处理。大小为1的小批量仅在您具有连续且可能是无穷无尽的数据源(例如,twitter feed)并且想要在每次新观察后更新模型时才有意义。但这是非常罕见的情况,而且绝对不是固定数据集的情况。
ffriend

很抱歉,我的回复很晚。请检查我添加到原始问题的文本。
Pablo Suau 2014年

1
你能展示你的实现吗?我看到了误解,但是如果没有代码示例,将很难解释。
ffriend

Answers:


10

首先,“ sample”一词通常用于描述总体子集,因此我将把与“ example”相同的事物称为“示例”。

由于以下原因,您的SGD实现速度很慢:

for each training example i:

在这里,您每次模型参数的更新都明确地使用了一个示例。根据定义,矢量化是一种将一个元素上的操作转换为此类元素的矢量上的操作的技术。因此,不能,您不能一一处理示例,而仍然使用矢量化。

但是,您可以使用mini-batch近似真实的SGD 。迷你批次是原始数据集的一小部分(例如100个示例)。您可以基于微型批处理来计算错误和参数更新,但是仍然需要对它们中的许多进行迭代,而无需进行全局优化,从而使过程变得随机。因此,要使您的实施更快,只需将前一行更改为:

batches = split dataset into mini-batches
for batch in batches: 

并从批处理而不是从单个示例计算错误。

尽管很明显,但我还应该在每个示例级别提及向量化。也就是说,而不是像这样的东西:

theta = np.array([...])  # parameter vector
x = np.array([...])      # example
y = 0                    # predicted response
for i in range(len(example)):
    y += x[i] * theta[i]
error = (true_y - y) ** 2  # true_y - true value of response

您绝对应该这样做:

error = (true_y - sum(np.dot(x, theta))) ** 2

同样,对于小批量生产,它也易于推广:

true_y = np.array([...])     # vector of response values
X = np.array([[...], [...]]) # mini-batch
errors = true_y - sum(np.dot(X, theta), 1)
error = sum(e ** 2 for e in errors)

1
我认为这是要走的路。选择大小合适的迷你批处理实际上可以比批处理或在线版本收敛更快(前者每组仅更新一次权重,而后者无法向量化,而且更经常地进行额外的权重更新)
Neil Slater

谢谢你俩。道歉之前曾顽固拒绝小批量生产,但我不确定这种方法对收敛速度的影响。尼尔,您的肯定是来自您自己的经验,还是有任何理论/经验的公开结果?
Pablo Suau 2014年

1
@PabloSuau您可以在第10周的Coursera上查看Andrew Ng的机器学习课程,他解释了为什么收敛速度可以比SGD和批处理GD都快。更准确地说:它应始终与SGD一样快,但有时在实践中甚至应该更快。
华丽的

1

查看scikit SGD分类器的partial_fit方法。您可以控制调用它的方式:您可以一次传递一个实例来实现“真正的”在线学习,或者如果阵列中的所有数据都可用,则可以将实例批量批处理。如果是这样,则可以对阵列进行切片以提供微型批次。

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.