我一直在使用多种资源在 C++ 中实现我自己的人工神经网络包。
我一直在使用的一些资源包括
https://www.anotsorandomwalk.com/backpropagation-example-with-numbers-step-by-step/
https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/
https://cs.stanford.edu/people/karpathy/convnetjs/intro.html,
以及其他几个。
我的代码设法准确地复制了前两个资源中的结果。然而,就深度而言,这些都是相当简单的网络。因此,以下(详细)问题:
对于我的实现,我一直在使用 MNIST 手写数字数据库 ( http://yann.lecun.com/exdb/mnist/ )。
使用我编写的 ANN 包,我创建了一个简单的 ANN,其中包含 784 个输入神经元、一个包含 16 个神经元的隐藏层以及一个包含 10 个神经元的输出层。我已经在隐藏层和输出层上实现了 ReLU,以及在输出层上实现了 softmax 以获得概率。权重和偏差分别初始化为 [-1,1] 范围内的随机值
所以网络是784x16x10。
我的反向传播结合了权重梯度和偏置梯度逻辑。
使用这种配置,我在包含 60,000 位数字的 MNIST 训练集上反复获得大约 90% 的命中率,总平均成本约为 0.07,在包含 10,000 位数字的测试集上,命中率略高,约为 92.5%。
对于我第一次实现 ANN,我对此非常满意。然而,我的下一个想法是:
“如果我添加另一个隐藏层,我应该会得到更好的结果......?”。
所以我创建了另一个具有相同配置的人工网络,除了添加了另一个 16 个神经元的隐藏层,我也通过一个 reLU 运行它。所以这个网络是784x16x16x10。
在这个 ANN 上,我得到的结果明显更差。训练集上的命中率反复出现在 ~45% 左右,总平均误差约为 0.35,而在测试集上我也只有 45% 左右。
这使我得出以下一个或两个结论:
A)我在 C++ 中的 ANN 实现存在某种错误。如果是这样,我敢打赌它在反向传播的某个地方,因为我不能 100% 确定我的权重梯度和偏差梯度计算对于最后一个隐藏层之前的任何层都是正确的。
B) 这是预期的效果。关于添加另一层的某些事情使 ANN 不适合这种(数字分类)类型的问题。
当然,A、B 或 A 和 B 可能为真。
比我更有经验的人可以给我一些意见,特别是关于 B) 是否正确?
如果 B) 不正确,那么我知道我必须再次查看我的代码。