线性回归的梯度下降不收敛
Gradient descent on linear regression not converging
我在 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;
}
我从不同地方获取了公式,包括:
- 优达学城深度学习基础纳米学位的练习
- 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] 范围
- 将输入和输出值归一化为 mean = 0 和 stddev = 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
)。
我想要的是让我的网络 "learn" 参数 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
但这似乎根本不正确。
我终于找到了问题所在,我正在回答我自己的问题,希望它也能帮助这方面的初学者。
首先,正如 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
疯狂跳跃以适应它。
最后,在您的网络训练时跟踪误差测量,这样您就可以对正在发生的事情有一些了解。这有助于识别简单过度拟合、大学习率和简单错误之间的区别。
我在 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;
}
我从不同地方获取了公式,包括:
- 优达学城深度学习基础纳米学位的练习
- 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] 范围
- 将输入和输出值归一化为 mean = 0 和 stddev = 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
)。
我想要的是让我的网络 "learn" 参数 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
但这似乎根本不正确。
我终于找到了问题所在,我正在回答我自己的问题,希望它也能帮助这方面的初学者。
首先,正如 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
疯狂跳跃以适应它。
最后,在您的网络训练时跟踪误差测量,这样您就可以对正在发生的事情有一些了解。这有助于识别简单过度拟合、大学习率和简单错误之间的区别。