[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

在上周发布的iPhoneX中,最吸引我的,不是那蠢萌的兔耳朵,而是苹果的FaceID。在苹果用FaceID取代TouchID的背后,是强大的视觉算法支持,让iPhoneX有能力识别各种欺骗和伪装,从而敢于将FaceID作为最重要的安全校验手段。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

正如大家所知晓的,深度学习算法最近迅猛发展,推动着人工智能的发展。2012年AlexNet在ImageNet数据集上的成功,使沉寂已久的卷积神经网络(Concolutional Neural Network, CNN)再次获得人们的关注,VGG,ResNet等一系列模型的提出赋予了计算机接近人类的视觉能力。循环神经网络(Recurrent Neural Network, RNN)在自然语言处理和语音识别等领域的应用,突破了传统模型难以把握时序数据的瓶颈。深度学习作为一种基础能力,推动着迁移学习、强化学习等一系列相关学科的发展,当然,这里面也包括了视觉相关的变革。

为此,我们将多个经典的深度学习算法和模型,融入到Jarvis算法库中,并通过Tesla平台给大家使用。目前Jarvis的深度学习类目,已经集成了9种不同算法,分布于如下3大类:

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

本文将会重点介绍计算机视觉领域的几种经典算法,包括其原理、模型和适用场景。其他领域之后也会陆续有文章,请大家要持续关注哟~

计算机视觉概要

计算机视觉是一门研究如何使机器“看懂”世界的科学。计算机视觉采用图像处理、模式识别和人工智能技术相结合的手段,着重于对一幅或多幅图像进行分析,从而获得需要的信息。因此计算机视觉也可以看做是研究如何使人工系统从图像或多维数据中“感知”的科学。具体来说,计算机视觉包含物体的检测和识别、物体跟踪、图像恢复(移除噪声等)和场景重建等。

从2012年Alexnet摘下视觉领域竞赛ILSVRC的桂冠以来,Deep Learning便一发不可收拾,ILSVRC每年都不断被深度学习刷榜。下图中的这些模型,代表了深度视觉领域发展的里程碑。随着模型变得越来越深,Top-5的错误率也越来越低,在Resnet上的结果已经达到了3.5%附近,而在同样的ImageNet数据集上,人眼的辨识错误率大概在5.1%,也就是说深度学习模型的识别能力已经超过了人类。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

经典算法和模型

Alexnet、VGG等网络不仅在ImageNet上取得了很好的成绩,而且还可以被用于其他场景。为了方便用户能灵活快速地训练这些模型,我们在Jarvis中,集成了这些算法。用户可以在Tesla上直接拖出对应算法节点,无需再编写复杂的网络定义和模型训练代码,就可以对相应的图片进行训练,得到一个基本可用的模型。当然了,如果要效果好的话,还是要自己耐心慢慢调试的哈~

1. AlexNet

AlexNet的网络结构如下图所示,可以看到AlexNex在大体结构上仍遵循了传统CNN的原则,由卷积、下采样和全连接层逐一构成。图中诡异的“上下分层”的画法其实是指GPU的并行。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

(https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf)

AlexNet在ImageNet上能取得较好的成绩,除了利用较深和较宽的网络结构来增强学习能力外,在数据处理和训练技巧上还有以下几点值得借鉴:

  • Data Augmentation

Data Augmentation(数据增强)是一种在基础数据上进行一系列操作,从而得到更多数据,来增强数据集的多样性的手段,可以在一定程度上减少过拟合。AlexNet在ImageNet上训练时用到的数据增强方式有以下几种:

水平翻转

随机裁剪

颜色/光照变化等

  • Dropout

Dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。对于随机梯度下降来说,由于是随机丢弃,因此可以看做每一个mini-batch都在训练不同的网络。它是防止网络过拟合,增强模型泛化性的一个有效方法。

下图左边是常见的层连接,每一次dropout都相当于从原始的网络中找到一个更“瘦”的结构,像右图那样。在训练阶段,我们设定一个dropout因子p,范围为0-1,表示在前向计算阶段需要随机断开的连接的比例,并且在反向传播时只更新没有断开的权重值。在测试阶段则需要使用全部的连接,但这些权重都需要乘上1-p。

需要注意的是,每一次的断开和更新都是以p的概率随机实现的,因此每次迭代时的断开都不一样。对于一个有n个节点的神经网络,假设dropout因子p=0.5,那么在前向的次数足够多的情况下,在整个训练过程中会得到2^n种连接组合,也就相当于训练了2^n个模型,最后得到的是2^n个模型的组合。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

(http://blog.csdn.net/stdcoutzyx/article/details/49022443)

ReLU激活函数

ReLu激活函数与传统的Tanh或Logistic函数相比有以下几个优点:

  • 前向计算和反向求偏导的过程都非常简单,没有复杂的指数或除法之类的操作
  • 不像tanh和logistic那样有”flat spot”,因此不容易发生梯度弥散的问题
  • 关闭了左边,可以使很多隐层输出为0,因此使网络变得稀疏,有一定的正则化作用,可以缓解过拟合

Relu函数的缺点也体现在被关闭的左边部分,如果某些节点的输出落在函数左边,那么其将“永无翻身之日”。为了解决该问题后来又出现了pRelu等改进的激活函数,即给函数左边也赋予一定的梯度,在保证非线性的同时不至于让某些节点“死掉”。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

(http://gforge.se/2015/06/benchmarking-relu-and-prelu/)

  • 局部响应归一化(Local Response Normalization,LRN)

神经生物学上有一个概念叫做“侧抑制(lateral inhibitio)”,指被激活的神经元对相邻神经元有一定的抑制作用。

LRN就是借鉴侧抑制的思想来对局部神经元的活动创建竞争机制,使响应比较大的值相对更大,从而提高模型的泛化能力。LRN有两种归一化模式:通道内和通道间,具体可以参考该篇文章。在论文的ImageNet的实验中,LRN可以降低1.2%的top-5错误率,但从我们在其他数据集上的实验来看,LRN提升训练效果并不是那么显著,因此可以看到LRN的操作并不是适用于所有场景的,还是要多实验才能出结果。

  • 交叠的pooling

顾名思义,就是指在做pooling的时候也会存在overlap的部分。一般来说pooling是将输入的结果进行分块处理,通过提取该块的最大值(max pooling)或平均值(average pooling)来实现下采样的过程,这里的块间是相互不交叠的。在AlexNet中却会有overlap的部分。和LRN一样,这个trick不一定适用于所有场景。

综合以上几个技巧,整体来看,AlexNet还是非常经典的一个算法。所以我们将AlexNet集成到Jarvis的深度学习算法的视觉类目下。在实现上,我们根据AlexNet原本的构建和训练方式、参考Alex发表的《One weird trick for parallelizing convolutional neural networksc》这篇文章,做了如下几个事情,包括:

  • 移除了LRN层,并将参数的初始化改成xavier方式。
  • 激活函数使用Relu函数
  • 正则化选择L2正则化
  • 在fc6和fc7两个全连接层使用系数为0.5的dropout操作
  • 自动Resize:在数据的输入上,给定的输入图像是224x224x3的大小,如果读取到的图像大于该尺寸,则会将其随机crop到224x224x3,如果读取到的图像小于该尺寸,则会将其resize到224x224x3。

另外,我们对输入图像也提供了一些data augmentation的操作,包括水平翻转、颜色、光照变化等,文章后部分会有相关参数的描述。

2. VGG16

VGG16继承了alexnet的框架,但其通过加深卷积层数的方法获得了比AlexNet更高的图像识别率,是一种比AlexNet更深的网络结构,如下图所示,更详细的网络结构参数可以参考该论文。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

(https://www.cs.toronto.edu/~frossard/post/vgg16/ )

与AlexNet相比,VGG16明显的不同之处在于:

  • 连续的convolution块和较小的filter size

通过网络结构图可以看到,vgg16中含有多个连续的convolution操作(图中黑色框部分),而这些卷积层的卷积核大小都为3x3,相比AlexNet的7x7小很多。可以理解成VGG通过降低filter的大小,同时增加卷积层数来达到同样的效果。

This can be seen as imposing a regularisation on the 7 × 7 conv. filters, forcing them to have a decomposition through the 3 × 3 filters

较小的卷积核在一定程度上减少了需要训练的权重个数,假设输入和输出的channel数都为C,在7x7大小的卷积核下,该层的权重个数为7x7xCxC=49xCxC,而此时VGG中连续的3个卷积层的权重个数为3x3x3xCxC=27xCxC。权重个数的减少有利于网络的训练和泛化。

  • 通道数(channels)增多

对比AlexNet和VGG可以发现AlexNet的channel数明显小于VGG。如此一来,网络可以对输入提取更丰富的特征。VGG之所以能够达到更高的准确率,与通道数的增多有较大关系。

VGG16也被集成到Jarvis的深度学习算法的视觉模块下。除了网络结构的定义不同外,其他都与Alexnet相似,包括全连接层的dropout设置,Relu激活函数和L2的正则化。

  • 3. VGG19

VGG19和上面小节所述的VGG16其实出自同一篇论文,是一种方法的两种不同配置。VGG19的网络结构与VGG16非常相似,差别在于VGG19在第3、4、5个“卷积块”里分别加多了一个卷积层,因此比VGG16多了3个weight layer。这里就不再赘述。

除了上述的AlexNet和VGG系列的网络结构外,Jarvis还会逐步集成Googlenet,Resnet等,欢迎大家持续关注。

自定义网络

经典算法虽好,但是总会有一定的局限性的。为了提供更好的灵活度,Jarvis上还集成了基于卷积神经网络的分类和回归算法,其最大优点是可以对网络结构进行灵活的自定义,从而满足不同场景下的需求。

在TensorFlow中定义一个卷积+激活层通常需要如下几行代码:

with tf.name_scope('conv2') as scope: 


  kernel = tf.Variable(tf.truncated_normal([5, 5, 96, 256], dtype=tf.float32,stddev=1e-1), name='weights') 


  biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),trainable=True, name='biases') 


  conv2 = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME') 


  conv2 = tf.nn.relu(tf.nn.bias_add(conv2, biases)) 

这还只是一个卷积层的构造,如果我们要构建的网络由十几或者几十层组成,则估计要敲好几百行代码了,而且重点是你就算复制黏贴相同性质的层也不一定找得准眼花缭乱的参数啊。

好在tensorflow也支持一些接口的高级抽象如slim、keras和tensorlayer等,这样一个卷积层就可以一句话写完,比如在slim可以如此定义一个卷积层操作:

net = layers.conv2d(inputs, 64, [11, 11], 4, padding='VALID', scope='conv1')

尽管这些高级接口使网络的定义简便了不少,但如果在训练过程中要多次调整网络结构,这样hardcode的形式则仍然很不方便。

鉴于以上,我们在tesla上实现CNN时,将网络结构单独抽出来作为一个可修改的参数传入到算法中。该网络参数其实是一个json文件,文件中的每一行表示一个层,最后几行表示数据输入的一些信息。

一个CifarNet的网络结构如下图所示:

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

(https://inclass.kaggle.com/c/computer-vision-cs543-ece549)

将该CifarNet转成我们自定义的json文件后示例如下:

{ 


  "layer1" : { "operation": "conv", "maps": 64, "kernel_height": 5, "kernel_width": 5, "stride_height": 1,"stride_width": 1, "padding": "SAME", "activation_func": "relu"},  


  "layer2" : { "operation": "max_pool", "kernel_height": 3,"kernel_width":3,"stride_height": 2,"stride_width":2, "padding": "SAME"},  


  "layer3" : { "operation": "conv", "maps": 64, "kernel_height": 5,"kernel_width":5, "stride_height": 1,"stride_width":1, "padding": "SAME", "activation_func": "relu"},  


  "layer4" : { "operation": "max_pool", "kernel_height": 3,"kernel_width":3, "stride_height": 2,"stride_width":2, "padding": "SAME"},  


  "layer5" : { "operation": "fc", "maps": 384, "dropout_rate": 1.0, "activation_func": "relu"},  


  "layer6" : { "operation": "fc", "maps": 192, "dropout_rate": 1.0, "activation_func": "relu"},  


  "layer7" : { "operation": "fc", "maps": 100}, 


  "initial_image_height": 32, "initial_image_width": 32, 


  "input_image_height": 32, "input_image_width": 32, 


  "normalize": 1,"crop": 1,"whitening": 1,"contrast": 1,"flip_left_right": 1,"brightness": 1 


} 

还有更懒的亲们甚至可以直接复制这份模板,然后按自己的网络定义更改一下里面的参数就可以了。在tesla界面运行时,如果需要修改网络结构,可以直接在界面右边的参数配置编辑该json文件,不需要再修改并上传代码啦~~

基于上述的自定义网络结构的特点,我们配置了CNN的分类和回归两种算法。

1. CNN Classification

基于卷积神经网络CNN的分类算法。支持如上所述的网络结构自定义,可以适应不同场景下的图像分类任务。

2. CNN Regression

基于卷积神经网络CNN的回归算法,与CNN classification类似,区别在于训练时用的是欧氏距离损失函数,可以接受float类型的标签。注意在配置网络结构时最后一层的feature map个数为1,而不是分类中的类别数。

Jarvis视觉算法的使用

目前,Jarvis主要通过Tesla平台透出,其训练和使用都非常简单,总体来说可以分为三个步骤:数据准备、模型训练和模型使用

1. 数据准备

在开始训练前,我们需要准备好训练集和测试集数据。对于目前计算机视觉目录下的算法,输入都为图像数据,并且都需要转换成tfrecord的格式。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

打开Tesla的工作界面,在输入->数据源下拖出数据集节点,点击该节点,完整填写界面右边的参数配置选项,便完成了一个数据节点的配置。转换节点可以加在数据节点之后。为了方便用户使用,我们会提供一个image->tfrecord的转换工具,放在输入->数据转换目录下。

2. 模型训练

在tesla工作流界面从左边的深度学习算法下拖出想要训练的算法节点。点击该节点,右侧会出现参数配置选项,包含算法IO参数,算法参数和资源配置参数。

  • 资源参数

指定模型训练时所需的GPU和CPU资源。

  • 算法IO参数

用于指定数据集、模型存储和Tensorboard保存的ceph路径,这里我们只需要指定数据集所在路径,而模型存储和Tensorboard路径由Tesla默认指定。

如果算法节点上有对应的数据集节点,则该数据集节点的数据路径会自动匹配到算法的数据输入路径,不想拖数据集节点的用户也可以手动填写算法的数据输入路径。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

  • 算法参数

用于指定训练过程中所需的参数。深度学习各算法的参数有一部分是相通的,如批处理大小、学习率和迭代次数等。但不同的算法也可能有自己特殊的参数。在下面的介绍中,我们将会在各算法的详细介绍链接里找到对应的参数解释。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

对于CNN Classification/Regression算法来说,由于支持网络结构的自定义,因此参数与上表会稍有不同。以工作流右侧的参数配置项目为准。

配置完各参数后,右键点击该算法节点,选择起点运行即可开始训练模型。在训练过程中可通过tensorflow控制台查看log信息和tensorboard可视化,便于把握训练走向。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

3. 模型收藏和使用

模型使用指用训练好的模型做预测工作。除了在刚训练完成时对模型做预测外,Tesla还贴心地提供了模型收藏功能,可以留待以后再做预测。

模型收藏:在模型操作下选择收藏模型可以将模型收藏到tesla界面左边的个人模型目录下,下一次需要使用的时候可以直接拖出模型节点,填写相应的配置参数,右键选择起点运行即可。

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

结语

本篇文章介绍了计算机视觉领域比较经典的几种深度学习算法,同时展示了如何在tesla平台上快速灵活地训练和使用深度学习模型。在算法Demo下有各个算法的样例工程供大家参考。

最后,再一次提一下苹果的FaceID。FaceID的成功启用无疑是计算机视觉领域在人类生活应用中的一大进步,其低于指纹解锁的破解率与背后的机器学习尤其是深度学习算法密不可分。当然,FaceID背后的人脸识别技术肯定比本文中简单介绍的几种算法复杂的多,这里我们就不深入探讨了,因为就算你问我我也不知道呀,呵呵~~ 不过,苹果在去年的CVPR上发表了一篇SimGAN的文章《Learning from Simulated and Unsupervised Images through Adversarial Training》,有兴趣的可以看一下。另外,苹果在去年的NIPS上宣布会开始公开他们的研究成果,相信这一决定会给学术界和工业界带来很多惊喜,大家可以期待一下。

最后+1,本文由andymhuang和royalli指导完成,这里表示感谢。如果在使用算法时遇到相关问题,欢迎咨询我(joyjxu)或者royalli,也墙裂欢迎各种批评指正意见!

相关推荐