NERVANA 已经加入 英特尔
如欲了解关于此话题和 英特尔 Nervana 深度学习框架的更多信息,请查看 Nervana 网站上的 原始文章
简介
在过去几年间,许多深度神经网络 (DNN) 模型用于各种应用,如图像识别和语音翻译。上述模型通常针对特定目标,但是可以进一步扩展,应用于新型使用案例。例如,可以训练模型,以识别图像中的数字和字母,重复使用该模型,在更广泛的模型或数据集(用于自主驾驶)中阅读指示牌。
通过本博文,我们将会:
- 介绍传输学习及一些传输学习应用
- 介绍 neon 在传输学习中的应用
- 介绍示例代码如何利用 neon* 将预训练模型传输到新数据集
- 通过一些结果探索传输学习的价值
传输学习
接触视觉分类任务。卷积神经网络 (CNN) 分为若干层,每一层学习特性的规模各不相同。低级别层识别低级特性,如猫的皮毛或砖墙的纹理。高级别层识别高级特性,如行人移动时的体型或汽车车窗的构造。
针对不同的分类任务,不同规模中学习的特性提供了优秀的特征向量。它们和基于内核的算法(人工操作员开发的)所获取的特征向量截然不同,因为后者通过大量的训练运行进行学习。这些训练运行旨在系统化地改进模型参数,以尽量减少预测输出,yp=f(xt)(xt是真实世界中的信号,f()是模型)和地面实况, yt, 之间的典型错误。
以下几个示例介绍了重复使用 CNN(经受良好训练)所学习的特性。Oquab 等。
[1] 展示了训练 AlexNet 模型识别包含单个对象的图像,其特性可以用于识别真实世界中复杂的图像对象。Szegedy 等。[2] 展示了在一个极为深入的深度神经网络中,半数层所学习的特性可以用于视觉分类。Bell 等。[3] 展示了各种预训练 CNN 学习的材料特性(如木头、玻璃等),例如 AlexNet 和 GoogLeNet 可以完成其他不相关的任务,包括图像分割。预训练网络所学习的特性颇有成效,因为它们捕获了数据中的一般统计、空间一致性与层级元关系。
利用 neon 传输学习
Neon 不仅在训练及推断 DNN 中表现卓越,还提供了丰富的生态系统,支持 DNN 的相关要求。例如,您可以序列化处理学习模型,加载预训练或部分训练模型,选择行业专家构建的 DNN,并在云中运行,无需自备物理基础设施。如欲获取有关 neon API 的全面概述,请访问。
加载模型的预训练权重,并利用以下两行代码在每层获取权重:
from neon.util.persist import load_obj pre_trained_model = load_obj(filepath) pre_trained_layers = pre_trained_model['model']['config']['layers']
然后,在模型中利用以下代码将权重从预学习层传输至兼容层:
[code]layer_of_new_model.load_weights(pre_trained_layer, load_states=True)[/code]
将权重从预学习模型传输至模型中几个指定的层,这个任务变得非常简单:
new_layers = [l for l in new_model.layers.layers] for i, layer in enumerate(new_layers): if load_pre_trained_weight(i, layer): layer.load_weights(pre_trained_layers[i], load_states=True)
就这么简单!您已将预训练模型有选择地传输至 neon。我们将在下文探讨:1) 如何构建新模型,2) 如何有选择地编写代码,尽可能地重复利用 neon 框架,3) 如何在 neon 中快速准确地训练新模型,无需进行大量的全新训练练习。我们将通过实施 Oquab 等人的项目来探索这些问题。[1].
利用单个对象上训练的权重进行一般性场景分类
ImageNet 是非常流行的数据集,训练数据集的图像主要代表了 1000 种不同类型的单个对象。它是一个优秀的数据库,用于获取代表单个对象的特征向量。然而,真实世界的图像更加复杂,针对不同的规模,单个图像捕获的对象产生许多实例。这些场景因为合拢变得更加复杂。在不同规模和合拢程度下,人和牛的示例如下图所示。
通常使用两种技术对此类图像进行分类:1) 使用滑动多量程取样器,对图像的一小部分进行分类,2) 有选择地传输复杂算法发现的区域提议,最后传输至 DNN,进行分类。如欲了解有关利用 Fast R-CNN 实施第二种方法的详细信息[4],请访问。Fast R-CNN 还利用传输学习提升训练速度。本章节将探讨更易实施的第一种方法。如欲了解有关该实施的详细信息,请访问。该实施 dataset利用一个 AlexNet 模型(在 ImageNet 上预训练)dataset,在 Pascal VOC 上进行训练。
实施的核心结构很简单:
def main(): # Collect the user arguments and hyper parameters args, hyper_params = get_args_and_hyperparameters() # setup the CPU or GPU backend be = gen_backend(**extract_valid_args(args, gen_backend)) # load the training dataset. This will download the dataset # from the web and cache it locally for subsequent use. train_set = MultiscaleSampler('trainval', '2007', ...) # create the model by replacing the classification layer # of AlexNet with new adaptation layers model, opt = create_model( args, hyper_params) # Seed the Alexnet conv layers with pre-trained weights if args.model_file is None and hyper_params.use_pre_trained_weights: load_imagenet_weights(model, args.data_dir) train( args, hyper_params, model, opt, train_set) # Load the test dataset. This will download the dataset # from the web and cache it locally for subsequent use. test_set = MultiscaleSampler('test', '2007', ...) test( args, hyper_params, model, test_set) return
创建模型
新型神经网络和预训练 AlexNet 的结构基本相同,有所不同的是,两个仿射层与 dropout 层取代了最后的分类层,使神经网络(针对 ImageNet 的标签进行训练)适应 Pascal VOC 数据集的新标签组。neon 的简化意味着以下代码行(请参阅 create_model())
# train for the 1000 labels of ImageNet Affine(nout=1000, init=Gaussian(scale=0.01), bias=Constant(-7), activation=Softmax())
将被替换为:
Affine(nout=4096, init=Gaussian(scale=0.005), bias=Constant(.1), activation=Rectlin()), Dropout(keep=0.5), # train for the 21 labels of PascalVOC Affine(nout=21, init=Gaussian(scale=0.01), bias=Constant(0), activation=Softmax())
由于我们已经使用预训练模型,只需进行 6-8 次训练。因此,采用的小型学习速度数值为 0.0001。此外,每隔几次将大幅度减少学习,并利用高>动量组件,因为预学习权重已经接近本地最小值。和超参数设置一致:
if hyper_params.use_pre_trained_weights: # This will typically train in 5-10 epochs. Use a small learning rate # and quickly reduce every few epochs. s = 1e-4 hyper_params.learning_rate_scale = s hyper_params.learning_rate_sched = Schedule(step_config=[15, 20], change=[0.5*s, 0.1*s]) hyper_params.momentum = 0.9 else: # need to actively manage the learning rate if the # model is not pre-trained s = 1e-2 hyper_params.learning_rate_scale = 1e-2 hyper_params.learning_rate_sched = Schedule( step_config=[8, 14, 18, 20], change=[0.5*s, 0.1*s, 0.05*s, 0.01*s]) hyper_params.momentum = 0.1
这些强大的超参数通过 create_model() 中的单行代码执行:
opt = GradientDescentMomentum(hyper_params.learning_rate_scale, hyper_params.momentum, wdecay=0.0005, schedule=hyper_params.learning_rate_sched)
多量程取样器
2007 版 Pascal VOC 数据集为每张图像的某些矩形相应区域 (ROI) 提供了标签。Neon 安装了 Pascal VOC 数据集加载器。根据 PASCALVOCTrain 等级创建一个类型,然后创建一个数据集加载器。
依次按照 [1., 1.3, 1.6, 2., 2.3, 2.6, 3.0, 3.3, 3.6, 4., 4.3, 4.6, 5.] 的调整规模,对输入图像进行取样,并收集 448 个补丁。特定规模的取样流程如下所示(请参阅 compute_patches_at_scale()):
size = (np.amin(shape)-1) / scale num_samples = np.ceil( (shape-1) / size)
由于补丁是生成的,而不是地面真实情况衍生而来,需要为补丁分配标签。将 ROI 标签分配给补丁,补丁产生明显重叠。我们选择的重叠标准是单个补丁至少有 20% 的区域与单个 ROI 重叠,ROI 至少有 60% 的区域被重叠区域所覆盖。如果针对特定补丁,有 0 个或多于 1 个 ROI 符合这个标准,将该补丁标记为背景(请参阅 get_label_for_patch())。背景补丁通常占据主导地位。训练过程中,进行偏差取样,以传输更多的非背景补丁(请参阅 resample_patches())。利用 MultiscaleSampler 的 __iter__() 函数全程动态取样。当 neon 要求数据集提供下一批小批次数据时,调用该函数。[1] 的图 4 展示了该过程的动机。
补丁取样方法既能用于训练,也能用于推断。多量程取样器为 neon 传输小批输入和标签数据,而 neon 察觉不到这种 meta 形式的多量程学习。由于每张图像的补丁超过小批尺寸,在训练和推断过程中,一张图像将传输多个小批任务。在训练过程中,我们使用了 neon 配备的 CrossEntropyMulti 函数。在推断过程中,我们使用了 neon 的灵活性来定义成本函数。
推断
通过预测图像中特定对象标签是否存在,在推断过程中进行多类分类。利用指数使分类预测产生偏差,累积所有补丁(从图像上推断出)的偏差值,根据类别进行分类。也就是说,图像 i 类别 c 中 S(i,c) 的得分是类别 c 中单个补丁得分 P(j,c) 的总和(乘以一个指数)。
通过 ImageScores 类别得以实施,分数计算可以用以下两行代码表示(请参阅 __call__()):
exp = self.be.power(y, self.exponent) self.scores_batch[:] = self.be.add(exp, self.scores_batch)
[1] 的图 5 和图 6 展示了该评分技术的原则。
结果
以下是测试数据集的结果。通过平均准确率指标来衡量预测质量。整体平均准确率 (mAP) 的数值是 74.67。对于比较简单的实施来讲,结果令人满意。只进行了 15 次训练,而预训练模型的训练超过 90 次此外,如果将针对预训练模型的超参数优化考虑入内,大大节约了计算。
类别 | 飞机 | 自行车 | 鸟类 | 船 | 瓶子 | 公共汽车 | 汽车 | 猫 | 椅子 | 牛 |
---|---|---|---|---|---|---|---|---|---|---|
AP | 81.17 | 79.32 | 81.21 | 74.84 | 52.89 | 74.57 | 87.72 | 78.54 | 63.00 | 69.57 |
类别 | 餐桌 | 狗 | 马 | 摩托车 | 人类 | 植物 | 羊 | 沙发 | 火车 | 电视 |
---|---|---|---|---|---|---|---|---|---|---|
AP | 58.28 | 74.06 | 77.38 | 79.91 | 90.69 | 69.05 | 78.02 | 59.55 | 81.32 | 82.26 |
不出所料,如下图所示,预训练模型极大加快了训练融合的速度。
以下是关于运行示例的几点有效提示:
- 利用以下命令启动全新训练运行
[code]./transfer_learning.py -e10 -r13 -b gpu –save_path model.prm –serialize 1 –history 20 > train.log 2>&1 &[/code] - 利用以下命令运行测试。务必通过 -e 选项将本命令的规定 epochs 数量设置为 0。这样可确保 neon 跳过训练,直接进入测试。
[code]./transfer_learning.py -e0 -r13 -b gpu –model_file model.prm > infer.log 2>&1 &[/code] - 如果对训练数据集中的 5000 张图像全部进行训练,训练一个 epoch 将花费 4-6 个小时。如果由于某种原因您必须终止训练,利用以下命令,将从上次保存的 epoch 处重新开始训练。
[code]./transfer_learning.py -e10 -r13 -b gpu –save_path train.prm –serialize 1 –history 20 –model_file train.prm > train.log 2>&1 &[/code]
如欲获取本文使用的预训练模型,请访问。
如欲获取传输学习后获得的完全训练模型请访问。
您可以使用训练模型在 Pascal VOC 数据集上分类(通过 AlexNet)。
参考资料
[1] M. Oquab 等。利用卷积神经网络学习与传输中级图像表示,CVPR 2014年。
[2] C. Szegedy 等。重新思考面向计算机视觉的 Inception 架构2015年
[3] S. Bell、P. Upchurch、N. Snavely 和 K. Bala。利用环境数据库里的材料进行野外材料识别。CVPR,2015年。
[4] R. Girshick。Fast R-CNN。2015年。
关于作者:
Aravind Kalaiah 是一名经验丰富的技术负责人,面向实时查询处理和高性能计算构建可扩展分配系统。他是 NVIDIA 的技术负责人,在团队中担任创建工程师,他所在的团队制造了世界上第一台针对大规模并行处理器的调试器。Aravind 曾经在机器学习和计算机视觉领域成立了几家公司,这些公司面向企业和消费者市场,并且表现出良好的创收能力。