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
上篇介绍了神经网络的理论基石 - 感知机(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: 测试图片 (1648877bytes)
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')
交叉熵对两个概率分布的度量结果,不具对称性,所以交叉熵并不是严格意义上的距离。
交叉熵概念的源头,用比特(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), 通过进一步实践,了解这一挑战的应对方法。
(中篇完)
动手实践
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.
领取专属 10元无门槛券
私享最新 技术干货