使用 2 层网络和 softmax 进行反向传播的问题

数据挖掘 机器学习 神经网络 matlab 反向传播
2021-10-03 17:29:07

我有一个简单的神经网络,它有一个隐藏层,softmax作为输出层的激活函数。隐藏层使用各种激活函数,因为我正在尽可能多地测试和实现它们。

对于目前的训练和测试,我使用的是手写数字的 MNIST 数据集,因此我的输入数据是一个矩阵,在每一行中都有不同的图像,在每一列中,该图像的一个像素已被重新整形为向量。

当我对两个层都使用sigmoid激活函数时,计算的梯度和分析梯度似乎一致,但是当我尝试其他方法时,例如隐藏层的tanhsoftplus以及输出层的softmax,从数据中可以看出存在很大的差异下面(左->数值梯度,右->解析梯度)

(1)sigmoid (2)softmax

  -9.4049e-04  -6.4143e-04
  -6.2623e-05  -2.5895e-05
   1.0676e-03   6.9474e-04
  -2.0473e-03  -1.3471e-03
   2.9846e-03   1.9716e-03
   4.0945e-05   2.7627e-05
  -2.5102e-05  -1.7017e-05
   8.8054e-06   6.0967e-06
   7.8509e-06   5.0682e-06
  -2.4561e-05  -1.6270e-05
   5.6108e-05   3.8449e-05
   2.0690e-05   1.2590e-05
  -9.7665e-05  -6.3771e-05
   1.7235e-04   1.1345e-04
  -2.4335e-04  -1.6071e-04

(1)tanh (2)softmax

  -3.9826e-03  -2.7402e-03
   4.6667e-05   1.1115e-04
   3.9368e-03   2.5504e-03
  -7.7824e-03  -5.1228e-03
   1.1451e-02   7.5781e-03
   1.5897e-04   1.0734e-04
  -9.6886e-05  -6.5701e-05
   3.3560e-05   2.3153e-05
   3.3344e-05   2.1786e-05
  -1.0282e-04  -6.8409e-05
   2.1185e-04   1.4774e-04
   9.0293e-05   5.3752e-05
  -4.0012e-04  -2.6047e-04
   6.9648e-04   4.5839e-04
  -9.7518e-04  -6.4468e-04

(1)乙状结肠 (2)乙状结肠

-9.2783e-03  -9.2783e-03
   8.8991e-03   8.8991e-03
  -8.3601e-03  -8.3601e-03
   7.6281e-03   7.6281e-03
  -6.7480e-03  -6.7480e-03
  -3.0498e-06  -3.0498e-06
   1.4287e-05   1.4287e-05
  -2.5938e-05  -2.5938e-05
   3.6988e-05   3.6988e-05
  -4.6876e-05  -4.6876e-05
  -1.7506e-04  -1.7506e-04
   2.3315e-04   2.3315e-04
  -2.8747e-04  -2.8747e-04
   3.3532e-04   3.3532e-04
  -3.7622e-04  -3.7622e-04
  -9.6266e-05  -9.6266e-05

我实现反向传播的方式如下:

变量->

Theta1 , Theta2第一层和第二层具有不同权重的表格。

m :我的训练集的大小

y每个输入样本具有正确类别的向量

Y一个矩阵,每个输入样本的类别都有一个热编码

X :带有输入数据的矩阵,每一行是一个不同的训练样本

% Feedforward
a1 = [ones(m, 1) X];
z2 = a1*Theta1';
a2 = [ones(m, 1) activation(z2, activation_type)];
z3 = a2*Theta2';
a3 = activation(z3, 'softmax');
h = a3;

% Calculate J
J = sum(sum((-Y).*log(h) - (1-Y).*log(1-h), 2))/m + lambda*p/(2*m); # sigmoid
%J = -(sum(sum((Y).*log(h))) + lambda*p/(2*m)); # softmax

% Calculate sigmas
sigma3 = a3.-Y;
sigma2 = (sigma3*Theta2).*activationGradient([ones(m, 1) z2], 'sigmoid');
sigma2 = sigma2(:, 2:end);

% Accumulate gradients
delta_1 = (sigma2'*a1);
delta_2 = (sigma3'*a2);

第一个成本计算J是为sigmoid计算的,下面的一个是为softmax计算的(见评论),所以我在两者之间切换。

我在反向传播过程中是否遗漏了一些东西,为什么它在sigmoids中按预期工作,但在sofmax中没有按预期工作

1个回答

我认为这可能是 softmax 成本函数中一个相对微不足道的错误:

J = -(sum(sum((Y).*log(h))) + lambda*p/(2*m)) 

应该

J = -sum(sum((Y).*log(h)))/m + lambda*p/(2*m) 

即仅对于 softmax,您已经有效地从成本函数中减去了正则化项,而不是添加它。此外,您忘记将错误项除以批次中的示例数(并且在计算梯度时采用此平均值)

如果你纠正这个错误计算,你的反向传播计算对我来说是正确的J