【问题标题】:Stochastic Gradient Descent Convergence Criteria随机梯度下降收敛准则
【发布时间】:2015-05-27 03:48:35
【问题描述】:

目前我的 SGD 收敛标准检查 MSE 错误率是否在特定边界内。

def compute_mse(data, labels, weights):
    m = len(labels)
    hypothesis = np.dot(data,weights)
    sq_errors = (hypothesis - labels) ** 2
    mse = np.sum(sq_errors)/(2.0*m)
    return mse

cur_mse = 1.0
prev_mse = 100.0
m = len(labels)
while cur_mse/prev_mse < 0.99999:
    prev_mse = cur_mse

    for i in range(m):
        d = np.array(data[i])
        hypothesis = np.dot(d, weights)
        gradient = np.dot((labels[i] - hypothesis), d)/m
        weights = weights + (alpha * gradient)

    cur_mse = compute_mse(data, labels, weights)
    if cur_mse > prev_mse:
        return 

权重是更新的 w.r.t。到训练集中的单个数据点。

alpha 为 0.001,模型应该在几次迭代内收敛,但我没有收敛。这个收敛标准是不是太严格了?

【问题讨论】:

  • 可能是您没有正确计算梯度。我在任何地方都看不到梯度计算。
  • @iluengo 我已经添加了我用来执行此操作的代码。

标签: python linear-regression gradient-descent


【解决方案1】:

我会试着回答这个问题。首先,随机梯度下降的伪代码如下所示:

input: f(x), alpha, initial x (guess or random)
output: min_x f(x) # x that minimizes f(x)

while True:
    shuffle data # good practice, not completely needed
    for d in data:
        x -= alpha * grad(f(x)) # df/dx
    if <stopping criterion>:
        break

可以将其他regularization 参数添加到要最小化的函数中,例如l1 penalty 以避免过度拟合。

回到你的问题,看看你的数据和梯度的定义,看起来你想解决一个简单的线性方程组的形式:

Ax = b

产生客观函数:

f(x) = ||Ax - b||^2

随机梯度下降一次使用一行数据:

||A_i x - b||

其中|| o || 是欧几里得范数,_i 表示行的索引。

这里,A 是你的 datax 是你的 weightsb 是你的 labels

然后将函数的梯度计算为:

grad(f(x)) = 2 * A.T (Ax - b)

或者在随机梯度下降的情况下:

2 * A_i.T (A_i x - b)

.T 表示转置。

将所有内容放回您的代码中...首先我将设置一个合成数据:

A = np.random.randn(100, 2) # 100x2 data
x = np.random.randn(2, 1) # 2x1 weights
b = np.random.randint(0, 2, 100).reshape(100, 1) # 100x1 labels
b[b == 0] = -1 # labels in {-1, 1}

然后,定义参数:

alpha = 0.001
cur_mse = 100.
prev_mse = np.inf
it = 0
max_iter = 100
m = A.shape[0]
idx = range(m)

然后循环!

while cur_mse/prev_mse < 0.99999 and it < max_iter:
    prev_mse = cur_mse
    shuffle(idx)

    for i in idx:
        d = A[i:i+1]
        y = b[i:i+1]
        h = np.dot(d, x)
        dx = 2 * np.dot(d.T, (h - y))
        x -= (alpha * dx)

    cur_mse = np.mean((A.dot(x) - b)**2)
    if cur_mse > prev_mse:
        raise Exception("Not converging")
    it += 1

此代码与您的代码几乎相同,只是添加了一些内容:

  • 另一个基于迭代次数的停止标准(以避免在系统不收敛或收敛速度过慢时永远循环)

  • 重新定义渐变dx(仍然与您的相似)。您将符号倒置,因此权重更新为正 +,因为在我的示例中为负 -(这是有道理的,因为您在渐变中下降)。

  • datalabels 的索引。虽然data[i] 给出了一个大小为(2,) 的元组(在本例中为100x2 数据),但使用花哨的索引data[i:i+1] 将返回数据视图而不对其进行整形(例如形状为(1, 2)),因此将允许您执行正确的矩阵乘法。

您可以根据可接受的mse 错误添加第三个停止条件,即:if cur_mse &lt; 1e-3: break

这个算法,使用随机数据,对我来说在 20-40 次迭代中收敛(取决于生成的随机数据)。

所以...假设这是您要最小化的功能,如果此方法不适合您,则可能意味着您的系统未确定(您的训练数据少于功能,这意味着 A宽大于高)。

希望对你有帮助!

【讨论】:

  • @illuengo,谢谢,这很有帮助,但是数据和标签的索引会以任何方式影响收敛吗?另外,我的数据绝对不会比高宽。它由 4601 个点组成,每个点具有 57 个特征。
  • 嗯,它确实会影响因为我的数据你的算法不起作用,并在尝试计算梯度时告诉我一个错误ValueError: shapes (1,) and (2,) not aligned: 1 (dim 0) != 2 (dim 0)。那是因为我的datalabelsweights 都是二维矩阵。如果您将 weightslabels 设为 1D,那么您的代码可以正常工作(但我发现在计算代数运算时坚持矩阵表示法是一个很好的做法)。
  • 无论如何,您的代码有什么问题不是,您遇到的问题是:1) cur_mse 应该设置为较高的值(例如 100 或 100000),因为将被分配到第一条指令中的prev_mse。 2) prev_mse 应该设置为更高的值(如np.inf)。 3)最重要的是,你的梯度计算不正确,删除/ m并添加2 * (更快收敛)
  • 最后一点,shuffle 是从random 导入为from random import shuffle,以防您想将其添加到您的代码中。
  • 操作!忘了提你@IndecisiveCoder
猜你喜欢
  • 2017-08-03
  • 2015-02-18
  • 2019-01-31
  • 1970-01-01
  • 2013-06-21
  • 1970-01-01
  • 2021-11-16
  • 2020-04-28
  • 1970-01-01
相关资源
最近更新 更多