没有 Sigmoid 导数的 CNN 反向传播

数据挖掘 美国有线电视新闻网 反向传播
2021-10-12 06:24:42

我是 CNN 的新手,正在尝试研究一些 MATLAB 示例代码(因为我需要知道内部计算)。我最近意识到我正在使用的示例代码不会将误差乘以 sigmoid 在反向传播中的导数。前馈过程将 sigmoid 作为最后一层的激活函数,因此据我了解,反向传播误差 =(输出 - 目标)* sigmoid 的导数(输出)。但是,作者故意使用以下代码禁用了这种乘法:

if cnn.loss_func == 'cros' 
    if cnn.layers{cnn.no_of_layers}.act_func == 'soft'
        cnn.CalcLastLayerActDerivative = 0;
    elseif cnn.layers{cnn.no_of_layers}.act_func == 'sigm'
        cnn.CalcLastLayerActDerivative = 0;
    end    
end

我的参考代码

当 cnn.CalcLastLayerActDerivative = 0 时,错误被定义为(输出 - 目标)。我尝试初始化 cnn.CalcLastLayerActDerivative = 1 以便在反向传播中考虑 sigmoid 的导数,但随后我的错误率变差了。我不确定这是否只是因为 sigmoid 的导数在 [0,0.25] 范围内,或者我没有正确理解反向传播。有谁知道为什么会发生这种情况以及我是否应该在计算中添加 sigmoid 的导数?

谢谢!

2个回答

错误被定义为(输出 - 目标)

这是以 Sigmoid 作为最后一层的交叉熵损失函数的正确梯度。

对于平方(二次)损失

(yf(x))2,
正如你所说,梯度是
(yf(x))f(x)
(持续的2被删除),但对于二元交叉熵损失
ylogf(x)+(1y)log(1f(x)),
梯度是
yf(x)/f(x)(1y)f(x)/(1f(x)),
因为对于Sigmoid我们有f(x)=f(x)(1f(x)),通过替换梯度变为
y(1f(x))(1y)f(x)=yf(x)
为了区分这两种渐变,作者设置cnn.CalcLastLayerActDerivative = 0稍后在文件中的if语句中进行检查bpcnn.m,如下所示(原始代码中不存在注释):

...
else
  % error = (f(x) - y)
  er = ( cnn.layers{cnn.no_of_layers}.outputs - yy);
...
if cnn.CalcLastLayerActDerivative ==1 
    % change the error from (f(x) - y) to f'(x)(f(x) - y)
    er =applyactfunccnn(cnn.layers{cnn.no_of_layers}.outputs,cnn.layers{cnn.no_of_layers}.act_func, 1, er);
end

这意味着梯度是(yf(x))f(x)对于quad(yf(x))对于cros(错误的变量名!)。

作为旁注,作者只允许 Sigmoid 用于交叉熵,这意味着只支持二元分类器(多类分类器需要 SoftMax)。

error('cross entropy is implemented only when last layer is sigmoid');

编辑

感谢@Edison 指出错误和梯度的处理方式与代码中的损失值不同,这大大改变了最终答案。

非常感谢您(Esmailian)的回答。我同意你的观点,作者通过设置区分了这两种损失cnn.CalcLastLayerActDerivative=0/1

yf′(x)/f(x)−(1−y)f′(x)/(1−f(x))但是,在原始代码中,没有提供corss-entropy: 的梯度计算bpcnn.m仅提供了 corss-entropy 误差ylogf(x)+(1−y)log(1−f(x)),但er1仅用于绘制损失:

>     if cnn.loss_func == 'cros' %cross_entropy'
>             if cnn.layers{cnn.no_of_layers}.act_func == 'sigm'
>                 er1 = -1.*sum((yy.*log(cnn.layers{cnn.no_of_layers}.outputs) + (1-yy).*log(1-cnn.layers{cnn.no_of_layers}.outputs)), 1);
>             else
>      ...
>             end
>             cnn.loss = sum(er1(:))/size(er1,2); %loss over all examples
>         
>         else
>             er1 = er.^2;
>             cnn.loss = sum(er1(:))/(2*size(er1,2)); %loss over all examples
>          
>     end

因此,您能否就此提供更详细的答案?

感谢@Esmailian!我所有的问题现在都解决了。