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

卷积神经网络不收敛

黄弘新
2023-03-14

我一直在看一些关于深度学习/卷积神经网络的视频,比如这里和这里,我试图用C语言实现我自己的。在我第一次尝试时,我试图保持输入数据相当简单,所以我的想法是区分十字和圆,我有一个大约25个的小数据集(64*64个图像),它们如下所示:

网络本身有五层:

Convolution (5 filters, size 3, stride 1, with a ReLU)
MaxPool (size 2) 
Convolution (1 filter, size 3, stride 1, with a ReLU)
MaxPool (size 2)
Linear Regression classifier

我的问题是我的网络没有收敛到任何东西上。权重似乎都没有改变。如果我运行它,预测基本保持不变,除了偶尔出现的异常值,它会在下一次迭代返回之前跳起来。

卷积层训练看起来像这样,删除了一些循环以使其更干净

// Yeah, I know I should change the shared_ptr<float>
void ConvolutionalNetwork::Train(std::shared_ptr<float> input,std::shared_ptr<float> outputGradients, float label)
{
    float biasGradient = 0.0f;

    // Calculate the deltas with respect to the input.
    for (int layer = 0; layer < m_Filters.size(); ++layer)
    {
        // Pseudo-code, each loop on it's own line in actual code
        For z < depth, x <width - filterSize, y < height -filterSize
        {               
            int newImageIndex = layer*m_OutputWidth*m_OutputHeight+y*m_OutputWidth + x;

            For the bounds of the filter (U,V)
            {
                // Find the index in the input image
                int imageIndex = x + (y+v)*m_OutputWidth + z*m_OutputHeight*m_OutputWidth;
                int kernelIndex = u +v*m_FilterSize + z*m_FilterSize*m_FilterSize;
                m_pGradients.get()[imageIndex] += outputGradients.get()[newImageIndex]*input.get()[imageIndex];
                m_GradientSum[layer].get()[kernelIndex] += m_pGradients.get()[imageIndex] * m_Filters[layer].get()[kernelIndex];
                        
                biasGradient += m_GradientSum[layer].get()[kernelIndex];
            }       
        }
    }

    // Update the weights
    for (int layer = 0; layer < m_Filters.size(); ++layer)
    {
        For z < depth, U & V < filtersize
        {
            // Find the index in the input image
            int kernelIndex = u +v*m_FilterSize + z*m_FilterSize*m_FilterSize;
            m_Filters[layer].get()[kernelIndex] -= learningRate*m_GradientSum[layer].get()[kernelIndex];
        }
        m_pBiases.get()[layer] -= learningRate*biasGradient;
    }
}

因此,我创建了一个缓冲区(m\u pGradients),它是输入缓冲区的维度,用于将梯度反馈回前一层,但使用梯度和来调整权重。

“最大池”(max pooling)按原样计算渐变(它保存最大索引并将所有其他渐变置零)

void MaxPooling::Train(std::shared_ptr<float> input,std::shared_ptr<float> outputGradients, float label)
{
    for (int outputVolumeIndex = 0; outputVolumeIndex <m_OutputVolumeSize; ++outputVolumeIndex)
    {
        int inputIndex = m_Indices.get()[outputVolumeIndex];
        m_pGradients.get()[inputIndex] = outputGradients.get()[outputVolumeIndex];
    }
}

最后的回归层计算其梯度如下:

void LinearClassifier::Train(std::shared_ptr<float> data,std::shared_ptr<float> output, float y)
{
    float * x  = data.get();

    float biasError = 0.0f;
    float h = Hypothesis(output) - y;

    for (int i =1; i < m_NumberOfWeights; ++i)
    {
        float error = h*x[i];
        m_pGradients.get()[i] = error;
        biasError += error;
    }

    float cost = h;
    m_Error = cost*cost;

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

    m_pWeights.get()[0] -= learningRate*biasError;
}

在对这两个示例进行100次迭代训练后,对每个示例的预测与另一个相同,并且从一开始就保持不变。

  1. 像这样的卷积网络应该能够区分这两类吗
  2. 这是正确的方法吗
  3. 我应该考虑卷积层反向传播中的ReLU(max)吗

