利用 Neon* 传输学习

NERVANA 已经加入 英特尔

如欲了解关于此话题和 英特尔 Nervana 深度学习框架的更多信息,请查看 Nervana 网站上的 原始文章,以及更多人工智能方面的技术专题

简介

在过去几年间,许多深度神经网络 (DNN) 模型用于各种应用,如图像识别和语音翻译。上述模型通常针对特定目标,但是可以进一步扩展,应用于新型使用案例。例如,可以训练模型,以识别图像中的数字和字母,重复使用该模型,在更广泛的模型或数据集(用于自主驾驶)中阅读指示牌。

通过本博文,我们将会:

  1. 介绍传输学习及一些传输学习应用
  2. 介绍 neon 在传输学习中的应用
  3. 介绍示例代码如何利用 neon* 将预训练模型传输到新数据集
  4. 通过一些结果探索传输学习的价值

传输学习

接触视觉分类任务。卷积神经网络 (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 次此外,如果将针对预训练模型的超参数优化考虑入内,大大节约了计算。

类别飞机自行车鸟类瓶子公共汽车汽车椅子
AP81.1779.3281.2174.8452.8974.5787.7278.5463.0069.57
类别餐桌摩托车人类植物沙发火车电视
AP58.2874.0677.3879.9190.6969.0578.0259.5581.3282.26

不出所料,如下图所示,预训练模型极大加快了训练融合的速度。

以下是关于运行示例的几点有效提示:

  1. 利用以下命令启动全新训练运行
    [code]./transfer_learning.py -e10 -r13 -b gpu –save_path model.prm –serialize 1 –history 20 > train.log 2>&1 &[/code]
  2. 利用以下命令运行测试。务必通过 -e 选项将本命令的规定 epochs 数量设置为 0。这样可确保 neon 跳过训练,直接进入测试。
    [code]./transfer_learning.py -e0 -r13 -b gpu –model_file model.prm > infer.log 2>&1 &[/code]
  3. 如果对训练数据集中的 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 曾经在机器学习和计算机视觉领域成立了几家公司,这些公司面向企业和消费者市场,并且表现出良好的创收能力。

 

有关编译器优化的更完整信息,请参阅优化通知