线性回归上的梯度下降不收敛
Posted
技术标签:
【中文标题】线性回归上的梯度下降不收敛【英文标题】:Gradient descent on linear regression not converging 【发布时间】:2017-08-09 17:52:28 【问题描述】:我在 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 深度学习基础纳米学位的练习 Andrew Ng's course on Gradient Descent for Linear Regression (also here) Stanford's CS229 Lecture Notes this other PDF slides I found from Carnegie Mellon我已经试过了:
将输入和输出值标准化为 [-1, 1] 范围 将输入和输出值标准化为 [0, 1] 范围 将输入和输出值标准化为均值 = 0 和标准差 = 1 降低学习率(1e-7 和我一样低) 拥有一个完全没有偏差的线性数据集 (y = x * 3
)
具有非零偏差的线性数据集 (y = x * 3 + 2
)
使用介于 -1 和 1 之间的随机非零值初始化权重
不过,权重(this.b
和 this.m
)并未接近任何数据值,它们会发散到无穷大。
我显然做错了什么,但我不知道是什么。
更新:这里有一点上下文可能有助于弄清楚我的问题到底是什么:
我正在尝试通过线性回归伪神经元在线学习对线性函数的简单近似进行建模。有了这个,我的参数是:
权重:[this.m
, this.b
]
输入:[x
, 1
]
激活函数:身份函数z(x) = x
因此,我的网络将由y = this.m * x + this.b * 1
表示,模拟我想要近似的数据驱动函数(y = 3 * x
)。
我想要的是让我的网络“学习”参数this.m = 3
和this.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.m
和this.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
但这似乎根本不正确。
【问题讨论】:
这太宽泛了,因为有些代码没有上下文。但是这个this.m += this.learningRate * delta * input;
看起来并不眼熟:输入在这里无关。你的偏见处理看起来也很奇怪。由于我不熟悉 JS,我希望这些表达式是矢量化的?如果没有,请从头开始。
学习算法不是w += learningRate * gradient * input
吗?它总是作为y = m.x + b
对m
的导数的结果出现。 (要么这样,要么我完全误解了它。)
@sascha PS:实际上没有比这更多的代码了,但请告诉我,我可以包含哪些内容以使调查更容易?
No 输入错误。再次检查这些公式!输入的所有信息都已经在您的渐变中。但恐怕这里还有很多错误。你在做向量的数学运算吗? JS 默认会这样做吗?是的,偏见的事情,你从哪里得到这样做的想法?
@sascha 谢谢!我会检查输入的东西。不,这些都是标量。我正在研究一个简单直观的示例,以便以后在它之上构建。这就是偏见也被分开的原因。
【参考方案1】:
我终于找到了问题所在,我正在回答我自己的问题,希望它也能帮助这个领域的初学者。
首先,正如 Sascha 所说,我有一些理论上的误解。您的调整逐字包含输入值可能是正确的,但正如他所说,它应该已经是渐变的一部分。这一切都取决于您选择的误差函数。
您的误差函数将用来衡量您与实际值的偏差程度,并且该测量值需要保持一致。我使用均方误差作为测量工具(如您在我的 error
方法中所见),但我在训练方法中使用纯绝对误差 (y^ - y
) 来测量误差。 你的梯度将取决于这个误差函数的选择。所以只选择一个并坚持下去。
其次,简化您的假设以测试问题所在。在这种情况下,我非常清楚要逼近的函数是什么(y = x * 3
),所以我手动将权重(this.b
和this.m
)设置为正确的值,但我仍然看到错误发散。这意味着在这种情况下,权重初始化不是问题。
在搜索了更多之后,我的错误出现在其他地方:将数据输入网络的函数错误地将 3
硬编码值传递到预测输出(它在数组中使用了错误的索引),所以我看到的振荡是因为网络试图逼近y = 0 * x + 3
(this.b = 3
和this.m = 0
),但是由于学习率小和误差函数导数的误差,this.b
不会得到接近正确的值,使this.m
疯狂跳跃以适应它。
最后,在您的网络训练时跟踪误差测量,这样您就可以对正在发生的事情有所了解。这有助于识别简单过拟合、大学习率和简单错误之间的区别。
【讨论】:
以上是关于线性回归上的梯度下降不收敛的主要内容,如果未能解决你的问题,请参考以下文章