从0到1:神经网络实现图像识别(中)

SIGAI推荐

SIGAI 资源大汇总

SIGAI特邀作者

无双谱JX

作者简介:金融应⽤架构专家

研究⽅向:机器学习的特定场景应用,复杂项目群管理

”. . . we may have knowledge of the past and cannot control it; we may control the future but have no knowledge of it.”

往者可知然不可谏,来者可追或未可知

— Claude Shannon 1959

点击查看:从0到1:神经网络实现图像识别(上)

上篇介绍了神经网络的理论基石 - 感知机(perceptron)模型;感知机模型是一个简洁的二类分类模型,在中篇里,我们把它推广到多类分类问题,不借助计算框架,构建一个全连接神经网络,再应用于MNIST数据集手写数字识别场景。

MNIST数据集

能正确的提出问题,你已经解决了问题的一半。

这里“正确的问题”是MNIST,一个手写数字图片集数据的识别问题。

你可以在 Yann LeCun的官网下载这套数据集,共四个文件包:

train-images-idx3-ubyte.gz: 训练图片集 (9912422 bytes)

train-labels-idx1-ubyte.gz: 训练图片集的正确标签 (28881 bytes)

t10k-images-idx3-ubyte.gz: 测试图片 (1648877 bytes)

t10k-labels-idx1-ubyte.gz: 测试图片的正确标签 (4542 bytes)

每张图片包含一个手写数字。

数据集包含6万张图片用于训练,1万张用于测试验证。

图像数据格式和图向量

每张图片表达了[0,9]这是10个数字中的一个,有28X28=784个像素,每个像素根据灰度取整数值[0,255];把每张图片看作具有784个特征的图向量,问题就变成:根据D个特征维度,对图像做K分类的问题,这里D=784,K=10。

从二分类到多分类问题

一种思路是把 K 类分类问题,视为 K 个二类分类问题:第一次,把样本数据集的某一个类别,和余下的K-1类(合并成一个大类)做二类分类划分,识别出某一类;第 i 次,划分第i类和余下的K-i类;经过 K 次 二类分类迭代,最终完成 K 类分类。

这里,我们选用一种更直接的思路,回忆感知机二类分类模型,只包含了一个输出节点;现在把输出节点扩展为K个 ;权值向量w扩展为 D x K的权值矩阵W,偏置(bias) b扩展为长度为K的数组;这样一来,一个样本点经过模型处理,会得到这个样本点在所有K个类别上的归类可能性得分 z。

z同样是长度为K的数组,某一个元素z [j]的数值越大,输入样本点属于对应分类类别j的可能性也越高。

Softmax

Softmax方法,用于把输出z进一步标准化(normalize),得到某个样本点,归属于各个类别的概率分布;

例如,归属于类别 j 的概率为:

这个结果满足了概率分布的标准化要求:在所有类别上的输出概率都不小0,且所有类别上的输出概率和等于1。

就得到了模型预测输出结果的标准概率分布。

对应的,目标问题MNIST数据集的正确标签,也可以视为一个概率分布;一张手写数字图片,在正确类别上的概率分布视为1,其它类别上为0;数字9的图片,所对应的正确标签为(0,0,0,0,0,0,0,0,0,1),可视为放平之后的分类期望向量

有了预测输出和正确答案的概率分布,就可以刻画两者之间相似度,简便地度量模型预测的损失。

损失函数-交叉熵

经过 Softmax 转换为标准概率分布的预测输出p,与正确类别标签

之间的损失,可以用两个概率分布的 交叉熵(cross entropy)来度量:

所以,某一样本点使用模型预测的损失函数,可以写为

你可以跳过关于交叉熵的展开介绍,从学习算法处继续阅读,不影响方法使用。

再深一点:关于交叉熵

1948年,Claude E Shannon首次提出信息熵(Entropy)概念。

交叉熵(Cross Entropy)的概念来自信息论 :若离散事件以真实概率p(xi)分布,则以隐概率q(xi)分布对一系列随机事件xi做最短编码,所需要的平均比特(bits)长度。其中,定义q(xi)=1/2li,显然,较短的编码长度li,应当被用于出现频度q(xi)较高的编码片段,以提高传输效率。

