[UFLDL] Exercise 1C:Softmax Regression

本文详细解析了多分类softmax回归的目标函数及梯度计算方法,通过向量化代码实现,介绍了如何利用矩阵运算高效计算目标函数值及其梯度,适用于大规模数据集的机器学习任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码来源: UFLDL-Tutorial-notes-code,感谢其分享!

本人工作只是对代码进行讲解,如有改动会单独指出。

任务

完成多分类softmax的目标函数 J ( θ ) J(\theta) J(θ)和梯度 ∇ θ J ( θ ) \nabla_{\theta}J(\theta) θJ(θ)的计算。

代码

softmax_regression_vec.m 代码如下:

function [f,g] = softmax_regression(theta, X,y)
  %
  % Arguments:
  %   theta - A vector containing the parameter values to optimize.
  %       In minFunc, theta is reshaped to a long vector.  So we need to
  %       resize it to an n-by-(num_classes-1) matrix.
  %       Recall that we assume theta(:,num_classes) = 0.
  %
  %   X - The examples stored in a matrix.  
  %       X(i,j) is the i'th coordinate of the j'th example.
  %   y - The label for each example.  y(j) is the j'th example's label.
  %
  m=size(X,2);
  n=size(X,1);

  % theta is a vector;  need to reshape to n x num_classes.
  theta=reshape(theta, n, []);
  num_classes=size(theta,2)+1;
  
  % initialize objective value and gradient.
  f = 0;
  g = zeros(size(theta));

  %
  % TODO:  Compute the softmax objective function and gradient using vectorized code.
  %        Store the objective function value in 'f', and the gradient in 'g'.
  %        Before returning g, make sure you form it back into a vector with g=g(:);
  %
