2017-03-18 131 views
0

我已经实现了一个非常简单的线性回归与JavaScript的梯度下降算法,但咨询多个来源和尝试几件事情后,我不能让它收敛。线性回归渐变下降不收敛

数据绝对是线性的,它只是数字0到30作为输入,其中x * 3作为它们的正确输出来学习。

这是背后的梯度下降的逻辑:

train(input, output) { 
    const predictedOutput = this.predict(input); 
    const delta = output - predictedOutput; 

    this.m += this.learningRate * delta * input; 
    this.b += this.learningRate * delta; 
} 

predict(x) { 
    return x * this.m + this.b; 
} 

我从不同的地方公式,其中包括:从Udacity的深度学习基础

我已经尝试:

  • 正火输入和输出值到[-1,1]的范围内
  • 正火输入和输出值的[0,1 ]范围
  • 正常化输入和输出值的平均值= 0和stddev = 1
  • 降低学习率(1e-7与我去的一样低)
  • 具有一种具有线性数据具有非零偏压(y = x * 3 + 2
  • 初始化-1,1
  • 之间的随机的非零值的权重设置一个线性数据在所有( y = x * 3
  • 没有偏压设定

仍然,权重(this.bthis.m)不接近任何数据值,并且它们分叉到无穷大。

我明显做错了什么,但我无法弄清楚它是什么。


更新:这里有一点点的上下文,可以帮助找出我的问题是,究竟是什么:

我想要一个简单的近似模型的线性函数,通过在线学习线性回归伪神经元。就这样,我的参数是:

  • 权重:this.mthis.b]
  • 输入:[x1]
  • 激活函数:恒等函数z(x) = x

这样,我的净将用y = this.m * x + this.b * 1表示,模拟我想要近似的数据驱动函数(y = 3 * x)。

我想要的是我的网络“学习”参数this.m = 3this.b = 0,但它似乎卡住了当地最低标准。

我的误差函数是均方误差:

error(allInputs, allOutputs) { 
    let error = 0; 
    for (let i = 0; i < allInputs.length; i++) { 
    const x = allInputs[i]; 
    const y = allOutputs[i]; 
    const predictedOutput = this.predict(x); 
    const delta = y - predictedOutput; 

    error += delta * delta; 
    } 

    return error/allInputs.length; 
} 

我更新我的权重逻辑将(据有关人士透露,到目前为止我已经签)wi -= alpha * dError/dwi

为求简单,我会打电话给我的权重this.mthis.b,所以我们可以将其与我的JavaScript代码关联起来。我还会拨打y^预测值。

从这里:

error = y - y^ 
     = y - this.m * x + this.b 

dError/dm = -x 
dError/db = 1 

因此,将其应用于重量校正逻辑:

this.m += alpha * x 
this.b -= alpha * 1 

但这似乎正确根本不会。

+0

这是太宽泛,因为有一些没有上下文的代码。但是这个'''this.m + = this.learningRate * delta * input;'''看起来并不熟悉:输入在这里没有任何关系。你的偏见处理也看起来很奇怪。由于我不熟悉JS,我预计这些表达式是矢量化的?如果不是,从头开始。 – sascha

+0

不是学习算法'w + = learningRate * gradient * input'?它总是作为'y = m.x + b'相对于'm'的导数的结果出现。 (或者,或者我完全误解了它。) – Alpha

+0

@sascha PS:没有比这更多的代码,但是让我知道,我可以包括哪些内容,这将使得这更容易调查? – Alpha

回答

1

我终于发现有什么问题了,我正在回答我自己的问题,希望它能帮助这个领域的初学者。

首先,正如Sascha所说,我有一些理论上的误解。您的调整可能包含逐字输入值,但如他所说,它应该已经是梯度的一部分。这完全取决于您对错误功能的选择。

您的错误函数将用于衡量您用什么来衡量您离真实值的距离,并且该度量需要保持一致。我使用均方误差作为测量工具(正如您可以在我的error方法中看到的那样),但我在训练方法内部使用纯绝对误差(y^ - y)来测量误差。 您的渐变将取决于此错误功能的选择。所以选择一个并坚持下去。

二,简化你的假设,以便测试什么是错的。在这种情况下,我有一个非常好的主意是什么函数来近似(y = x * 3),所以我手动设置权重(this.bthis.m)为正确的值,我仍然看到了错误分歧。这意味着在这种情况下重量初始化不是问题。

经过多次搜索后,我的错误还在其他地方:将数据提供给网络的函数错误地将硬编码值传递给了预测输出(它在阵列中使用了错误的索引),因此振荡我看到的原因是网络试图接近y = 0 * x + 3this.b = 3this.m = 0),但由于学习率和误差函数导数的误差,this.b不会接近正确的值,使得this.m作出野生跳跃来适应它。

最后,跟踪您的网络火车错误测量,所以你可以有一些洞察到发生了什么事情。这对于识别简单的过度配合,大的学习率和简单的简单错误之间的差异有很大帮助。