直观理解,如果有H(p,q')<H(p,q),则相对于qi, 概率分布qi'同真实概率分布pi更相似。

交叉熵对两个概率分布的度量结果,不具对称性,所以交叉熵并不是严格意义上的距离。

交叉熵概念的源头,用比特(bits)信息为单位,以2为底做对数计算,那么用作损失函数Loss时,对数计算是否必须以2为底呢?

不是必须的。

机器学习领域,交叉熵被用来衡量两个概率分布的相似度,交叉熵越小,两个概率分布越相似。工程实践中,出于简化公式推导,或优化数值计算效率的考虑,对数的底可以做出其它选择。

例举以e为底的情况,由换底公式:

可知,对数的底由2换成e,对Loss的影响是,缩小了常数倍 log2e;上一次,我们提到,优化损失函数使损失极小的场景下,函数取值的数值缩放正倍数不影响优化方法。

所以损失函数也可以写为:

学习算法

用上一次介绍的方法,你可以先为 W, b 设置初始值,W随机初始化为很小的值,b初始化为0;然后用梯度下降法( gradient descent),让参数不断更新梯度▽W 和▽b,来极小化损失函数。

对包含D维输入特征的K类分类样例点,根据损失函数计算参数更新的梯度:

, 将Zi,内积运算展开,易得:

对后一部分, 应用链式法则:

从而

同样

得到参数更新的梯度:

其中

反向传播(back propagation)

反向传播(back propagation)是相对前向推断(inference)过程而言的。

抽取训练数据,得到预测分类结果,再使用训练数据的正确标注,计算样本预测损失,然后根据损失更新神经网络模型参数,这个迭代过程就是反向传播方法。

工程实践中,往往从训练样本集中,抽取一批(batch)训练样本,通过整批数据的矩阵运算,得到这批样本损失的均值,减少更新梯度的次数提高训练效率;每轮训练后,使用该批次的梯度均值更新参数,较快得到接近梯度下降的收敛结果。

实现-第一个神经网络

上述算法的python实现,不需要安装Tensorflow计算框架,你可以从算法实现层面,了解一个基础的全连接神经网络的基本结构,跟踪训练过程:

在一千五百次参数更新迭代后,模型参数在验证集上准确率超过90%,五千次迭代后,验证数据集上预测损失(Loss)趋于稳定。

预测准确率(acc)也在验证数据集上稳定在92%附近。

上述算法,可以进一步通过正则化处理,来缓解过拟合风险,降低泛化误差。

过拟合与正则化

在训练数据集上,训练迭代次数不足,模型没有学到训练样本的一般特征,称为欠拟合(under-fitting);

反之,有大量参数的复杂模型,经过多轮训练,会将训练数据中,不具一般性的噪声,也学习到模型参数里,结果在训练数据上得到很好的拟合表现,在未知数据上预测效果却不好,这种情况称为过拟合(Over-fitting)。

通过大量参数,在训练数据上拟合复杂模型,可能很好地反映出训练数据集上的细微特征,也会包括不具一般性的样本噪声,过拟合为模型引入“偏见”,增加了模型的泛化误差。

过拟合的缓解方法,是根据模型的复杂程度,增加罚项(penalty term),使模型的结构风险最小化。

总损失中增加的罚项部分,也称为L2正则化项(regularizer),其中,入是根据模型复杂度设定的罚项系数;乘数0.5用于简化计算;||w||是权值参数w的L2范数,计算方法参见上篇,学习策略部分的介绍。

你可以进一步了解正则化处理,也可以跳到”隐藏层“部分继续阅读,不影响正则化方法的使用。

再深一点:关于正则项

L2正则化的直观效果是:含有相对大分量的权值参数 w,其罚项也越大;各分量相对小而分散权值w,罚项也较小。

例如:

输入向量 x = [1,1,1,1],和两个权值向量 w1=[1,0,0,0], w2=[0.25,0.25,0.25,0.25]。

做内积运算后结果均为1;然而 W1的L2 罚项为1,W2由于各分量相对小而分散,罚项只有0.25。

L2正则化后的模型,倾向于均衡评估输入样本点上全部各个维度的特征,而不是少数大分量值特征对分类结果的影响,来提高模型在测试数据集上的泛化(generalization)能力,缓解过拟合风险。

偏置项 b 是否也需要做正则化处理呢?

不需要。

上面的例子可以看到:输入样本点各个维度特征分量的数值特征,影响了内积计算结果;而偏置 b, 既不参与内积计算,也不对特征分量的数值特征做倍数放大。所以实践中通常只对权值参数 w 做正则化处理。

隐藏层(Hidden Layer)

感知机线性模型能很好的处理上述线性可分样本点的类别划分,却无法处理如下异或类场景的分类问题:

通过引入隐藏层,使模型通过线性组合的方式,支持异或类场景下,样本的分类识别;

原始输入,先经过隐藏层处理,再传递到输出层;隐藏层中的节点,代表了从输入特征中抽取得到的更高层特征。

把新增隐藏层中的节点看作神经元,这些神经元通过自身的激活函数产生神经元输出,使模型可以进一步处理非线性可分场景下的样本分类。

激活函数

这里使用ReLU(Rectified Linear Units)作为激活函数,形式简洁,有如下效果:

单侧抑制,仅激活输出大于阈值0的信号

宽阔的激活边界

稀疏的激活性

随着神经网络深度(隐藏层数)的增加,ReLU降低信号的激活率的作用愈加显著,有助于重要特征的高效提取。

从图像可以看到,ReLU函数不是处处可导的,但是反向传播梯度仍然可以计算,接下来的算法部分会介绍。

以上是ReLU和另一个常用激活函数tanh的图像对比。

下面是不再常用的S型激活函数和softplus激活函数的图像。

算法

由于总损失增加了正则化损失部分:

反向传播时,权值矩阵W的也相应增加了正则化部分梯度:

增加了隐藏层之后,隐藏层的M个节点和输入层节点之间,有了新的权值矩阵 W1和偏置b1;

隐藏层原始输出Zh,激活后表达程为h,作为下一层的输入。

隐藏层到输出层的参数仍然保留,名称改为W2,b2,以方便对应。

隐藏层到输出层参数梯度计算方法不变,以隐藏层输出的M个元素数组h,转置为列向量后,作为输入,

仍然采用交叉熵度量预测损失,W2, b2 反向传播梯度,正则化后,成为:

对 W1, b1 仍然可以设置初始值,然后用梯度下降法( gradient descent),让参数不断更新梯度▽W1 和▽b1,来极小化损失函数。

首先,误差损失 δ 反向传播到隐藏层:

又有

再看激活函数 ReLU(x) =max(0,x),不是处处可导的,但是观察函数性质,当输出为负数时,经过ReLU之后被抑制,其梯度降为0;如果输出为非负数,则导数为1,即误差传递到此处是自变量x本身。

所以实际反向梯度▽h为

得到正则化后,参数更新的梯度:

得到反向传播的全部参数更新梯度。

实现-加入隐藏层

上述算法的python实现,不借助计算框架,在上一次全连接神经网络的基本结构上,增加了正则化处理,缓解过拟合问题,并添加了一个隐藏层和非线性激活函数,使模型能处理异或场景和非线性可分特征,进一步提高识别效果。

以下是设置单隐藏层500个隐藏层节点的训练过程:

验证集上识别正确率稳定在98以上%。

以上,介绍了具有一个隐藏层的全连接神经网络,随着深度(隐藏层)增加,神经网络能在复杂的输入样本上提取更多的特征,得以在一些数据集上,超过了人工识别准确率。

增加深度也带来了新挑战:连接节点和参数过多,导致反向传播训练效率降低,且增加了过拟合风险;下一次,将在目前网络结构的基础上,引入卷积核(Convolutional kernel)处理,使之成为一个卷积神经网络(CNN), 通过进一步实践,了解这一挑战的应对方法。

(中篇完)

动手实践

1. 登陆SIGAI人工智能平台(www.sigai.cn)

2. 点击“在线编程”,进入sharedata

3. 项目代码见nn_base文件夹

4. 在浏览器直接编码运行

5. 在线编程进入较慢,请耐心等候,建议使用Chrome浏览器

参考

[1] 斯坦福大学 class CS231n:The Stanford CS class CS231n

[2] de Boer, PT., Kroese, D.P., Mannor, S. et al. A Tutorial on the Cross-Entropy Method. Ann Oper Res (2005) 134: 19.

原文发布于微信公众号 - SIGAI(SIGAICN)

原文发表时间:2018-12-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券