【问题标题】:Convolutional neural network not converging卷积神经网络不收敛
【发布时间】:2016-05-13 10:57:34
【问题描述】:

我一直在观看一些关于深度学习/卷积神经网络的视频,例如 herehere,我尝试用 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_pGradients),它是输入缓冲区的维度,用于将梯度反馈到前一层,但使用梯度和来调整权重。

最大池化这样计算梯度(它保存最大索引并将所有其他梯度归零)

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(最大值)吗?

【问题讨论】:

    标签: c++ machine-learning neural-network deep-learning backpropagation


    【解决方案1】:
    1. 这样的卷积网络应该能够区分这两个类别吗?

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

    1. 这是正确的方法吗?

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

    1. 基本模型开始。不要从 2-conv 网络开始。在没有任何卷积的情况下开始您的代码。它现在有效吗?当您有 1 个线性层时,添加 单卷积。它现在有效吗?等等。
    2. 始终以数字方式检查您的渐变。这很容易做到,并且可以节省您数小时的调试时间!从分析中回忆

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

      其中 []_i 表示第 i 个坐标,e_i 表示第 i 个规范向量(零向量,第 i 个坐标上为一个)

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

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

    【讨论】:

    • 谢谢!我会试试然后回复你。图像没有居中并且颜色不同等,所以我认为线性分类器将在整个测试集上失败。但我会在这两个上试一试。
    猜你喜欢
    • 2012-03-03
    • 2016-12-05
    • 2016-05-13
    • 2017-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多