大家好啊,我是董董灿。

经常看我文章的同学,或许知道最近我在做一个小项目——《从零手写Resnet50实战》。

从零开始,用最简单的程序语言,不借用任何第三方库,完结Resnet50的一切算法完成和网络结构建立,最终将下面这只猫辨认出来。

我完全手写的Resnet50网络,终于把猫识别出来了

不幸的是,在刚建立完网络之后,就试着运行了一下自己的神经网络,辨认成果是错的

没办法,只能用 torch 搭了一个官方的网络,和我手写的神经网络,一层一层进行成果比对,然后调试(从零手写Resnet50实战——运用 torch 辨认出了虎猫和萨摩耶)。

幸运的是,在通过一个数据一个数据比照之后,我的神经网络。

出猫了!

它居然真的将猫辨认出来了!

我完全手写的Resnet50网络,终于把猫识别出来了
我的神经网络出猫现场

在从1000个分类得分中,将最大值的索引(第282号)挑出来之后,查询分类文件,便得到了分类成果:tiger cat

我完全手写的Resnet50网络,终于把猫识别出来了

这个网络我没用 softmax。

由于 softmax 的效果是将成果“大的变得更显著,小的变得更微弱”,并不会改动成果的相对巨细。

我直接从最后一个全衔接层的输出,去找了最大值索引。

softmax的效果能够参考softmax原理。

进程记载

辨认出猫的进程,说难也不是太难,说简单但又有不少坑。

最难的在于出猫失败,查找原因的进程,是真的一层一层的进行成果比照。

好在我封装了一个比照函数,能帮助我在重要的网络节点,验证我的网络是否正确。

下面是出猫全流程记载。

首层 Conv2d + 第一个 BatchNorm2d + MaxPool 验证正确。

我完全手写的Resnet50网络,终于把猫识别出来了

第一个 Layer 验证正确,共 10 个 Conv2d。

我完全手写的Resnet50网络,终于把猫识别出来了

第二个 Layer 验证正确,共 13 个 Conv2d。

我完全手写的Resnet50网络,终于把猫识别出来了

第三个 Layer 验证正确,共 19 个 Conv2d。

我完全手写的Resnet50网络,终于把猫识别出来了

第四个 Layer 验证正确,共10个卷积。

我完全手写的Resnet50网络,终于把猫识别出来了

AvgPool 和 FC 层也都验证正确。

整个验证进程仍是挺苦楚的,但是看着一层层的打出来“succ”(success的缩写,说明和官方成果是共同的),仍是很有成就感,而且挺治好的。

下面简单说一下

我在出猫进程中遇到的那些坑

保存权值文件 layout 搞错

torch 默许的图片数据摆放格式是 NCHW,而我习气写算法的方法是NHWC。

因而,在前期将图片导出时,没有考虑自己算法完成的习气,而是将权值直接 flatten之后保存了。

成果便是,再将权值从文件中读入内存参与运算时,数据读取不正确。成果必定是错的。

意识到这一点之后,由于我算法都已经写好,而且不想改了,所以,将保存权值的逻辑,在 flatten 之前,添加了一个 transpose 操作,将权值从NCHW 转为 NHWC,然后保存。

BatchNorm2d 的均值和方差运用错误

BatchNorm2d的算法完成有多种,特别需求留意的是需求区分该算法是在练习时用的仍是推理时用的。

我完全手写的Resnet50网络,终于把猫识别出来了

练习和推理时用的BatchNorm2d虽然公式是相同的,但完成方法却大不相同。

首要差异在于:

  • 练习时均值和方差需求依据本次的数据进行实时核算

  • 推理是运用的均值和方差是模型保存好的参数,在 torch 模型中,分别为 BatchNorm2d.running_mean 和 BatchNorm2d.running_var。

而我在最开始的算法完成时,均值和方差是自己手算的(对应的练习进程),而没有运用模型保存的均值和方差。

成果便是每层BatchNorm算出来的成果都差一点,这一点差错在层与层之间传递,导致到最后的辨认成果中,差错被扩大。

正是由于这个差错被逐层扩大,就把猫辨认成了一个水桶

我完全手写的Resnet50网络,终于把猫识别出来了

残差结构问题

上一篇文章从零手写Resnet50实战——运用 torch 辨认出了虎猫和萨摩耶剖析残差结构或许会有问题。

实践验证残差结构没问题,便是一个简单地加法。

有问题的是上一层的BatchNorm2d,核算错误了。

那为什么核算错了,当时的剖析仍然能和官方的核算成果对上呢?

是由于当时的官方核算忘了一个 model.eval() 调用。该调用会告诉模型运行在推理形式而不是练习形式。

而如果我不调用,显然用的练习形式,恰巧的 BatchNorm2d 的第一次完成,手算均值和方差,就对应了练习形式的算法。

所以成果刚好对上了,但这样最终辨认的图片分类必定仍是错误的。

基本就遇到了这3个问题,在把这3个问题解决了之后,整个预测进程运行了大约40分钟,猫就被水到渠成的预测出来了。

所以,项意图第一阶段,就这么完结了。

下面会开启本项意图第二阶段——神经网络功能优化。

  • 用C++ 从头完成一遍一切算法:由于C++功能要比 python 手写的算法功能好很多

  • 重点优化卷积的功能:目前40多分钟有将近39分钟的实践花在了卷积上

  • 运用C++完成的版本争取在数秒内完结一张图片的推理

由于本次有2/3的坑都是BatchNorm算法引起的,后边会写一篇BatchNorm算法的文章,欢迎继续重视。

出猫,看起来也很简单。

欢迎继续重视本博主文章和本系列,一同从零开始,学算法,做实践项目。 这是一个能够写到简历上,亮瞎面试官双眼的项目哦