在 Torch 上 CIFAR-10 达到 92.45% 准确率
完整代码可在 https://github.com/szagoruyko/cifar.torch 获取,只需将其克隆到你的机器上即可使用。
CIFAR-10 包含 60000 张标记为 10 个类别,大小为 32x32 的图像,训练集有 50000 张,测试集有 10000 张。曾经举办过一个 Kaggle 比赛:https://www.kaggle.com/c/cifar-10,这里有一个略微过时的最先进结果表:http://rodrigob.github.io/are_we_there_yet/build/classification_datasets_results.html
按照今天的标准,该数据集相当小,但仍然是机器学习算法的一个很好的游乐场。最先进的当然包括深度卷积神经网络,然而很难定义哪种“深度”技术是最好的。如果你不做任何裁剪、仿射变换或集成,只进行水平翻转,我认为 92.45% 是最好的结果。有趣的是,人类的表现大约为 94%,要超越它就必须使用大量的图像增强。查看 @nagadomi 在 24x24 裁剪上的训练代码:https://github.com/nagadomi/kaggle-cifar10-torch7
我的代码大约 400 行,包括模型定义和数据预处理,主要来自 2_supervised 教程。有一些我不喜欢的地方
- 所有代码都在一个文件中:这对演示来说很好,但是如果你想做实验,你不想每次运行都要等待数据预处理;
- 批次逐个示例处理。对于新手来说,如何正确地做到这一点并不明显,他们会复制粘贴代码,然后它就会非常慢;
- 其中的模型已经很旧了。
所以我对它进行了现代化,并添加了一些不错的技巧,例如保存一个每次迭代都会更新的 html 报告。它可以复制到 Dropbox 等地方,非常有助于跟踪模型性能并保存报告。
你需要一台至少有 2 GB 内存的 GPU,并安装 cudnn
,使用标准 nn
后端需要更多内存。 cudnn
是 NVIDIA 的深度学习库,目前尚未公开发布,但绝对值得注册并申请,它很棒:https://developer.nvidia.com/cudnn
NVIDIA GPU 是首选,也是 BatchNormalization 所需的,但 AMD 卡也可以使用 OpenCL,这得益于 Hugh Perkins 的这项惊人工作:https://github.com/hughperkins/cltorch.git 查看 opencl 分支。
这篇文章和代码由 3 个部分/文件组成
- 模型定义
- 数据预处理
- 训练
模型 models/vgg_bn_drop.lua
在 Batch Normalization 论文 [1] 今年冬天出现在 arxiv 上,提供了一种通过使用批次统计来加速训练和提高性能的方法,以及 nn.BatchNormalization
在 Torch 中实现后(感谢 Facebook),我想看看它与 Dropout 如何协同工作,CIFAR-10 是一个很好的起点。
想法很简单,虽然 BatchNormalization 的作者认为它可以代替 Dropout,但我认为为什么不在网络内部一起使用它们来大规模正则化训练呢?
所以模型定义在这里
这是一个类似 VGG 的网络 [2],有许多 3x3 过滤器,填充为 1,1,因此它们之后的特征图大小不会改变。只有在最大池化后才会改变它们的大小。卷积层的权重采用 MSR 风格 [3] 初始化。
预处理 provider.lua
我喜欢用 BatchProvider -> 网络结构来训练模型。实际上,你甚至可以创建一个像这样的模型
model = nn.Sequential()
model:add(BatchProvider) -- different in train and test mode
model:add(DataAugmentation) -- disabled in test mode
model:add(NeuralNetwork)
然后你的训练代码非常简单。但是,在实际代码中,我只在模型中保留数据增强,虽然 BatchProvider 是一个类。所以,让我们开始预处理,从 https://github.com/szagoruyko/cifar.torch 克隆代码,进入文件夹 cifar.torch
,启动解释器
th -i provider.lua
它会运行文件并进入交互模式。预处理大约需要 40 分钟
provider = Provider()
provider:normalize()
torch.save('provider.t7',provider)
最终,所有数据都将存储在 provider.t7
文件中,大小为 1400 MB。图像被转换为 YUV,并进行均值-标准差归一化。
训练 train.lua
就是这样,你可以开始训练了
CUDA_VISIBLE_DEVICES=0 th train.lua
模型达到最佳性能的参数是代码中的默认参数。我使用了带交叉熵损失的 SGD,学习率为 1,动量为 0.9,权重衰减为 0.0005,每 25 个迭代周期降低一次学习率。几个小时后,你将拥有模型。可以通过例如自动更新的 Firefox 或 Chrome 插件更新 logs/report.html
来跟踪准确率。
准确率如何提高
混淆矩阵
ConfusionMatrix:
[[ 929 4 15 7 4 0 1 2 29 9] 92.900%
[ 2 977 2 0 1 0 0 0 6 12] 97.700%
[ 16 1 923 16 25 8 7 1 3 0] 92.300%
[ 14 2 30 836 19 68 18 5 6 2] 83.600%
[ 6 1 18 16 932 7 6 10 4 0] 93.200%
[ 3 1 25 78 17 867 4 5 0 0] 86.700%
[ 4 1 19 17 6 7 942 0 2 2] 94.200%
[ 6 0 12 15 10 14 0 942 1 0] 94.200%
[ 22 6 4 1 0 1 1 0 961 4] 96.100%
[ 9 38 1 4 0 1 1 1 10 935]] 93.500%
+ average row correct: 92.439999580383%
+ average rowUcol correct (VOC measure): 86.168013215065%
+ global correct: 92.44%
移除 BN 或 Dropout 会导致 91.4% 的准确率。
我创建了一个小表格,在 GeForce GTX 980 上对 VGG+BN+Dropout 架构的不同后端进行了基准测试。批次大小设置为 128,数字以秒为单位
| cunn | cudnn R2 | clnn(无 BN) — | :—: | :—: | :—: forward | 0.292 | 0.163 | 1.249 backward | 0.407 | 0.333 | 0.831 forward + backward | 0.699 | 0.500 | 2.079
cunn
是 Torch 的标准 CUDA 神经网络后端,clnn
是 OpenCL 后端。 cudnn
是最快的,正如预期的那样。还有一个 cuda-convnet2
后端,它可能更快,但我没有在这个架构上进行测试,主要是因为 BN 是以 BDHW 格式实现的,而 cuda-convnet2
以 DHWB 格式工作。
这段代码是深度卷积神经网络的一个很好的游乐场,例如,它很容易实现 Network-In-Network 架构 [4],该架构在使用 BN 时可以达到 92% 的准确率(比他们在论文中声称的准确率高出约 2%),在不使用 BN 时可以达到 88% 的准确率,而 NIN 的训练速度是 VGG 的 4 倍。我在 nin.lua 中添加了示例
感谢 Soumith 和 IMAGINE 实验室帮助我准备这篇文章!
参考资料
- Sergey Ioffe, Christian Szegedy. Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift [arxiv]
- K. Simonyan, A. Zisserman. Very Deep Convolutional Networks for Large-Scale Image Recognition [arxiv]
- Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun. Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification [arxiv]
- Min Lin, Qiang Chen, Shuicheng Yan. Network In Network [arxiv]