返回介绍

CNN 的数值实验

发布于 2025-02-25 23:04:59 字数 4554 浏览 0 评论 0 收藏 0

前面我们聊过了 Caffe 的整体架构,相信各位对 Caffe 的结构已经比较熟悉了,下面我们就来看看 CNN 中的一些细节问题,也顺着前面的思路进一步进行。

在好久之前介绍 ReLU 的时候,我们曾经提到 ReLU 相比于 Sigmoid 的一些优势:

  • Sigmoid 整体的梯度偏小,在外向传导的过程中会不断让梯度的幅度变小;
  • Sigmoid 存在一个梯度饱和问题:那就是如果非线性部分的输出靠近 0 或者 1,那么反向传导到了这里,Sigmoid 的梯度会接近于 0,这样就会导致梯度到这里就传导不下去了。从前面我们的那张图中可以看得出来。

有了这两个原因,我们认为 ReLU 这样的非线性函数在前向后向的传递性方面效果更好,如果 CNN 的网络层数比较深,ReLU 更能够保证梯度的无损传递。

当我们的前辈完成了这个重大发现之后,大家都觉得“这次终于稳了”,AlexNet 也横空出世,让 CNN 大放异彩。那个时候 AlexNet 已经算是非常"Deep"的网络了……

可是后来,大家对 CNN 模型能力的诉求越来越高,大家通过不断地实验,慢慢发现,现在的模型还不够深,想要模型够牛逼,模型的深度还得继续增加啊!

可是随着后面模型的深度不断增加,我们发现模型的训练过程变得越来越不可控,有时候一个不留神模型就训练溢出了,有时候模型训练着训练着就不动了。训练模型也变得越来越像炼丹了……

炼丹不是一件让人开心的事情,能炼好固然让人开心,但是炼不好就会让宝宝有情绪了。于是各位前辈又重新出发,试图找出新的方法解决这些恼人的问题。

当年众位大神齐聚一堂,开始讨论究竟什么样招式能破解这个困局。有的大神选择从数值的方向入手,有的大神选择从模型结构的方向入手,有的大神选择从模型结构入手,还有的大神走了其他的方法。一场“拯救大兵 CNN”的好戏也由此上演……

一个数值的小实验

好了,让我们回到 MNIST 这种比较简单的问题上。我们也曾经展示过 Caffe 中 MNIST 的例子,以下这个模型是我们曾经用过的模型:

  1. Conv 20*5*5 - ReLU - Pooling2*2,stride2
  2. Conv 50*5*5 - ReLU - Pooling2*2,stride2
  3. Ip 500 - ReLU
  4. Ip 10

这一次我们将 debug_info 打开,记录一下网络中每一层数据的数值信息。Caffe 中的 debug_info 默认可以给出所有数据的 L1 norm,也就是绝对值的和。这个数值可以在一定程度上反映数据的幅度。如果数据比较大,那么说明整体的数值比较大。

完成了 10000 轮模型的训练,模型最终在 test 集合得到了 0.991 的精度,可以说精度已经很高了。那么各个层的数据表现如何呢?这里我们主要关注以下的数值:

  1. 两个 conv 层和两个 ip 层的 top data 信息
  2. 两个 conv 层和两个 ip 层参数 w 的 data 信息
  3. 两个 conv 层和两个 ip 层参数 w 的 diff 信息
  4. 所有参数的 data 和 diff 的 L1 norm 和 L2 norm

首先是 top data

可以看出除了一开始的数值波动,后面的迭代中数值整体表现比较稳定,稳中有升。

其次是 w 的 data

可以看出 w 整体表现不算稳定,不过考虑整个优化的过程就是在改变它,所以它的大幅波动也是可以理解的。

接下来是 w 的 diff

可以看出 diff 在数值上表现得也比较稳定,基本上处于一个小的区间之中。

最后是 L1 norm 和 L2 norm

norm 和 diff 的表现总体上和前面展现的一致。

总体来说,topdata 和 w 的 diff 数值没有太大的波动,保持在一个稳定幅度上,所以整体的数值比较稳定,无论是前向的 top data 还是后向的 diff data 没有出现太大的数值波动或者数值幅度问题。

看完了这个成功案例,我们再看看失败案例,当然这个失败案例一般不会出现,只是做个效果而已,不过这个效果也足以说明一些问题。

这个失败案例直接来自于刚才的例子。我们在刚才的模型上只修改一个地方:四个核心层(conv1,conv2,ip1,ip2)的 w 参数的初始化方法。

原来的初始化方法是:

weight_filler {
  type: "xavier"
}

我们将它们改成:

weight_filler {
  type: "gaussian"
}

这样的改法是比较脑残的,这相当于对参数采取均值为 0,方差为 1 的高斯分布对参数进行初始化……

不用说,这个模型会死的很难看,10000 轮训练结束后,最终的精度为 0.1135。要知道一共只有 10 个数字,猜也可以达到 0.1 的精度。这个模型采用了各种高科技,结果却只比猜稍微好一点,简直弱到家了。

那么它在数值上的表现是怎样呢?直接来看图:

从图中可以看出,各个数据在幅度上的差距都非常大。尤其是最后一张图,data 和 diff 在数值上的差距拉得非常大,那么小量的 diff 对大量的 data 完全起不到改变的作用。这么看来一定是初始化的锅了。

那真的完全是初始化的锅么?众人问:初始化同学,你还有没有什么要补充的?

初始化同学:其实是因为我和 ReLU 同学不熟,你们换 Sigmoid 试试……

众人:当真?

于是乎我们开始了第三个实验……

第三个实验

为了洗刷初始化的清白,我们在保持初始化的基础上,将 3 个非线性的部分重新换成 sigmoid,由 sigmoid 再度出马。sigmoid 表示这种小场面它 Hold 住……

于是我们来看看 sigmoid 的最终结果:0.9538,相关的数值图在这里就不全贴了,只贴一张 L1 L2 norm 的图:

从这个图上来看,虽然 data 的幅度很大,但是 diff 的幅度也很大,基本上算旗鼓相当。

这个最终的精确率不能算特别高,但是起码说明模型还是学到了很多有用的知识。而且和 0.11 的精度相比,简直是一个天上一个地下,完全没得比啊!大家纷纷表示关键时候还得靠老将才能扛得住,初始化同学是被冤枉了。

这时候众人重新以怀疑的眼光看着 ReLU,原来真正的问题出你这啊!你的表现有点浪啊!

ReLU 委屈地表示:我还能再说一句么?

众人表示:这次的版面已经不够了,有话下次再说……

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文