我正在为单变量线性回归编写一个小的 d3.js 可视化,其中两个参数是通过成本函数的梯度下降(误差平方和又名SSE)来学习的。
截至目前,我们可以看到最佳拟合线随着梯度下降迭代向参数“alpha”和“beta”的成本最小化选择进行调整,其中
y_i = alpha + beta * x_i
在 javascript 中,数据表示为具有“x”和“y”属性的对象数组。数据生成如下:
- 首先,X是从 'lowBound' 和 'upBound' 之间的均匀分布中采样的
- 接下来,根据数据生成过程对Y进行采样:y = 3x - 10 + error,
其中误差是从均值为零和方差errorVariance的正态分布中采样的。
我编写了一些 d3.js 代码来实现梯度下降,当我观看可视化时,似乎没有正确学习截距项。这是因为该算法经常调整斜率参数,但仅从其初始值(随机选择)非常轻微地调整截距参数。有三种可能:
- 我在数学(或数学的 javascript 表示)中犯了一个错误。
- 我在可视化中犯了一个错误(例如 d3 SVG 的东西)。
- 我没有犯错,SSE关于截距参数alpha的偏导数远小于斜率参数,因此梯度下降不会对alpha进行太多调整是有道理的。
我实在想不通答案是什么。因此,我将发布我的代码的简化设置,希望有人能够为我提供一些启发。您还可以在此处查看当前形式的可视化(并查看完整源代码)。我们现在只关心数学。如果有人希望我发布将数据连接到 svg 元素的代码,我很乐意这样做,但我认为问题更可能出在此处。
// Section 1: GENERATE DATA
var n = 60;
var upBound = 20;
var lowBound = -20;
var errorVariance = 6;
var data = []
// grab a random x value.
var randomX = function() {
return Math.random() * (upBound - lowBound) + lowBound;
}
// zero-mean normally distributed error.
var error = d3.random.normal(0, errorVariance);
// The following function defines the "data-generating-process":
// y = 3x - 10 + error
var dgp = function(x) {
return 3*x - 10 + error();
}
// Randomly generate data according to the dgp.
for (var i = 0; i < n; i++) {
var newX = randomX()
var newY = dgp(newX);
data.push({
"x": newX,
"y": newY
});
}
这一切都很好,花花公子。然后在第 2 节中,我提供了进行梯度下降的实用程序。
// define parameters for Gradient Descent
var learningRate = 0.00001;
var convThreshold = 0.005;
// Per Observation Cost Function
var obsCost = function(alpha, beta, data, i) {
return .5 * Math.pow(((alpha + beta * data[i]["x"]) - data[i]["y"]), 2);
}
// Sum of Squared Errors
var costFuncLR = function(alpha, beta, data) {
var sse = 0;
for (var j = 0; j < n; j++) {
sse += obsCost(alpha, beta, data, j);
}
return sse;
}
var obsErr = function(alpha, beta, data, i) {
return (alpha + data[i]["x"] * beta) - data[i]["y"];
}
// Partial derivative of cost w.r.t. alpha
var pJpAlpha = function(alpha, beta, data) {
var sum = 0;
for (var i = 0; i < n; i++) {
sum += obsErr(alpha, beta, data, i);
}
//return sum;
return Math.sqrt(2 * costFuncLR(alpha, beta, data));
}
// Partial derivative of cost w.r.t. beta
var pJpBeta = function(alpha, beta, data) {
var sum = 0
for (var j = 0; j < n; j++ ) {
sum += obsErr(alpha, beta, data, j) * data[j]["x"];
}
return sum;
}
// Performs one iteration of Gradient Descent.
var gradientDescentIter = function(data, alphaOld, betaOld, learningRate) {
var pjpa = pJpAlpha(alphaOld, betaOld, data)
var pjpb = pJpBeta(alphaOld, betaOld, data)
var temp0 = alphaOld - (learningRate * pjpa);
var temp1 = betaOld - (learningRate * pjpb);
var alphaNew = temp0;
var betaNew = temp1;
var out = [];
out.push(alphaNew);
out.push(betaNew);
console.log(costFuncLR(alphaNew, betaNew, data));
return out;
}
我提前感谢您的所有帮助。
有点不相关,我想通过参数空间中的等高线图或嵌入欧几里得 3 空间(z 轴是成本)中的表面来显示成本函数的水平集,并观察该空间中的参数变化为出色地。我找到了 mike bostock 关于如何使用等高线图的帖子,但是