简介
英特尔® 深度学习 SDK 是一套免费工具,数据科学家和软件开发人员用它开发、训练和部署深度学习解决方案。SDK 包含一个训练工具和一个部署工具,可以独立使用,也可以共同用于整个深度学习工作流程。本篇案例研究不仅介绍了 LeNet*(一种进行手写数字识别的重要图像识别拓扑),还展示了如何利用训练工具在面向英特尔® 架构优化的 Caffe* 上对混合国家标准技术研究所 (MNIST) 数据集进行可视化设置、调试和训练。目标受众是数据科学家。
人类视觉系统和卷积神经网络
在接触英特尔深度学习 SDK 的使用方法之前,了解基本的人类视觉系统工作原理,以及它和计算机神经网络的联系,会有所帮助。神经元是人脑的基本计算单元。它从树突中接收输入,当输入的总和达到一定阙值时,将产生输出,触发相连的神经元。抽象地讲,该生物系统可以由下图表示 [1]:
这是一个极其简化的模型。事实上,人脑通过视觉皮质的若干层来处理输入信号,视觉皮质负责特性提取、特性检测和分类。特性提取是指视觉皮质中的细胞对视域(感受域)中的重叠区域进行二次采样,其作用相当于处理输入图像的过滤器。特性检测发生在皮质层的第 17、19 和 19 号区域,分类集中在第 20、21 号区域。请看下面的图片 [2] 。经过处理的信息通过向前和向后传播传输到之前的层后,才能正确地识别图像。
在卷积神经网络 (CNN) 中,卷积层相当于特性检测器,完全连接层相当于分类器。在运行时处理特性提取时,多个输入集同时经过 CNN (称为小批),然后调整每次迭代的权重,从每个正向传播中聚集特性,在向后传播的过程中微调特性。下面,我们来了解一下 LeNet 拓扑,它是一种用于手写数字识别的重要的 CNN。
LeNet 拓扑
[3] 所发布的 LeNet-5 架构如下所示:
该拓扑共有 7 层(不包括输入):两组卷积层和二次采样层,两层完全连接层和一层输出分类层。
第一个卷积层 C1 有六个特性映射,尺寸为 28´28。选择了带有随机权重和常量偏差的 5´5 内核。在六个特征映射之间,总共构成了 156 个可训练参数(6fm * (5 * 5 + 1[偏项]))。通过每次移动一个像素(跨度等于 1),对特征映射进行重叠区域扫描,在第一层总共形成了 122,304 个连接。您会发现每层的神经元数量都在成倍增长,增长速度会因待解决问题的复杂度不同而有所差别。为了减少计算单元的数量,进行二次采样。在 S2 层中,有 6 个尺寸为 14´14 的特性映射。在相应的特性映射 C1 中取样 2´2 尺寸的像素,添加 4 个输入,然后乘以可训练系数和偏差,从而缩小尺寸。请注意,二次采样(池化)层中的 2´2 区域不相互重叠。因此,在 S2 层中,我们最终获得 12 个可训练参数((系数 + 偏差)* 6 个特性映射)和 5,880 个连接。
下面请看 C3 层。此层共有 16 个特性映射,每个特性映射的尺寸为 10´10。下表介绍了如何减少S2 和 C3 之间的像素数[3]:
从 S2 到 C3 的不对称选择确保了每个特性映射获得不同的像素后,提取不同的特性,同时将连接数量控制在合理的范围内。我将简要介绍下 S4。和 S2 的原理完全一致。
最后,让我们来看一下完全连接层。由于这些属于分类器,在先前层中提取的全部特性用于匹配输入,以提取正确的输出。请记住,在 C1、S1、C2 和 S2 中,选择第一次传播中的随机权重和偏差。根据 CNN 的实际输出评估输入时发现,准确性非常低,这点和我们预想的一样。我们的目标是提高模型的准确性,以实现大多数(即使不是全部)输入的预期输出与提供的标签相匹配。我们的解决方法是采用面向成本函数的梯度下降。简言之,该公式如下所示 [4]:
C 代表成本函数,处理所选的权重和偏差。我们的目标是利用权重“w”和偏差“b”所提取的特性,尽量降低任意输入“x”的实际输出“y”和全部输入“n”的预期输出“a”之间发生错误的可能性。
随后,我们将详细介绍如何在 Caffe 中创建卷积层、池化层和完全连接层,向您展示如何利用英特尔深度学习 SDK 选择梯度和其他超参数。
MNIST 数据集
MNIST 数据集是一个由 7 万张手写数字灰度图像构成的存储库 [5]。每张图像的尺寸为 28´28。该数据集基于两个 NIST 数据集,一个由 Census Bureau 的员工收集,另一个由高中生收集。为了加大数据的差异,最终的 MNIST 集在每个数据集中收集 3 万张图像用于训练,5 千张图像用于测试。
您可以点击此处,获取该数据集。我们使用 MNIST 数据集和上述 LeNet 拓扑,展示英特尔深度学习 SDK 中的训练工具。在开始之前,请确保能够正常处理数据,使类别标签 (0,1…9) 位于目录结构的最高级别,并确保每个文件夹内有相应的图像:
现在,让我们借助英特尔深度学习 SDK,探讨如何训练模型。如果您尚未安装英特尔深度学习 SDK,可以单击 此处立即下载。安装程序包括 Windows* 和 MacOS* 两种版本。安装程序使用 Docker 在Ubuntu* 14.04 设备(或更高版本)的后台安装 SDK。训练程序在面向英特尔架构优化的 Caffe 框架上运行。如需帮助,请参考 [7]。英特尔深度学习 SDK 训练工具提供一个图像用户界面,以操作参数,直观显示训练过程。
利用英特尔® 深度学习 SDK 训练模型
易用性是利用英特尔® 深度学习 SDK 进行模型训练的主要优势之一。作为一名数据科学家,您应该更关注如何轻松准备训练数据,尽可能使用现成的拓扑,在必要时设计新的模型,以及借助自动实验和高级可视化训练模型。该训练工具能提供上述全部优势,还简化了常见的深度学习框架的安装过程。以下是该训练工具的概述:
现在,我们来看一下如何利用现有的拓扑,生成经过训练的模型。首先,通过 IP 地址和安装训练工具的设备端口启动训练用户界面。如果未指定端口编号,默认编号为 8080。输入您在安装过程中创建的用户名和密码,并登录界面。
第一步:上传数据集
在左侧的 Uploads选项卡中选择包含上述标签文件夹和相关图像的数据集 zip 文件。选择文件夹路径,然后单击 Upload。完成后,上传成功的数据集路径可以通过 Completed部分获取。
第二步:创建一个新数据集
选择训练/验证百分比和数据增加
在 Datasets选项卡中单击 New Dataset。命名数据集,并从下拉列表中选择一个已经上传成功的数据集。您可以选择一定比例的数据用于训练、验证和测试。
训练过程的效率取决于数据集的数据可变性,因此,您可以通过某些转换来增加模型的输入,无需改变基本数据集。实用的增加技术包括旋转、双向移位、放大和镜像。请参阅 [8],了解关于每个选项的更多信息。
处理数据
我们所使用的 MNIST 数据集包含 28´28 像素的灰度图像,所以,需要对设置进行相应地调整。如果您需要调整数据的大小,请使用任意一个选项。用户指南包含关于每个选项的更多知识。
选择数据集后端和图像格式
创建数据集
单击Create Dataset。创建完成后,显示训练和测试数据集中每个标签下的数据数量。
第三步创建一个模型
选择数据集
在左侧的 Models选项卡中单击 New Model,然后命名该模型(为了简单起见,我为它选择了与数据集名称相同的名称,您也可以选择其他名称)。
选择拓扑
训练工具目前支持三种图像识别拓扑:LeNet、AlexNet* 和 GoogLeNet*.因为我们针对手写数字识别进行模型训练,我选择了 LeNet,它非常适合这个任务。通过在下面运行的 Caffe* 英特尔® 分发版获取基本数据(卷积层、池化层、完全连接层等的通道数量)。如果您想训练另一种模型,假设使用 Cifar 100* 或 ImageNet 中的彩色图像,可以选择 AlexNet 或 GoogLeNet 进行模型训练。
您也可以基于 LeNet、AlexNet 或 GoogLeNet 创建全新的定制拓扑,具体方法将在后面的部分介绍。
执行数据转换
如果您在训练过程中需要增加一些随机性,可以执行数据转换操作,不会影响数据集中的原始数据。执行数据转换操作的具体步骤详见用户指南。现在,我将使用默认设置。
选择超参数
在此,您选择进行模型微调的设置。某些重要参数包括:
Epoch:通过所有 CNN 层的一次完整传输,数据集中的全部数据文件都经过训练。
批处理尺寸:CNN 数据集通常都很大。为了提高训练效率,数据集被分为包含“x”个图像的批处理。单个批处理通过 CNN 的一次完整的传输被称为一次迭代。大型批处理尺寸可能会降低参数更新过程中的可变性,还会消耗大量内存。因此两者的平衡非常重要。
基础学习速度:在之前讨论的梯度下降算法中,我说过,由于第一次传输的权重和偏差是随机选择的,所以准确率很低。为了实现全局最小值的收敛,我们更改了该算法的基础学习速度。学习速度的提高将加速收敛,但是学习速度过高不利于收敛。另一方面,较低的学习速度更有助于全局最小值的收敛
解析器类型:默认选项是随机梯度下降,在连续批次的输入数据集中随机采集样本,以更快地收敛全局最小值。您也选择采用用户指南描述的其它选项。
现在,您可以开始运行模型了。完成后,将显示每个 epoch 执行的准确性和损失,以及最终训练、验证和测试的准确性。
此时,训练已经完成。需要训练工具生成的 Caffe 文件列表。单击 Download,并保存文件。下面,我们将简要介绍每一种文件,并联系所学的概念。
了解 Caffe* 模型文件
已下载的 model.zip 文件包含了解 CNN 所需的全部文件。如果您想创建自定义拓扑以及调试模型,这些文件非常重要。还可以使用这些文件在部署平台上根据实时数据验证模型。让我们进一步了解这个存档文件中的文件。
最重要的文件是 train_val.prototxt,该文件包含模型的架构 [9]。
数据层
我们看一下数据层的描述。
name:"MNISTLeNet" layer { name:"MNISTFinal" type:"Data" top:"data" top:"label" include { phase:TRAIN } transform_param { mirror: false scale:0.00390625 } data_param { source:"/workspace/dl-genie/jobs/datasets/ca04ddcd-66b2-422d-8de8-dcc1ad38cfd4/train.txt_LMDB" batch_size:64 backend:LMDB } }
上述代码生成两个 blob,由“top”表示:一个面向数据,另一个面向标签。“include”部分表示数据层针对训练阶段创建。由于验证需要相同的结构,您将在 train_val.prototxt 文件中发现另一个数据层,在“include”部分表示测试。下一步,我们对像素进行扩展,使它们全部在 0 到 1 的范围内(通过 1/256 = 0.00390625 来实现)。然后,设置数据源,使其指向创建数据集的 docker 容器。需要指出的是,将后端设置为 LMDB,将批处理尺寸设置为 64,和训练工具显示的一致。
卷积层
layer { name:"conv1" type:"Convolution" bottom:"data" top:"conv1" param { lr_mult:1 } param { lr_mult:2 } convolution_param { num_output:20 kernel_size:5 stride:1 weight_filler { type:"xavier" } bias_filler { type:"constant" } } }
从上述的 LeNet 拓扑可知,第一个卷积层用来输入尺寸为 28´28 的二进制图像。由“bottom:”参数表示,显示数据 blob 为输入。“param”部分表示根据权重和偏差调整学习速度,权重和偏差是该层的可学习参数。将权重的学习速度 (lr_mult:1) 设置为超参数显示的值。将偏差学习速度设置为权重学习速度的两倍。一般来讲,这样做是为了提高收敛速度。
接下来,需要定义卷积层中的通道数量,由“num_output”定义。需要指出的是,此处的通道数量和上述 LeNet 拓扑的通道数量不同。Caffe 框架中的 LeNet 拓扑使用上述 LeNet 算法的一种变体,但是,从概念上讲,它们彼此相似。将 kernel_size 设置为 5´5 像素(和 LeNet-5 相同),通过每次移动一个像素(由“跨度”显示),扫描尺寸为 28´28 的输入图像。还需要指出的一点是,在第一次迭代时,权重和偏差是随机选择的,这些参数学习如何在训练过程中微调特性。本示例中的 weight_filler 设置为“Xavier”,从均匀分布的 [-scale, scale] 中对权重进行取样,其中,scale = sqrt (3/ n);n= 输入的数量。如果您想进一步了解 Caffe 提供的其它类型的 filler,请查看此文件。我们将 bias_filler 设置为常量值 = 0。
二次采样或池化层
layer { name:"pool1" type:"Pooling" bottom:"conv1" top:"pool1" pooling_param { pool:MAX kernel_size:2 stride:2 } }
定义二次采样层相对简单。输入前一个卷积层,选择尺寸为 2´2 的像素区域,按照“stride”的指示移动两个像素,以执行最大池化。这表明不存在重叠区域。通过二次采样,我们得到一个特性映射,其尺寸是第一个卷积层中通道尺寸的一半。
train-val.prototxt 文件包含另外两个部分,列出包含 50 个通道的第二个卷积层和第二个池化层。由于它们类似于上述部分,不在这里探讨。
完全连接层
layer { name:"ip1" type:"InnerProduct" bottom:"pool2" top:"ip1" param { lr_mult:1 } param { lr_mult:2 } inner_product_param { num_output:500 weight_filler { type:"xavier" } bias_filler { type:"constant" } } } layer { name:"relu1" type:"ReLU" bottom:"ip1" top:"ip1" } layer { name:"ip2" type:"InnerProduct" bottom:"ip1" top:"ip2" param { lr_mult:1 } param { lr_mult:2 } inner_product_param { num_output:10 weight_filler { type:"xavier" } bias_filler { type:"constant" } } }
在 Caffe 中,“InnerProduct”指完全连接层。唯一的变化是通道数量设置为 500。修正线性单元 (ReLU) 执行元素智能函数 f(x) = max(0,x)。最后一个完全连接层输出 10 个信号。这是一个二进制信号。激活输出 n (say n= 3) 后,显示经过训练的模型预测输入为 3。
损失层
layer { name:"loss" type:"SoftmaxWithLoss" bottom:"ip2" bottom:"label" top:"loss" }
如前所述,在 CNN 中,将模型准确性向后传播,以调整权重和偏差,更好地进行特性提取和预测。损失层负责在向后传播过程中输入标签 blob 和当前预测、计算损失以及返回数据。
您可以将某些规则应用于层定义。例如,在定义仅限训练过程中的准确层时,您可以使用以下规则:
layer {
name:"accuracy_top5"
type:"Accuracy"
bottom:"ip2"
bottom:"label"
top:"accuracy_top5"
include {
phase:TEST
}
accuracy_param {
top_k:5
}
}
我们来看一下 solver.prototxt 文件。该文件包括利用训练工具界面定义的全部超参数。您可以改变一个或多个参数,来观察训练过程的变化。
# The train/test net protocol buffer definition net:"/workspace/dl-genie/jobs/models/ce7c60e9-be99-47bf-b166-7f9036cde0c8/train_val.prototxt" # test_iter specifies how many forward passes the test should carry out. # In the case of MNIST, we have test batch size 100 and 100 test iterations, # covering the full 10,000 testing images. # The base learning rate, momentum and the weight decay of the network. base_lr:0.01 momentum:0.9 weight_decay:5.0E-4 # The learning rate policy lr_policy:"inv" gamma:1.0E-4 power:0.75 # Display every 100 iterations display:31 # The maximum number of iterations max_iter:12645 # snapshot intermediate results snapshot:843 snapshot_prefix:"/workspace/dl-genie/jobs/models/ce7c60e9-be99-47bf-b166-7f9036cde0c8/snapshot" # solver mode:CPU or GPU solver_mode:CPU type:"SGD"
需要指出的是,在默认情况下,英特尔深度学习 SDK 在 CPU 上运行训练,无需手动配置 Caffe。如果您想在面向英特尔架构优化的 Caffe 上运行训练,请按照 本文的说明进行操作。
您现在已经知道如何解释 Caffe 模型文件,我们来看一下如何利用训练工具界面自定义拓扑。
利用英特尔® 深度学习 SDK 自定义拓扑
我们来回顾一下新模型的创建过程。创建新的模型名称和选择数据集后,转至 Topology选项卡,并选择一个现有的拓扑。在本示例中,我选择的是 LeNet 拓扑。如下所示,单击 edit:
预安装 train_val.prototxt 文件的所选模型文本框显示:
现在,您可以修改卷积层、池化层和完全连接层的参数。.输入新模型的名称,并保存新拓扑。保存成功后,生成自定义拓扑列表,您可以通过列表选择合适的拓扑。
您可以按照上述步骤继续进行训练。训练完成后,训练工具下载的模型文件可用于部署平台,做出实时预测。
参考资料和资源
[1] 利用卷积神经网络进行图像识别
[2] 用于一般图像识别的神经网络架构
[3] 用于文档识别的梯度学习
[4] 利用神经网络识别手写数字
[5] MNIST 数据库
[6] 英特尔® 深度学习 SDK
[9] 利用 Caffe 在 MNIST 上训练 LeNet
[10] 利用面向英特尔® 架构优化的 Caffe* 训练和部署深度学习网络
注
对本文件中包含的软件源代码的提供均依据相关软件许可而做出,任何对该等源代码的使用和复制均应按照相关软件许可的条款执行。
该示例源代码根据“英特尔示例源代码许可协议”发布。