共有1个答案

林和煦
2023-03-14
  1. 像这样的卷积网络应该能够区分这两类吗

对事实上,即使是线性分类器本身也应该能够非常容易地进行区分(如果图像或多或少居中)。

最可能的原因是梯度公式中的错误。始终遵循2条简单规则:

>

  • 从基本模型开始。不要从2-conv网络开始。无需任何卷积即可启动代码。现在能用了吗?当您有一个工作线性层时,添加单个卷积。现在能用了吗?等等
  • 始终以数字形式检查渐变。这是很容易做到的,并将节省您数小时的调试!从分析中回忆起

    [grad f(x) ]_i ~  (f(x+eps*e_i) - f(x-eps*e_i)) / 2*eps
    

    其中[]_i是指第i个坐标,e_i是指第i个标准向量(第i个坐标上有一个零向量)

    我应该考虑卷积层反向传播中的ReLU(max)吗?

    是的,ReLU会改变您的梯度,因为这是您需要区分的非线性。再次回到要点1。从简单的模型开始,分别添加每个元素以找出导致梯度/模型崩溃的元素。

  •  类似资料:
    • 注意: 本教程适用于对Tensorflow有丰富经验的用户,并假定用户有机器学习相关领域的专业知识和经验。 概述 对CIFAR-10 数据集的分类是机器学习中一个公开的基准测试问题,其任务是对一组大小为32x32的RGB图像进行分类,这些图像涵盖了10个类别: 飞机, 汽车, 鸟, 猫, 鹿, 狗, 青蛙, 马, 船以及卡车。 想了解更多信息请参考CIFAR-10 page,以及Alex Kriz

    • 卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。卷积神经网络由一个或多个卷积层和顶端的全连通层(对应经典的神经网络)组成,同时也包括关联权重和池化层(pooling layer)。这一结构使得卷积神经网络能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网络

    • 在了解了机器学习概念之后,现在可以将注意力转移到深度学习概念上。深度学习是机器学习的一个分支。深度学习实现的示例包括图像识别和语音识别等应用。 以下是两种重要的深度神经网络 - 卷积神经网络 递归神经网络 在本章中,我们将重点介绍CNN - 卷积神经网络。 卷积神经网络 卷积神经网络旨在通过多层阵列处理数据。这种类型的神经网络用于图像识别或面部识别等应用。CNN与其他普通神经网络之间的主要区别在于

    • 主要内容:卷积神经网络深度学习是机器学习的一个分支,它是近几十年来研究人员突破的关键步骤。深度学习实现的示例包括图像识别和语音识别等应用。 下面给出了两种重要的深度神经网络 - 卷积神经网络 递归神经网络。 在本章中,我们将关注第一种类型,即卷积神经网络(CNN)。 卷积神经网络 卷积神经网络旨在通过多层阵列处理数据。这种类型的神经网络用于图像识别或面部识别等应用。 CNN与任何其他普通神经网络之间的主要区别在于CNN

    • 注意: 本教程适用于对Tensorflow有丰富经验的用户,并假定用户有机器学习相关领域的专业知识和经验。 概述 对CIFAR-10 数据集的分类是机器学习中一个公开的基准测试问题,其任务是对一组32x32RGB的图像进行分类,这些图像涵盖了10个类别: 飞机, 汽车, 鸟, 猫, 鹿, 狗, 青蛙, 马, 船以及卡车。 想了解更多信息请参考CIFAR-10 page,以及Alex Krizhev

    • 在“多层感知机的从零开始实现”一节里我们构造了一个含单隐藏层的多层感知机模型来对Fashion-MNIST数据集中的图像进行分类。每张图像高和宽均是28像素。我们将图像中的像素逐行展开,得到长度为784的向量,并输入进全连接层中。然而,这种分类方法有一定的局限性。 图像在同一列邻近的像素在这个向量中可能相距较远。它们构成的模式可能难以被模型识别。 对于大尺寸的输入图像,使用全连接层容易造成模型过大