%%% YOUR CODE HERE %%%

  A = exp([theta' * X; zeros(1,m)]);        % 计算θ^T * X
  B = bsxfun(@rdivide, A, sum(A));          % 对θ^T * X 归一化
  C = log(B);                               % 取对数
  I = sub2ind(size(C),y,1:size(C,2));       % 获取label对应的位置的值
  f = (-1) * sum(C(I));                     % 计算目标函数
  
  % calculate g 
  Y = repmat(y',1,num_classes);
  for i=1:num_classes
      Y(Y(:,i)~=i,i) = 0;       % 第i列中,仅标签为i的样本对应的位置不为0。
  end
  Y(Y~=0)=1;                % 第i列非零元所在的位置,表示标签为i的元素的索引
  disp(size(Y(:,1:(size(Y,2)-1))))
  disp(size(B(1:(size(B,1)-1),:)'))
  g = (-1) * X * (Y(:,1:(size(Y,2)-1))-B(1:(size(B,1)-1),:)');
  
  %%% 别人的写法,两种写法效果一样,主要是稀疏矩阵生成不一样一点,他的速度略快%%
  %%% 因为这里num_classes还很小,我耗时0.014272秒,他的耗时0.014249秒 %%%
%   h = theta'*X;%h(k,i)第k个theta,第i个样本
%   a = exp(h);
%   a = [a;ones(1,size(a,2))];%加1行
%   p = bsxfun(@rdivide,a,sum(a));
%   c = log2(p);
%   i = sub2ind(size(c), y,[1:size(c,2)]);
%   values = c(i);
%   f = -sum(values);

%   d = full(sparse(1:m,y,1));
%   d = d(:,1:(size(d,2)-1));%减1列
%   p = p(1:(size(p,1)-1),:);%减1行
%   g = X*(p'.-d);  

  g=g(:); % make gradient a vector for minFunc

思路

主要需要的就是这两个公式:

  • 损失函数 J ( θ ) J(\theta) J(θ)
    J ( θ ) = − [ ∑ i = 1 m ∑ k = 1 K 1 { y ( i ) = k } log ⁡ exp ⁡ ( θ ( k ) ⊤ x ( i ) ) ∑ j = 1 K exp ⁡ ( θ ( j ) ⊤ x ( i ) ) ] = − [ ∑ i = 1 m ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) + y ( i ) log ⁡ h θ ( x ( i ) ) ] = − [ ∑ i = 1 m ∑ k = 0 1 1 { y ( i ) = k } log ⁡ P ( y ( i ) = k ∣ x ( i ) ; θ ) ] \begin{aligned} J(\theta) &= - \left[ \sum_{i=1}^{m} \sum_{k=1}^{K} 1\left\{y^{(i)} = k\right\} \log \frac{\exp(\theta^{(k)\top} x^{(i)})}{\sum_{j=1}^K \exp(\theta^{(j)\top} x^{(i)})}\right] \\ &= - \left[ \sum_{i=1}^m (1-y^{(i)}) \log (1-h_\theta(x^{(i)})) + y^{(i)} \log h_\theta(x^{(i)}) \right] \\ &= - \left[ \sum_{i=1}^{m} \sum_{k=0}^{1} 1\left\{y^{(i)} = k\right\} \log P(y^{(i)} = k | x^{(i)} ; \theta) \right] \end{aligned} J(θ)=[i=1mk=1K1{y(i)=k}logj=1Kexp(θ(j)x(i))exp(θ(k)x(i))]=[i=1m(1y(i))log(1hθ(x(i)))+y(i)loghθ(x(i))]=[i=1mk=011{y(i)=k}logP(y(i)=kx(i);θ)]

  • 梯度 ∇ θ J ( θ ) \nabla_{\theta}J(\theta) θJ(θ)
    ∇ θ ( k ) J ( θ ) = − ∑ i = 1 m [ x ( i ) ( 1 { y ( i ) = k } − P ( y ( i ) = k ∣ x ( i ) ; θ ) ) ] \begin{aligned} \nabla_{\theta^{(k)}} J(\theta) = - \sum_{i=1}^{m}{ \left[ x^{(i)} \left( 1\{ y^{(i)} = k\} - P(y^{(i)} = k | x^{(i)}; \theta) \right) \right] } \end{aligned} θ(k)J(θ)=i=1m[x(i)(1{y(i)=k}P(y(i)=kx(i);θ))]

但是有一点奇怪的地方:

在所给的框架下, θ \theta θ 的维度是 n × ( K − 1 ) n×(K-1) n×(K1),其中 K K K 为类别数,此处为10。

这样,我们的预测值 θ T X \theta^TX θTX 的维度就变成了 ( K − 1 ) × m (K-1)×m (K1)×m,而不是 K × m K×m K×m,我个人认为还是挺奇怪的。

解决办法就是增加一个与 X X X 无关的偏置项(同样也不可优化),附加在 θ T X \theta^TX θTX 之后,从而将维度变为 K × m K×m K×m

这样 n × ( K − 1 ) n×(K-1) n×(K1) 维的参数确实也可以完成 K K K 类的分类,只不过有点难以理解。因为当 θ \theta θ 的每个元素都很小时,则偏置项相对较大,则被分类为第 K K K 类。

理解了这个之后,下面就很容易懂了。

解析

计算目标函数 J ( θ ) J(\theta) J(θ)
A = exp([theta' * X; zeros(1,m)]);        % 计算θ^T * X
B = bsxfun(@rdivide, A, sum(A));          % 对θ^T * X 归一化
C = log(B);                               % 取对数
I = sub2ind(size(C),y,1:size(C,2));       % 获取label对应的位置的值
f = (-1) * sum(C(I));                     % 计算目标函数

这部分对应目标函数的公式:
J ( θ ) = − [ ∑ i = 1 m ∑ k = 1 K 1 { y ( i ) = k } log ⁡ exp ⁡ ( θ ( k ) ⊤ x ( i ) ) ∑ j = 1 K exp ⁡ ( θ ( j ) ⊤ x ( i ) ) ] = − [ ∑ i = 1 m ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) + y ( i ) log ⁡ h θ ( x ( i ) ) ] = − [ ∑ i = 1 m ∑ k = 0 1 1 { y ( i ) = k } log ⁡ P ( y ( i ) = k ∣ x ( i ) ; θ ) ] \begin{aligned} J(\theta) &= - \left[ \sum_{i=1}^{m} \sum_{k=1}^{K} 1\left\{y^{(i)} = k\right\} \log \frac{\exp(\theta^{(k)\top} x^{(i)})}{\sum_{j=1}^K \exp(\theta^{(j)\top} x^{(i)})}\right] \\ &= - \left[ \sum_{i=1}^m (1-y^{(i)}) \log (1-h_\theta(x^{(i)})) + y^{(i)} \log h_\theta(x^{(i)}) \right] \\ &= - \left[ \sum_{i=1}^{m} \sum_{k=0}^{1} 1\left\{y^{(i)} = k\right\} \log P(y^{(i)} = k | x^{(i)} ; \theta) \right] \end{aligned} J(θ)=[i=1mk=1K1{y(i)=k}logj=1Kexp(θ(j)x(i))exp(θ(k)x(i))]=[i=1m(1y(i))log(1hθ(x(i)))+y(i)loghθ(x(i))]=[i=1mk=011{y(i)=k}logP(y(i)=kx(i);θ)]
说明比较重要的几点:

  • A = exp([theta' * X; zeros(1,m)]);是计算 exp ⁡ ( θ ⊤ X ) \exp(\theta^\top X) exp(θX),其中zeros(1,m)就是上面提到的偏置项。

    A的维度是 [ ( K − 1 ) × n ] × [ n × m ] + 1 × m = [ ( K − 1 ) × m ] + [ 1 × m ] = K × m [(K-1)×n]×[n×m] + 1×m = [(K-1)×m] + [1×m] = K×m [(K1)×n]×[n×m]+1×m=[(K1)×m]+[1×m]=K×m,具体在此处为10×60000。

  • I = sub2ind(size(C),y,1:size(C,2));f = (-1) * sum(C(I)); 完成的实际上是 1 { y ( i ) = k } 1\left\{y^{(i)} = k\right\} 1{y(i)=k} 这个函数。即筛选出预测类别中正确类别的概率,来计算目标函数。

    其中前一句是得到预测类别中正确类别的概率所在的索引sub2ind产生索引为线性索引),而 y 指明了获取的索引为预测类别中正确类别的概率

    后一句通过访问索引,得到 log ⁡ P ( y ( i ) = k ∣ x ( i ) ; θ ) \log P(y^{(i)} = k | x^{(i)} ; \theta) logP(y(i)=kx(i);θ) ,计算目标函数。

变量的内容:

  • A :每一列代表一个样本,每一行代表对应类别的评分。

    1.0590441.0163961.0444811.0945231.013291……
    1.0422451.0099331.0442061.0977551.011094……
    1.0556371.0125961.0341921.0841841.002852……
    1.0653031.0145361.0347891.093251.009064……
    1.0632921.0149941.0262041.0853031.017293……
    1.051121.0167761.0390491.0887841.014322……
    1.0601121.0193591.0478571.102381.010763……
    1.0642681.0069461.0391171.0977931.007203……
    1.0554981.0203931.0270371.0762831.006618……
    11111……
  • BA的归一化

    0.1007030.1003160.1010440.1011550.1004……
    0.0991060.0996780.1010170.1014540.100183……
    0.1003790.0999410.1000480.1001990.099366……
    0.1012980.1001330.1001060.1010370.099982……
    0.1011070.1001780.0992760.1003030.100797……
    0.0999490.1003540.1005180.1006250.100503……
    0.1008040.1006090.101370.1018810.10015……
    0.10120.0993830.1005250.1014570.099797……
    0.1003660.1007110.0993560.0994690.099739……
    0.0950880.0986980.0967410.0924190.099083……
  • C:对B取对数

    -2.29558-2.29943-2.2922-2.2911-2.29859……
    -2.31157-2.30581-2.29247-2.28815-2.30076……
    -2.2988-2.30317-2.3021-2.30059-2.30894……
    -2.28969-2.30126-2.30153-2.29227-2.30277……
    -2.29158-2.30081-2.30986-2.29956-2.29465……
    -2.30309-2.29905-2.29742-2.29636-2.29757……
    -2.29457-2.29652-2.28898-2.28395-2.30109……
    -2.29066-2.30877-2.29735-2.28812-2.30462……
    -2.29893-2.2955-2.30905-2.30791-2.3052……
    -2.35295-2.31569-2.33572-2.38142-2.31179……
  • I:正确概率的线性索引

    614213744……
计算梯度
% calculate g 
Y = repmat(y',1,num_classes);
for i=1:num_classes
    Y(Y(:,i)~=i,i) = 0;       % 第i列中,仅标签为i的样本对应的位置不为0。
end
Y(Y~=0)=1;                % 第i列非零元所在的位置,表示标签为i的元素的索引
g = (-1) * X * (Y(:,1:(size(Y,2)-1))-B(1:(size(B,1)-1),:)');

对应公式:
∇ θ ( k ) J ( θ ) = − ∑ i = 1 m [ x ( i ) ( 1 { y ( i ) = k } − P ( y ( i ) = k ∣ x ( i ) ; θ ) ) ] \begin{aligned} \nabla_{\theta^{(k)}} J(\theta) = - \sum_{i=1}^{m}{ \left[ x^{(i)} \left( 1\{ y^{(i)} = k\} - P(y^{(i)} = k | x^{(i)}; \theta) \right) \right] } \end{aligned} θ(k)J(θ)=i=1m[x(i)(1{y(i)=k}P(y(i)=kx(i);θ))]
写成向量格式:
∇ θ J ( θ ) = − [ X ( 1 { Y = K } − P ( Y = K ∣ X ; θ ) ) ] \begin{aligned} \nabla_{\theta} J(\theta) = - { \left[ X \left( 1\{ Y = K\} - P(Y = K | X; \theta) \right) \right] } \end{aligned} θJ(θ)=[X(1{Y=K}P(Y=KX;θ))]
尤其注意一下几个变量的维度和内容:

  • X n × m n×m n×m = 758×60000。

  • Y:为 1 { Y = K } 1\{ Y = K\} 1{Y=K},维度 n × ( K − 1 ) n×(K-1) n×(K1)。对应代码中Y(:,1:(size(Y,2)-1)去掉非参数的偏置项

    000……
    000……
    100……
    000……
    000……
    000……
    000……
    000……
    000……
    010……
    000……
    000……
    001……
    ……………………
  • B:样本被分类为各个类别的概率, K × n K×n K×n。对应代码中B(1:(size(B,1)-1),:)'去掉非参数的偏置项,并转置。最后维度为 n × ( K − 1 ) n×(K-1) n×(K1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值