卷积网络过滤器始终为负

Convolutional network filter always negative

我问了一个关于我一直在构建的网络的问题 last week, 并且我重复了导致我发现一些问题的建议。我回到这个项目并解决了所有问题,并在此过程中学到了 很多 关于 CNN 的知识。现在我陷入了一个问题,我所有的权重都变成了巨大的负值,再加上输出图像中的 RELU 端总是完全黑色(使得分类器无法完成它的工作)。

在两个标记的图像上:

这些被传递到一个两层网络,一个分类器(它自己得到 100%)和一个过滤器 3*3 卷积层。

在第一次迭代中,conv 层的输出看起来像(图像的顺序与上面相同):

滤镜是3*3*3,因为图片是RGB的。权重都是0.0f-1.0f之间的随机数。在下一次迭代中,图像 完全 黑色,打印过滤器显示它们现在在 -49678.5f(我能看到的最高值)和 -61932.3f 的范围内。

这个问题反过来是由于从 Logistic Regression/Linear 层传回的梯度对于交叉(标签 0,预测 0)来说非常高。对于圆(标签 1,预测 0),值大约在 -12 和 -5 之间,但对于十字,它们都在正高 1000 到高 2000 范围内。

将这些发回的代码看起来像(省略了一些部分):

void LinearClassifier::Train(float * x,float output, float y)
{
    float h = output - y;
    float average = 0.0f;
    for (int i =1; i < m_NumberOfWeights; ++i)
    {
        float error = h*x[i-1];
        m_pGradients[i-1] = error;
        average += error;
    }

    average /= static_cast<float>(m_NumberOfWeights-1);

    for (int theta = 1; theta < m_NumberOfWeights; ++theta)
    {
        m_pWeights[theta] = m_pWeights[theta] - learningRate*m_pGradients[theta-1];
    }

    // Bias
    m_pWeights[0] -= learningRate*average;
}

传回单卷积层:

// This code is in three nested for loops (for layer,for outWidth, for outHeight)
float gradient = 0.0f;
// ReLu Derivative
if ( m_pOutputBuffer[outputIndex] > 0.0f) 
{
    gradient = outputGradients[outputIndex];
}

for (int z = 0; z < m_InputDepth; ++z)
{
    for ( int u = 0; u < m_FilterSize; ++u)
    {
        for ( int v = 0; v < m_FilterSize; ++v)
        {
            int x = outX + u - 1;
            int y = outY + v - 1;

            int inputIndex = x + y*m_OutputWidth + z*m_OutputWidth*m_OutputHeight;

            int kernelIndex = u + v*m_FilterSize + z*m_FilterSize*m_FilterSize;

            m_pGradients[inputIndex] += m_Filters[layer][kernelIndex]*gradient;
            m_GradientSum[layer][kernelIndex] += input[inputIndex]*gradient;
        }
    }
}

通过一次一张地传递每个图像来迭代此代码。梯度显然朝着正确的方向发展,但我如何阻止巨大的梯度抛出预测函数?

我通过缩小 CNN 层的渐变来修复它,但现在我很困惑为什么需要这个 works/is 所以如果有人对它为什么起作用有任何直觉那就太好了。

RELU 激活因这样做而臭名昭著。您通常必须使用较低的学习率。这背后的原因是,当 RELU return 的正数时它可以继续自由学习,但是当一个单元成为 return 一个非常低的数字时它可以变成 "dead"神经元,再也不会激活。如果你有一个系统,正数可以自由变化,但低于某个阈值的负数有可能得到 "stuck",如果达到这个最小阈值,系统最终将完全卡住。

此外,RELU 神经元的权重初始化非常微妙。看来您正在初始化到 0-1 的范围,这会产生巨大的偏差。这里有两个提示 - 使用以 0 为中心的范围,以及一个小得多的范围。像 (-0.1) - (0.1)

另一件事是,根据我的经验,RELU 单元似乎在困难的任务(例如 Imagenet 分类)中更有用。为此尝试使用 TanH 单元。初始化权重和学习率的方式几乎没有那么微妙。