线性回归中的梯度下降出错
Gradient descent in linear regression goes wrong
其实我想用一个线性模型来拟合一组'sin'数据,但结果是损失函数在每次迭代中变大。我下面的代码有什么问题吗? (梯度下降法)
这是我在 Matlab 中的代码
m=20;
rate = 0.1;
x = linspace(0,2*pi,20);
x = [ones(1,length(x));x]
y = sin(x);
w = rand(1,2);
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2
total_loss = [total_loss loss];
**gradient = (h-y)*x'./m ;**
w = w - rate.*gradient;
end
这是我要拟合的数据
您的代码没有问题。以你现在的框架,如果你能以y = m*x + b
的形式定义数据,那么这段代码就绰绰有余了。实际上,我通过一些测试 运行 它定义了直线方程并向其添加一些高斯 运行dom 噪声(amplitude = 0.1,mean = 0,std.dev = 1)。
但是,我要向您提到的一个问题是,如果您查看正弦数据,您会在 [0,2*pi]
之间定义一个域。如您所见,您有多个 x
值映射到相同的 y
值但大小不同。例如,在 x = pi/2
处我们得到 1,但在 x = -3*pi/2
处我们得到 -1。这种高可变性对于线性回归来说不是好兆头,所以我的一个建议是限制你的域......所以像 [0, pi]
这样的东西。它可能不收敛的另一个原因是您选择的学习率太高。我会将其设置为较低的值,例如 0.01
。正如您在评论中提到的,您已经明白了!
但是,如果您想使用线性回归拟合非线性数据,则必须包括高阶项以说明可变性。因此,尝试包括二阶 and/or 三阶项。这可以简单地通过像这样修改 x
矩阵来完成:
x = [ones(1,length(x)); x; x.^2; x.^3];
如果你还记得,假设函数可以表示为线性项的总和:
h(x) = theta0 + theta1*x1 + theta2*x2 + ... + thetan*xn
在我们的例子中,每个 theta
项都会构建多项式的高阶项。 x2
将是 x^2
而 x3
将是 x^3
。因此,我们这里仍然可以使用梯度下降的定义来进行线性回归。
我还将控制 运行dom 生成种子(通过 rng
),以便您可以产生与我相同的结果:
clear all;
close all;
rng(123123);
total_loss = [];
m = 20;
x = linspace(0,pi,m); %// Change
y = sin(x);
w = rand(1,4); %// Change
rate = 0.01; %// Change
x = [ones(1,length(x)); x; x.^2; x.^3]; %// Change - Second and third order terms
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2;
total_loss = [total_loss loss];
% gradient is now in a different expression
gradient = (h-y)*x'./m ; % sum all in each iteration, it's a batch gradient
w = w - rate.*gradient;
end
如果我们尝试这样做,我们会得到 w
(您的参数):
>> format long g;
>> w
w =
Columns 1 through 3
0.128369521905694 0.819533906064327 -0.0944622478526915
Column 4
-0.0596638117151464
我最后的损失是:
loss =
0.00154350916582836
这意味着我们的直线方程是:
y = 0.12 + 0.819x - 0.094x^2 - 0.059x^3
如果我们用你的正弦数据绘制这条直线方程,这就是我们得到的:
xval = x(2,:);
plot(xval, y, xval, polyval(fliplr(w), xval))
legend('Original', 'Fitted');
其实我想用一个线性模型来拟合一组'sin'数据,但结果是损失函数在每次迭代中变大。我下面的代码有什么问题吗? (梯度下降法)
这是我在 Matlab 中的代码
m=20;
rate = 0.1;
x = linspace(0,2*pi,20);
x = [ones(1,length(x));x]
y = sin(x);
w = rand(1,2);
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2
total_loss = [total_loss loss];
**gradient = (h-y)*x'./m ;**
w = w - rate.*gradient;
end
这是我要拟合的数据
您的代码没有问题。以你现在的框架,如果你能以y = m*x + b
的形式定义数据,那么这段代码就绰绰有余了。实际上,我通过一些测试 运行 它定义了直线方程并向其添加一些高斯 运行dom 噪声(amplitude = 0.1,mean = 0,std.dev = 1)。
但是,我要向您提到的一个问题是,如果您查看正弦数据,您会在 [0,2*pi]
之间定义一个域。如您所见,您有多个 x
值映射到相同的 y
值但大小不同。例如,在 x = pi/2
处我们得到 1,但在 x = -3*pi/2
处我们得到 -1。这种高可变性对于线性回归来说不是好兆头,所以我的一个建议是限制你的域......所以像 [0, pi]
这样的东西。它可能不收敛的另一个原因是您选择的学习率太高。我会将其设置为较低的值,例如 0.01
。正如您在评论中提到的,您已经明白了!
但是,如果您想使用线性回归拟合非线性数据,则必须包括高阶项以说明可变性。因此,尝试包括二阶 and/or 三阶项。这可以简单地通过像这样修改 x
矩阵来完成:
x = [ones(1,length(x)); x; x.^2; x.^3];
如果你还记得,假设函数可以表示为线性项的总和:
h(x) = theta0 + theta1*x1 + theta2*x2 + ... + thetan*xn
在我们的例子中,每个 theta
项都会构建多项式的高阶项。 x2
将是 x^2
而 x3
将是 x^3
。因此,我们这里仍然可以使用梯度下降的定义来进行线性回归。
我还将控制 运行dom 生成种子(通过 rng
),以便您可以产生与我相同的结果:
clear all;
close all;
rng(123123);
total_loss = [];
m = 20;
x = linspace(0,pi,m); %// Change
y = sin(x);
w = rand(1,4); %// Change
rate = 0.01; %// Change
x = [ones(1,length(x)); x; x.^2; x.^3]; %// Change - Second and third order terms
for i=1:500
h = w*x;
loss = sum((h-y).^2)/m/2;
total_loss = [total_loss loss];
% gradient is now in a different expression
gradient = (h-y)*x'./m ; % sum all in each iteration, it's a batch gradient
w = w - rate.*gradient;
end
如果我们尝试这样做,我们会得到 w
(您的参数):
>> format long g;
>> w
w =
Columns 1 through 3
0.128369521905694 0.819533906064327 -0.0944622478526915
Column 4
-0.0596638117151464
我最后的损失是:
loss =
0.00154350916582836
这意味着我们的直线方程是:
y = 0.12 + 0.819x - 0.094x^2 - 0.059x^3
如果我们用你的正弦数据绘制这条直线方程,这就是我们得到的:
xval = x(2,:);
plot(xval, y, xval, polyval(fliplr(w), xval))
legend('Original', 'Fitted');