我实际上是想用一个线性模型来拟合一组’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
的形式,那么这段代码已经足够了。我实际上用它进行了几次测试,我定义了一条直线的方程并添加了一些高斯随机噪声(幅度=0.1,均值=0,标准差=1)。
然而,我要提到一个问题,如果你观察你的正弦数据,你定义的域是在[0,2*pi]
之间。正如你所见,有多个x
值被映射到相同但不同幅度的y
值。例如,在x = pi/2
时我们得到1,但在x = -3*pi/2
时我们得到-1。这种高变异性对线性回归不利,因此我的一个建议是限制你的域…比如[0, pi]
。另一个可能导致不收敛的原因是你选择的学习率太高。我建议将其设置为较低的值,如0.01
。正如你在评论中提到的,你已经发现了这一点!
然而,如果你想使用线性回归来拟合非线性数据,你将需要包含更高阶的项来解释变异性。因此,尝试包含二阶和/或三阶项。这可以通过简单地修改你的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
。因此,我们仍然可以在这里使用线性回归的梯度下降定义。
我还将控制随机生成种子(通过rng
),这样你可以生成我得到的相同结果:
clear all; close all;rng(123123);total_loss = [];m = 20;x = linspace(0,pi,m); %// Changey = sin(x);w = rand(1,4); %// Changerate = 0.01; %// Changex = [ones(1,length(x)); x; x.^2; x.^3]; %// Change - Second and third order termsfor 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;>> ww = 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');