当前位置: 首页 > 知识库问答 >
问题:

卷积网络滤波器总是负的

常光明
2023-03-14

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

在两个标记的图像上:

这些数据被传递到一个两层网络、一个分类器(它自己获得100%)和一个单过滤器3×3卷积层。

在第一次迭代中,conv层的输出如下所示(图像顺序与上面相同):

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

这一问题又是由于从逻辑回归/线性层传回的梯度对于交叉来说非常高(标签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;
        }
    }
}

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

共有2个答案

林和煦
2023-03-14

我通过缩小CNN层的梯度来解决这个问题,但现在我不明白为什么需要这样做,所以如果有人有任何直觉知道为什么这样做会很好。

黄淇
2023-03-14

RELU的激活在这方面是出了名的。你通常不得不使用较低的学习率。这背后的原因是,当RELU返回正数时,它可以继续自由学习,但当一个单元返回一个非常低的数字时,它可能会变成一个“死”神经元,永远不会再激活。如果你有一个系统,正数可以自由变化,但低于某个阈值的负数有可能被“卡住”,如果可以达到这个最低阈值,系统最终将完全卡住。

此外,对RELU神经元来说,初始化体重也是非常微妙的。您似乎正在初始化范围0-1,这会产生巨大的偏差。这里有两个提示-使用以0为中心的范围和更小的范围。类似于(-0.1)-(0.1)

另一件事是,根据我的经验,RELU单元似乎在困难的任务(如Imagenet分类)中更有用。尝试一下TanH单位。你初始化体重和学习速度的方式并没有那么微妙。

 类似资料:
  • 我正在构建一个卷积网络图像分类的目的,我的网络受到VGG conv网络的启发,但我更改了每层的层数和过滤器,因为我的图像数据集非常简单。 然而,我想知道为什么VGG中的Fitler数总是2:64的幂- 我猜这是因为每个池将输出大小除以2 x 2,因此需要将过滤器的数量乘以2。 但我仍然想知道,这一选择背后的真正原因是什么;这是为了优化吗?分配计算是否更容易?我应该在我的人际网络中保持这种逻辑吗。

  • 创建卷积神经网络(CNN)时(如中所述https://cs231n.github.io/convolutional-networks/)输入层与一个或多个过滤器连接,每个过滤器表示一个要素地图。这里,过滤层中的每个神经元只与输入层的几个神经元相连。在最简单的情况下,我的n个过滤器中的每一个都具有相同的维度并使用相同的步幅。 我的问题是: 如何确保过滤器学习不同的特征,尽管它们使用相同的补丁进行训练

  • 我读过这篇文章“UFLDF”,它发展了autoencoder中隐藏层的可视化,但我很困惑如何可视化卷积神经网络的滤波器。在我看来,对于第一个卷积层,要使滤波器可视化,它需要这个等式: 对于第二个卷积层,它应该将滤波器投射到原始输入空间,但我不知道如何做。

  • 此问题似乎与在帮助中心定义的范围内编程无关。 我不明白为什么在使用卷积神经网络时需要翻转滤波器。 根据千层面文件, flip_filters:bool(默认值:True) 是在将过滤器滑动到输入上之前翻转过滤器,执行卷积(这是默认设置),还是不翻转过滤器并执行相关。请注意,对于千层面中的其他一些卷积层,翻转会产生开销,默认情况下是禁用的–使用从其他层学习的权重时,请查看文档。 这是什么意思?我从未

  • 该脚本可以在几分钟内在 CPU 上运行完。 结果示例: from __future__ import print_function import time import numpy as np from PIL import Image as pil_image from keras.preprocessing.image import save_img from keras import la

  • 我正在实现一个三维卷积神经网络,我有两个问题。 问题一 每个输入是一个大小为(201,10,4)的3D矩阵。我希望我的过滤器能够在第二和第三维度上移动,因为它们是完全连接的。第三个维度是特征维度。所以我不想看第二和第三维度的当地社区。因此,我的过滤器大小将是例如(3,10,4)的大小。所以过滤器大小等于第二和第三维度,但我们在第一维度中有权重共享。以下是我的卷积代码: 所以我应该在这里使用步幅,这