机器学习-使用批量梯度下降进行线性回归

10

我正在尝试在具有单个特征和多个训练样例(m)的数据集上实现批量梯度下降。

当我尝试使用正规方程时,我得到了正确的答案,但使用以下MATLAB代码执行批量梯度下降时得到了错误的答案。

 function [theta] = gradientDescent(X, y, theta, alpha, iterations)
      m = length(y);
      delta=zeros(2,1);
      for iter =1:1:iterations
          for i=1:1:m
              delta(1,1)= delta(1,1)+( X(i,:)*theta - y(i,1))  ;
              delta(2,1)=delta(2,1)+ (( X(i,:)*theta - y(i,1))*X(i,2)) ;
          end
          theta= theta-( delta*(alpha/m) );
        computeCost(X,y,theta)
      end
end

y 是目标值向量,X 是一个矩阵,第一列是全为1的向量,第二列是变量的值。

我使用向量化实现了这个过程,即

theta = theta - (alpha/m)*delta

... 其中 delta 是一个由零初始化的2元列向量。

代价函数 J(Theta)1/(2m)*(i从1到m求和 [(h(theta)-y)^2])


考虑将标签[tag:batch-file]更改为[tag:batch-processing]。 - aschipfl
1
@aschipfl - 好建议。然而,这篇文章与批处理或任何与文件或数据相关的批处理无关。在这个上下文中,它被等同于机器学习中的一种技术,因此我已经删除了标签,因为它不合适。可能是原帖的错误标记。感谢您的评论! - rayryeng
1
抱歉,我打字太快了,没有仔细阅读问题...感谢您的纠正! - aschipfl
1个回答

28
错误非常简单。您的delta声明应该在第一个for循环内部。每次累积训练样本和输出之间的加权差异时,都应该从头开始累积。
这样做的问题是,您正在累积来自上一次迭代的错误,这将考虑到上一次学习版本的theta的错误,这是不正确的。您必须将其放在第一个for循环的开头。
此外,您似乎有一个多余的computeCost调用。我假设这会计算给定当前参数的每次迭代的成本函数,因此我将创建一个名为cost的新输出数组,以显示每次迭代中的成本。我还将调用此函数并将其分配给该数组中相应的元素。
function [theta, costs] = gradientDescent(X, y, theta, alpha, iterations)
    m = length(y);
    costs = zeros(m,1); %// New
%    delta=zeros(2,1); %// Remove
    for iter =1:1:iterations
    delta=zeros(2,1); %// Place here
   for i=1:1:m
       delta(1,1)= delta(1,1)+( X(i,:)*theta - y(i,1))  ;
       delta(2,1)=delta(2,1)+ (( X(i,:)*theta - y(i,1))*X(i,2)) ;
   end
    theta= theta-( delta*(alpha/m) );
   costs(iter) = computeCost(X,y,theta); %// New
end
end

关于正确向量化的说明

就个人而言,我不认为这个实现是完全向量化的。您可以通过使用向量化操作来消除第二个for循环。在我们这样做之前,让我介绍一些理论,以便我们能够达成共识。您在这里使用梯度下降法进行线性回归。我们想要寻找最佳参数theta,这些参数是我们的线性回归系数,旨在最小化此成本函数:

enter image description here

"

m代表我们拥有的训练样本数量,x^{i}对应第i个训练样本,y^{i}对应第i个训练样本的真实值。h是我们的假设,它被表示为:

"

enter image description here

请注意,在二维线性回归的背景下,我们只需要计算两个值的θ来进行计算 - 截距项和斜率。
我们可以最小化代价函数J以确定最佳回归系数,从而给出最小化训练集误差的最佳预测。具体而言,从一些初始θ参数开始...通常是一个零向量,我们在迭代次数上迭代从1到我们认为适合的次数,并且在每次迭代时,我们通过以下关系更新我们的θ参数:

enter image description here

对于我们想要更新的每个参数,您需要确定成本函数相对于每个变量的梯度,并在当前状态下评估该值。如果使用微积分来计算,我们得到:

enter image description here

如果你不清楚这个推导是怎么得到的,我建议你看一下这篇很好的数学堆栈交换文章:

https://math.stackexchange.com/questions/70728/partial-derivative-in-gradient-descent-for-two-variables

现在...我们如何将其应用于当前问题呢?具体而言,您可以分析所有样本并一次性轻松计算delta的条目。我的意思是,您只需执行以下操作:
function [theta, costs] = gradientDescent(X, y, theta, alpha, iterations)
    m = length(y);
    costs = zeros(m,1);
    for iter = 1 : iterations
        delta1 = theta(1) - (alpha/m)*(sum((theta(1)*X(:,1) + theta(2)*X(:,2) - y).*X(:,1)));
        delta2 = theta(2) - (alpha/m)*(sum((theta(1)*X(:,1) + theta(2)*X(:,2) - y).*X(:,2)));

        theta = [delta1; delta2];
        costs(iter) = computeCost(X,y,theta);
    end
end

对于 delta(1)delta(2) 的操作可以在单个语句中进行完全向量化。对于每个样本i1, 2, ..., m,你正在做theta^{T}*X^{i}。您可以方便地将其放入单个sum语句中。

我们甚至可以进一步用纯矩阵运算替换它。首先,您可以使用矩阵乘法非常快速地计算每个输入样本X^{i}theta^{T}*X^{i}。假设如果:

enter image description here

这里,X 是我们的数据矩阵,由 m 行组成,对应于 m 个训练样本和 n 列对应于 n 个特征。同样地,theta 是我们从梯度下降中学习到的权重向量,有 n+1 个特征,包括截距项。
如果我们计算 X*theta,我们会得到:

enter image description here

您可以看到,我们已经为每个样本计算了假设,并将每个样本的假设放入向量中。该向量的每个元素是第i个训练样本的假设。现在,请回忆一下梯度下降中每个参数的梯度术语:

enter image description here

我们希望一次性实现您学习向量中所有参数的操作,将其放入向量中得到:

enter image description here

最终:

enter image description here

因此,我们知道y已经是长度为m的向量,所以我们可以在每次迭代中非常简洁地计算梯度下降,方法如下:
theta = theta - (alpha/m)*X'*(X*theta - y);

...所以您的代码现在只是:

function [theta, costs] = gradientDescent(X, y, theta, alpha, iterations)
    m = length(y);
    costs = zeros(m, 1);
    for iter = 1 : iterations
        theta = theta - (alpha/m)*X'*(X*theta - y);
        costs(iter) = computeCost(X,y,theta);
    end
end

好的发现!非常感谢...这让我熬了很长时间。 - Sridhar Thiagarajan
@SridharThiagarajan - 没问题 :) 请看我的编辑,了解如何更加向量化地使其工作。 - rayryeng
1
@IvanRodriguezTorres 物理上将 X 的转置和假设值与真实值之间的差异向量中的所有术语写出来。将此矩阵和向量相乘,您会发现这些表达式是等价的。 - rayryeng
1
@BhoomtawathPlinsut 啊,那是凭直觉得出来的。例如,注意到梯度项只是点积。梯度中的每一项都是与假设值和真实值之间的差向量进行点积。此外,对于每个术语,我们可以看到我们正在将此差异向量与所有示例的每个特征作为向量进行点积。我们可以通过转置训练示例矩阵 X 并使用该差异向量的行与该矩阵的行进行点积来同时执行所有功能。这并没有写出来,只是凭直觉。 - rayryeng
1
@rayryeng 点赞。感谢您的澄清。 - Bhoomtawath Plinsut
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接