更新、更全的《机器学习》的更新网站,更有python、go、数据结构与算法、爬虫、人工智能教学等着你:http://www.javashuo.com/article/p-vozphyqp-cm.htmlpython
相信大家外出游玩的时候,都不会带上你的牛逼plus诺基亚手机出门,而是带上你的智能手机给本身美美的拍上一张。当你用手机镜头对准人脸的时候,都会出现一个矩形框,以下图所示(前方高能),那么这个技术是怎么作到的呢?算法
相机中的人脸定位技术用的是二分类技术。该技术流程以下图所示。数据库
如上图所示,相机首先会将照片分割成一块块的图像块,一张照片每每会有成千上万的图像块被切割出来。网络
而后每个图像块都会通过人脸分类器去判别是不是人脸。人脸分类器是预先训练好的分类器,相似于咱们以前讲的手写数字识别应用程序中的支持向量机分类器。若是人脸分类器预测该图像块为人脸,相机则会在这个图像块中显示出框的位置。数据结构
在人脸定位中,为了解决因为手机离人的距离不一样,致使手机上显示的人脸大小不一致的问题。手机在切割图像的时候,并非只用一种尺寸的图像块切割图像,而是有从小到大不少尺寸的图像块,所以保证了图像块切割图像时能涵盖几乎各类大小的人脸。架构
因为相机使用不一样尺寸的图像块判别图像块是否为人脸,所以会致使不一样尺寸、不一样位置的图像块可能同时都被判别为是人脸,所以会有不少重叠框。对于该问题,一般在后期使用后处理融合技术,将这些框融合为一个框。机器学习
在我国古代的时候,人们就对识图认物有了必定的认知。《史记》中曾记载:赵高混淆是非;《艾子杂说》中记载:有人欲以鹘(hú,鹰属猛禽)猎兔而不识鹘,买凫(fú,鸭子)而去,逼凫捉兔,成为笑谈。ide
现在千年以后深度学习技术,可让避免让咱们成为识物盲?函数
曾经讲到鸢尾花分类的时候,咱们给出了分类任务的两个核心步骤:特征提取和特征分类。以下图所示。
上图咱们为了减小麻烦,因此我也直接给出了手工提取特征的图像分类的过程,从图中能够看出在图像分类过程当中,咱们主要停滞在了特征提取的步骤,咱们该如何提取图像的特征,提取什么特征呢?若是要解决上述问题,咱们首先须要把本身当作计算机去看图像。
图像在计算机中的表示以下图所示。
如上图所示,若是将一副计算机眼中的图放大,咱们能够看到一幅图像在计算机眼中就是一个由数字组成的矩形阵列,即矩阵,也正是如此图像才能够存储在计算机中。对于矩阵内的每个元素,咱们称之为像素;而矩阵的行数和列数,咱们称为分辨率。咱们常常说的1280×720分辨率,值得就是这张图由1280行、720列的像素组成的。反之,若是咱们给出一个数字组成的矩阵,而后将矩阵中的每一个元素转换为对应的颜色后,并在电脑屏幕上显示出来,既能够复原出这张图像。
细心的同窗会发现矩阵中的每一个元素都是介于0-255之间的整数。对于上图所示的黑白图像,因为只有明暗的区别,所以只须要一个数字就能够表示不一样的灰度,一般咱们使用0表示最暗的黑色,255表示最亮的白色,因此矩阵的每个元素都是介于0-255之间的整数。
如上图所示,如今咱们最常看到的是彩色图像,彩色图像因为使用(R,G,B)三个数字表示一个颜色,他表示用红(R),绿(G),蓝(B)三种基本颜色叠加的颜色,而且三种颜色也都是介于0-255之间的整数。因为使用三种基本颜色叠加成颜色的明亮程度,如(255,0,0)表示纯红色、(136,200,255)表示天蓝色,因此通常一张彩色图像,须要使用一个由整数的立方体阵列来表示,这样的立方体阵列咱们称之为三阶张量。这个三阶张量的长度与宽度即为图像的分辨率,高度为3。对于黑白图像,他实际上是高度为1的三阶张量。
现在咱们已经了解了计算机眼中的图像,可是仅仅了解了图像并无用。若是如今在你眼前有猫、小鸟和树叶,咱们能够想一想,咱们人类是如何对图片分类的。
经过上图,咱们很容易得出下表,经过“有没有翅膀”和“有没有眼睛”这两个特征对猫、鸟、和树叶分类。如:没有翅膀有眼睛的是猫、有翅膀又有眼睛的是鸟、没有翅膀没有眼睛的是树叶。
特征 | 猫 | 鸟 | 树叶 |
---|---|---|---|
有没有翅膀 | 没有 | 有 | 没有 |
有没有眼睛 | 有 | 有 | 没有 |
因为图像在计算机眼中是一个三阶张量的东西(黑白图像是特殊的三阶张量),因此计算机并不知道图像中的物体有没有翅膀、有没有眼睛。很早以前为了让计算机认识翅膀、认识眼睛,人们一般手工设计各类图像特征,如:设计翅膀图画的颜色、边缘、纹理等性质,而后结合机器学习技术,达到物体识别的目的。
因为图像在计算机眼中能够表示为三阶张量,从图像中提取特征,即对这个三阶张量进行运算的过程。其中咱们最经常使用的运算是卷积。
卷积运算目前在图像处理中有着普遍的应用,他如咱们熟知的加减乘除同样也是一种数学运算。只是参加卷积运算的是向量、矩阵或三阶张量。
如上图所示,两个向量的卷积仍然是一个向量。他的计算过程如上图所示:
卷积结果的维数一般比长向量低,所以有时候咱们为了使得卷积后的结果向量与原始长向量的长度一直,会在长向量的两端补上一些0.对于如上图所示的长向量\((5,4,3,2,1)\),咱们能够将其两端补零变成\((0,5,4,3,2,1,0)\),以后再进行卷积运算,获得结果向量为\((0,22,16,10,0)\)。
经过向量的卷积运算,咱们能够定义矩阵的卷积运算,对于两个形状相同的矩阵,他们的内积是每一个对应位置的数字相乘以后的和,以下图所示。
进行向量的卷积时,咱们只须要朝着一个方向移动;进行矩阵卷积时,咱们一般须要沿着横向和纵向两个方向滑动,以下图所示。
定义矩阵的卷积以后,相似的也能够定义三阶张量的卷积,以下图所示。进行三阶张量的卷积时,当两个张量的通道数相同时(下图的图像和卷积核都为两通道),滑动操做和矩阵卷积同样,只须要在长和宽两个方向进行,卷积的结果是一个通道数为1的三阶张量。
# 卷积计算 import tensorflow as tf sess = tf.InteractiveSession() input_x = tf.constant([ [ [[0., 2.], [8., 0.], [6., 8.], [6., 6.]], [[1., 9.], [2., 2.], [0., 4.], [8., 8.]], [[4., 6.], [2., 4.], [3., 2.], [0., 3.]], [[6., 3.], [4., 1.], [2., 2.], [3., 3.]], ] ], shape=[1, 4, 4, 2]) kernel = tf.constant([ [ [[1.], [0.]], [[0.], [-2.]], [[0.], [2.]], [[-1.], [0.]] ], ], shape=[2, 2, 2, 1]) conv2d = tf.nn.conv2d(input_x, kernel, strides=[ 1, 1, 1, 1], padding='VALID') (sess.run(conv2d)).reshape(3, 3)
array([[ 16., -4., -6.], [ 7., -1., -12.], [ -2., -2., -2.]], dtype=float32)
卷积运算在图像处理中应用十分普遍,许多图像特征提取的方法都会用到卷积。以灰度图为例,灰度图在计算机的眼中被表示为一个整数的矩阵。若是咱们使用一个形状较小的矩阵和这个图像矩阵作卷积运算,就能够获得一个新的矩阵,这个新的矩阵则能够当作是一副新的图像。经过卷积运算获得的新图像有时候比原图更清楚的表示了某些性质,咱们就能够把他当作原图像的一个特征。而这里使用的小矩阵称为卷积核。
经过卷积,咱们能够从图像中提取边缘特征,因此在没有边缘的比较平坦的区域(物体内部),图像像素值的变化较小;因为0偏暗、255偏亮,而横向边缘两侧(物体侧边的两侧)的像素差别明显。以下图所示,咱们利用了卷积核分别计算了原图像上每一个3×3区域内左右像素或上下像素的差值(为了将运算结果以图像的形式展现出来,咱们对运算结果取了绝对值)。
上图咱们使用了三列一、0、-1组成的卷积核与原图像进行卷积运算,能够从图像中提取出竖向边缘
上图咱们使用了三行一、0、-1组成的卷积核,从图像中提取出了横向边缘。
上一节,咱们学会了如何手工设计图像特征,经过手工设计特征的过程能够发现手工设计图像特征是很是慢的,甚至有时候手工设计的图像特征毫无心义,所以致使图像分类的准确率曾经在一段时间内达到瓶颈。
# 2010-1017ImageNet挑战赛最低错误率图例 import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties %matplotlib inline font = FontProperties(fname='/Library/Fonts/Heiti.ttc') plt.style.use('ggplot') years = ['2010', '2011', '2012', '2013', '2014', '人类', '2015', '2016', '2017'] years_index = range(len(years)) error_rates = [28.2, 25.8, 16.4, 11.7, 7.3, 5.2, 4.9, 3.5, 2.3] plt.bar(years_index[:2], error_rates[:2], align='center', color='skyblue', label='传统方法') plt.bar(years_index[2:5], error_rates[2:5], align='center', color='darkcyan', label='深度学习') plt.bar(years_index[5:6], error_rates[5:6], align='center', color='gray', label='人类') plt.bar(years_index[6:], error_rates[6:], align='center', color='darkcyan') plt.xticks(years_index, years, rotation=0, fontsize=13, fontproperties=font) plt.ylabel('分类错误率', fontproperties=font, fontsize=15) plt.title('2010-1017ImageNet挑战赛最低错误率', fontproperties=font, fontsize=20) plt.savefig(fname='2010-1017ImageNet挑战赛最低错误率图例') plt.legend(prop=font) plt.show()
在2012年以后,深度神经网络在Image Net挑战赛(图片识别挑战赛)中大放异彩,如上图所示,也由于深度神经网络的加入,在2015年的Image Net挑战赛中,微软团队研究的神经网络架构将图片识别的错误率下降到了4.9%,首次超过了人类的正确率,而且在2017年,图片分类错误率也达到了2.3%,这也是举办Image Net挑战赛的最后一年,由于深度神经网络已经很好地解决了图片分类的问题。
深度神经网络之因此有这么强大的能力,就是由于他解决了传统图像分类中手工提取特征的缺点,而深度神经网络自己能够自动从图像中学习有效的特征。以下图所示看,以前传统的图像分类系统中,特征提取和分类是两个独立的步骤,而深度神经网络将二者集成在了一块儿。从这个角度来讲,深度神经网络并非在图像分类上作出某种创新,而是对传统的图像分类系统作出了改进与加强。
一个深度神经网络一般由多个顺序链接的层构成。
上述深度神经网络的流程能够理解成咱们平常学习英语的过程
其中句子的语义和句子所表达的思想,即为高级别的抽象的特征。
上图所示的即是一个神经网络架构,该神将网络架构是由2012年得到Image Net挑战赛冠军的Alex Net神经网络架构。这个神经网络架构出现了卷积层、ReLU非线性激活层、池化层、全链接层、softmax归一化指数层等概念,以后会逐一介绍。
这个神经网络由5个卷积层和3个全联接层组成。五个卷积层位于输入层右侧,依次对图像进行变化以提取特征。每一个卷积层以后都会有一个ReLU非线性激活层完成非线性变换。上图5个卷积层中第1、2、五个卷积层以后链接有最大池化层,能够用来下降特征图分辨率。在上述流程中,通过5个卷积层和池化层以后,特征图转换为4096维的特征向量;再通过两次全链接层和ReLU层的变换以后,成为最终的特征向量;最后通过一个全链接层和一个softmax归一化指数层以后,便可获得对图片所属类别的预测。
卷积层是深度神经网络在处理图像时十分经常使用的一种层。当一个深度神经网络以卷积层为主体时,咱们也会把这种深度神经网络称为卷积神经网络。卷积层主要的做用是使用卷积运算对原始图像或者上一层的特征进行变换的层,为了从图像中提取多种形式的特征,咱们一般使用多个卷积核对输入图像进行不一样的卷积操做,以下图所示。
# 卷积计算 import tensorflow as tf sess = tf.InteractiveSession() input_x = tf.constant([ [ [[0., 2.], [8., 0.], [6., 8.], [6., 6.]], [[1., 9.], [2., 2.], [0., 4.], [8., 8.]], [[4., 6.], [2., 4.], [3., 2.], [0., 3.]], [[6., 3.], [4., 1.], [2., 2.], [3., 3.]], ] ], shape=[1, 4, 4, 2]) kernel = tf.constant([ [ [[[1., 1., 1.], [0., 1., 1.]], [[0., 2., -1.], [-2., 0., 0.]]], [[[0., -1., 0.], [2., -1., -2.]], [[-1., -2., 0.], [0., 0., -1.]]] ], ], shape=[2, 2, 2, 3]) conv2d = tf.nn.conv2d(input_x, kernel, strides=[ 1, 1, 1, 1], padding='VALID') (sess.run(conv2d))
array([[[[ 16., 4., -26.], [ -4., 16., -6.], [ -6., 6., -8.]], [[ 7., 0., -8.], [ -1., -8., -6.], [-12., 15., -11.]], [[ -2., -3., 1.], [ -2., 3., -1.], [ -2., -5., -2.]]]], dtype=float32)
从上图能够看出一个卷积核能够获得一个通道为1的三阶张量,多个卷积核就能够获得多个通道为1的三阶张量结果。咱们把这些结果做为不一样的通道组合起来,便可以获得一个新的三阶张量,这个三阶张量的通道数为咱们使用的卷积核的个数。因为每个通道都是从原图像中提取的一种特征,咱们有时候也会把这个三阶张量称为特征图,这个特征图就是卷积层的输出。
也就是说若是一个神经网络有多个卷积层,第一个卷积层以图像做为输入,而以后的卷积层会之前面的层输出的特征图做为输入。
在讲解卷积层的时候,咱们假设图像的分辨率是4*4,可是若是图像或者特征图的分辨率很大,因为卷积核会滑过图像或特征图的每个像素,那么卷积层的计算开销会很大。为了解决这个问题,咱们通常会使用池化层下降特征图的分辨率。最大池化层的步骤以下图所示。
如上图所示:
对每个区块取最大值的池化层,咱们称之为最大池化层;对于取平均值的池化层,咱们称之为平均池化层。上图通过池化层处理,特征图的长和宽都会减少到原来的一半,即特征图的分辨率减少了一半,大大减少了计算开销。
当图像通过多层卷积层处理以后,会将获得的特征图转换为特征向量。全链接层的做用则是对这个特征向量作处理。
在全链接层中,咱们会使用若干维数相同的向量与输入向量(特征向量)作内积操做,而且将全部结果拼成一个向量做为输出。即假设全链接层以一个向量\(X=(x_1,x_2,\cdots,x_n)\)做为输入,咱们会用\(K\)个维数相同的参数(K通常等于类别个数)向量\(W_k=(w_{k1},w_{k2},\cdots,w_{kn})\)与\(X\)作内积运算,而且在每一个结果上面加上标量\(b_k\)(偏置单元),即完成
\(y_k=X·W_k+b_k,k=1,2,3,\cdots,K\)的运算。最后咱们将\(K\)个标量结果\(y_k\)组成向量\(Y=(y_1,y_2,\cdots,y_K)\)做为这一层的输出。
归一化指数层(softmax layer)通常是分类网络的最后一层,它以一个长度和类别个数相等的特征向量做为输入(通常这个特征向量是全链接层的输出),而后输出图像属于各个类别的几率。
再讲非线性激活层以前,咱们首先要回过头去看咱们以前的卷积层和全链接层,咱们能够发现卷积层和全链接层中的运算都是关于自变量的一次函数,即所谓的线性函数。而线性函数有一个性质,若干个线性函数复合时,只是自变量在不断的变化,复合后的函数仍然是线性的。也就是说,若是不使用非线性激活层,咱们只是将卷积层和全链接层直接堆叠起来,那么他们对输入图片产生的效果就能够被一个全链接层替代。如此作的话,咱们虽然堆叠了不少层,但每一层的变换效果实际上被合并到了一块儿。
若是在每次线性计算后,咱们再进行一次非线性运算,那么每次变换的效果将能够保留。神经网络中的非线性激活层方式有不少种,可是他们的基本形式都是对特征图或特征向量中的每个元素,使用某种你非线性函数进行转换,而后获得输出。
Sigmoid函数是较为原始的激活层使用的方法,能够在卷积层将数据扩大以后,把数据压缩在0-1之间。
\[ s(x)=\frac{1}{1+e^{-x}} \]
# Sigmoid激活函数图例 import numpy as np import matplotlib.pyplot as plt x = np.linspace(-10, 10, 100) y = (1/(1+np.e**(-x))) y2 = np.sign(x) plt.hlines(0, -10, 10, alpha=0.3, linestyles='--') plt.plot(x, y, c='r') plt.title('Sigmoid(x)', fontsize=20) plt.show()
双曲正切函数相比较激活函数能够减轻梯度消失的影响。
\[ tanh(x)=\frac{e^x-e^{-x}}{e^{-x}+e^{-x}} \]
# 双曲正切激活函数图例 import numpy as np import matplotlib.pyplot as plt x = np.linspace(-10, 10, 100) y = np.tanh(x) plt.hlines(0, -10, 10, alpha=0.3, linestyles='--') plt.plot(x, y, c='r') plt.title('tanh(x)', fontsize=20) plt.show()
ReLU激活函数以下图所示,ReLu会使一部分神经元的输出为0,这样就形成了网络的稀疏性,而且减小了参数的相互依存关系,缓解了过拟合问题的发生。而且ReLU激活函数将小于零的元素变成零,而保持其他元素的值不变。所以ReLU的计算很是简单,因此他的计算速度每每比其余非线性激活层快不少,而且他在实际应用中的效果很是好,所以在深度神经网络中被普遍的使用。
\[ ReLU(x)= \begin{cases} 0, & x<0 \\ x, & x\geq{0} \end{cases} \]
# ReLU激活函数图例 import numpy as np import matplotlib.pyplot as plt x = np.linspace(-10, 10, 100) y = np.where(x < 0, 0, x) plt.hlines(0, -10, 10, alpha=0.3, linestyles='--') plt.plot(x, y, c='r') plt.title('ReLU(x)', fontsize=20) plt.show()
传统的分类器须要通过训练才能够区分属于不一样类别的特征向量,深度神经网络也须要经过训练才能学习出有效的图像特征,二者相同之处都是在训练的过程当中找打最佳参数的组合。在线性分类器中,参数包括线性函数的全部系数;在神经网络中,卷积层中全部的卷积核的元素值、全链接层全部内积运算的系数都是参数。为了将4个特征的鸢尾花数据分类,咱们只须要训练5个参数;而在Alex Net中,须要学习的参数多达六千万个,其难度远高于线性分类器的训练。所以为了解决神经网络参数多,难训练的问题,科学家们提出了反向传播算法,以下图所示。
反向传播算法的流程为:
随着科技的发展,图像分类技术在平常生活中已经到处可见,有着普遍的应用,如人脸识别、图像搜索等。2014年,香港中文大学团队的工做使得机器在人脸识别任务上的表现第一次超越了人类,今后“人脸识别”也成为了深度学习算法着力研究的任务之一,并在不断的发展和演进中变成了最早实现落地和改变咱们生活的深度学习应用之一。接下来咱们主要介绍图像你分类计数在人脸识别上的应用。
人脸识别是从一张数字图像或一帧视频中,由“找到人脸”到“认出人脸”的过程,其中“认出人脸”就是一个图像分类的任务。人脸识别的整个流程能够包括如下几个步骤:人脸检测、特征提取、人脸对比和数据保存。
话很少说,上图!
经过本章的对神经网络的描述,咱们学习了如下几个知识点: