我已经在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;
}
我从不同的地方拿了公式,包括:
我已经尝试过了:
y = x * 3
)y = x * 3 + 2
)仍然,权重(this.b
和this.m
)不接近任何数据值,它们会分散到无穷大。
我显然做错了什么,但我无法弄清楚它是什么。
更新:这里有更多的背景信息可能有助于弄清楚我的问题究竟是什么:
我试图通过线性回归伪神经元在线学习来模拟线性函数的简单近似。有了它,我的参数是:
this.m
,this.b
] x
,1
] z(x) = x
因此,我的网络将由y = this.m * x + this.b * 1
表示,模拟我想要近似的数据驱动函数(y = 3 * x
)。
我想要的是我的网络,以及#34;学习"参数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
但这看起来并不正确。
答案 0 :(得分:3)
我终于发现了什么是错的,我正在回答我自己的问题,希望它也能帮助这个领域的初学者。
首先,正如萨沙所说,我有一些理论上的误解。你的调整包括逐字输入值可能是正确的,但正如他所说,它应该已经是渐变的一部分。这一切都取决于您选择的错误功能。
您的错误函数将衡量您用什么来衡量您与实际价值的关系,并且该衡量需要保持一致。我使用均方误差作为测量工具(正如您在error
方法中看到的那样),但我在训练方法中使用纯绝对误差(y^ - y
)来测量错误。 您的渐变将取决于此错误函数的选择。因此,只选择一个并坚持使用它。
其次,简化您的假设以测试错误。在这种情况下,我非常清楚要近似的函数是什么(y = x * 3
)所以我手动将权重(this.b
和this.m
)设置为正确的值,我仍然看到错误分歧。这意味着在这种情况下权重初始化不是问题。
在搜索了一些之后,我的错误就在其他地方:将数据输入网络的函数错误地将3
硬编码值传递给预测输出(它在数组中使用了错误的索引),所以我看到的振荡是因为网络试图接近y = 0 * x + 3
(this.b = 3
和this.m = 0
),但由于学习率较小且误差函数导数误差,{ {1}}无法接近正确的值,使this.b
进行疯狂跳跃以适应它。
最后,跟踪网络训练时的错误测量,这样您就可以深入了解正在发生的事情。这有助于识别简单过度拟合,大学习率和简单的简单错误之间的差异。