基于卷积神经网络识别手写数字
面对各种AI模型,感觉眼花缭乱,静下心花了一周时间读了《深度学习入门》,觉得讲的很好不得不推荐下,本来是想按照神经网络历史梳理,关键概念,如何实现这样步骤来写,写了一半感觉这样写还不如直接去看书呢,又重新按照我的理解改写一遍,希望能帮到大家。
稍稍介绍下神经网络
说到神经网络大家可能会浮现类似这种图,我第一次也是被这种图吓到的。如果把每条线当作电线,整个图看作一个电网可能会容易理解点,比如现在有这样的问题,我输入随机的电流经过复杂的电网,因为每一条电线的电阻不一样,输出的电压就不一样了,根据以前的经验我知道一些输入电流和对应的输出电压,现在想知道输入全新电流的输出电压值 。
请问这个问题你打算怎么解决呢?不可能一个一个去测电阻,毕竟电线分布的到处都是,还可能埋在地下。
最有可能的方法可能是,先给每个电线电阻估个值(为了方便后续都叫权重了),通过输入已知电流,得到输出电压(假设可以),再跟已知的做比对,如果大了或小了,就调节下权重的值,最后找到最接近的。这就可以看作是训练神经网络的过程。
但是认识只是到这里就太浅了。现在我问一个基本问题,怎么调整权重可以到达目标且最快到达呢?
稍稍提下基本概念
卷积神经网络由很多的基本概念,但是我们要知道这些概念不是突然出现的,都是为了寻找某个问题最优解才提出来的。
回到刚刚提出的问题,怎么调整权重可以到达目标且最快到达呢?答案是最好能够把输出的差距最大化反馈到每个权重上,而且还要知道差距往哪个方向变最快,为了实现这个目的,聪明的数学家(数学家应该没有不聪明的吧),设计了很多函数。
比如使用经过sofeMax函数正规化之后的交叉熵误差函数作为损失函数,可以实现把训练输出值和训练目标值的差值作为梯度传递到权重上,可以理解为当差值越大就更大的传递这个差值,差值越小就更小的传递这个差值。使用激活函数ReLU或Sigmoid,也是为了更好把数据变化传递到权重上。
怎么计算这个数据变化呢?
我们知道数据变化称为导数,对于一个未知数可以看成一条直线导数可以这样表示,对于两个未知数可以看成一个平面,用梯度表示
,计算梯度基本的方法是进行数值微分就是一个一个求导数,但是效率太低了,于是出现了**误差反向传播法, **用于高效计算梯度。
后面又发现沿梯度方向更新参数,在有些情况(比如这个平面是个马鞍形状)梯度方向不是最佳方向,这时候就引进了优化方法,比如SGD、Momentum、AdaGrad、Adam等。
权重的问题算解决了,但是我训练用的数据是历史经验值,怎么保证训练出的模型可以支持预测全新数据。会不会出现只能拟合训练用数据(过拟合) 情况,毕竟获得泛化能力才是机器学习的最终目标(泛化能力是指处理未被学习过的数据的能力)。于是就出现Dropout方法,Dropout 是一种在学习的过程中随机删除神经元的方法,用来解决过拟合问题。
到这里上面电路的问题就可以算解决了,但是这时候又遇到新问题,之前电流的输入,只是一维的数据,那么对于图片这种三维(长+宽+颜色)怎么办呢?
于是卷积神经网络就闪亮登场了,卷积神经网络主要包括卷积层和池化层。
我们之前说神经网络使用的是全连接层,对三维数据需要通过把数组拉平为一维数据,但是这样就丢失了重要的空间信息。卷积层可以保持形状不变。当输入数据是图像时,卷积层会以 3 维数据的形式接收输入数据(又叫输入特征图),并同样以 3 维数据的形式输出至下一层(又叫输出特征图),同时对局部特征(比如边缘、纹理)进行提取,而且每一层只对局部特征进行运算处理,大大减轻了算力压力。
而池化层是从目标区域中取最大值(或者平均值)输出,会吸收输入数据的微小偏差,加强特征输出。
以上神经网络的主要概念我用比较简洁的方式串了下,实际上里面有很多魔鬼般的细节。
卷积神经网络的实现
需要注意的是,以 2012 年为界,之后基于深度学习的方法一直居于首位。实际上,我们发现 2012 年的 AlexNet 大幅降低了错误识别率。并且,此后基于深度学习的方法不断在提升识别精度。
首先介绍下VGG模型,VGG 在 2014 年的比赛中最终获得了第 2 名的成绩,准确率为92.7%。因为 VGG 结构简单,应用性强,所以很多技术人员都喜欢使用基于VGG 的网络。
VGG结构图
书中的模型是参考VGG模型进行了改造,最终准确率达到99.35%,这里使用的卷积层全都是 3 × 3 的小型滤波器,特点是随着层的加深,通道数变大,并且后面的全连接层中使用了 Dropout 层,这个网络使用 He 初始值作为权重的初始值,基于 Adam 的最优化,激活函数使用ReLU。如下图
进行手写数字识别的深度 CNN结构图
代码我整理放在gitee.com/bigtreetime…。
模型参数约1千万,大小1M,对硬件配置要求不高,本人使用的电脑处理器是i7-8750,内存16G。实际训练时,CPU占50%左右,内存6G(包括系统运行内存在内)。
使用CPU训练的,用了4个小时。
效果展示
可以看到准确率在99.35%。识别到的数字为8。
这个是没有识别正确的图片,可以看到这个图对人类也很有难度。