gpt4 book ai didi

c++ - 卷积神经网络不收敛

转载 作者:行者123 更新时间:2023-11-30 01:11:51 25 4
gpt4 key购买 nike

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

Cross Circle

网络本身有五层:

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 (max) 吗?

最佳答案

  1. Should a convolutional network like this be able to discriminate between the two classes?

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

  1. Is this the correct approach?

最可能的原因是您的梯度公式有误。始终遵循 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 个规范 vector (第 i 个坐标上有一个的零 vector )

Should I be accounting for the ReLU (max) in the convolution layer backpropagation?

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

关于c++ - 卷积神经网络不收敛,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35190715/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com