神经网络实战:快速构建一个基于神经网络的手写数字识别系统

没吃过猪肉,但得看过猪跑。虽然我们暂时对深度学习及神经网路的基本原理知之甚少,但获得深刻理性认识必须建立在足够的感性认知之上,就像掌握游泳技巧的前提是把自己泡到水里。因此我们在研究分析神经网络的技术原理时,先用代码构建一个实用的智能系统,通过运行后看结果的方式,我们就能快速建立起对深度学习相关技术的感知,这为我们后续建立扎实的理论体系奠定坚实的基础。

神经网络系统的开发一般都使用python语言,我们也不例外,我们的手写数字识别系统将使用python来开发,首先要做的是在机器上安装开发环境,也就是Anacoda。安装好了后,我们需要继续安装开发神经网络最常用的开发框架,这里我们选择Keras,打开控制台,输入下面命令行:

install -c conda-forge keras

这样我们就能自动在Anacoda开发环境里嵌入Keras框架,上面命令运行后如图所示:

我们需要注意的是,要选择Linux系列系统来进行开发,Kares框架对windows的支持不是很好。完成上面开发环境的设置后,我们尽可以着手代码的编写。

首先我们先引入用于训练神经网络的数据集,代码如下:

from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
print(train_images.shape)

这段代码将训练数据和检测数据加载到内存中,train_images是用于训练系统的手写数字图片,train_labels是用于标志图片的信息,test_images是用于检测系统训练效果的图片,test_labels是test_images图片对应的数字标签。代码运行后,情况如下:

第一行打印结果表明,train_images是一个含有60000个元素的数组,数组中的元素是一个二维数组,二维数组的行和列都是28.也就是说,一个首先数字图片的像素大小是28*28。我们打印出来的train_lables数组表明,第一张手写数字图片的内容是数字5,第二种图片是数字0,以此类推。

print(test_images.shape)的结果表示,用于检验系统效果的图片有10000张,print(test_labels)输出结果表明,用于检测的第一张图片内容是数字7,第二张是数字2,依次类推。

接下来我们把用于测试的第一张图片打印出来看看,代码如下:

digit = test_images[0]
import matplotlib.pyplot as plt
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()

上面代码执行后的结果为:

通过我们人眼识别可以看出,图片里面黑色图案表示的确实是一个数字7,我们需要做的就是让计算机也能把它识别出来。接下来我们要使用Keras迅速搭建一个有效识别图案的神经网络,代码如下:

from keras import models
from keras import layers

network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28*28,)))
network.add(layers.Dense(10, activation='softmax'))

我们先将代码相关组件从keras框架里引入,代码里的layers表示的就是神经网络中的一个数据处理层。models.Sequential() 表示我们要把每一个数据处理层串联起来,就好像用一根线把一排珠子串起来一样。神经网络的数据处理层之间的组合方式有多种,串联是其中一种,也是最常用的一种。

layers.Dense(…)就是构造一个数据处理层。input_shape(28*28,)表示当前处理层接收的数据格式必须是长和宽都是28的二维数组,后面的“,“表示数组里面的每一个元素到底包含多少个数字都没有关系,例如:

[
  [1,2], [3,4],
  [5,6], [7,8]
]

表示的就是一个2*2的二维数组,只不过数组的每个元素是一个含有两个数组的一维数组。代码构造了两个数据处理层,接下来我们需要把数据处理层连接起来,并设置网络的其他部分,回想上一节我们提到的神经网络模型:

前面代码完成了上图中,上半部分含有四个矩形的部分,接着我们要完成下半部分,代码如下:

network.compile(optimizer='rmsprop', loss='categorical_crossentropy',
               metrics=['accuracy'])

代码中的输入参数optimizer, loss都对应着上图中相关组件,metrics的含义我们以后再深究。上面代码完成后,整个神经网络就建立好了,接下来我们需要把数据喂给它,以便对它进行训练,在输入数据前,我们需要把数据做一个处理,相关代码如下:

train_images = train_images.reshape((60000, 28*28))
train_images = train_images.astype('float32') / 255

test_images = test_images.reshape((10000, 28*28))
test_images = test_images.astype('float32') / 25

其中reshape(60000, 2828) 的意思是,train_images数组原来含有60000个元素,每个元素是一个28行,28列的二维数组,现在把每个二维数组转变为一个含有28\28个元素的一维数组。由于数字图案是一个灰度图,图片中每个像素点值的大小范围在0到255之间,代码train_images.astype(“float32”)/255 把每个像素点的值从范围0-255转变为范围在0-1之间的浮点值。

接着我们把图片对应的标记也做一个更改,目前所有图片的数字图案对应的是0到9,例如test_images[0]对应的是数字7的手写图案,那么其对应的标记test_labels[0]的值就是7,我们需要把数值7变成一个含有10个元素的数组,然后在第7个元素设置为1,其他元素设置为0,例如test_lables[0] 的值由7转变为数组[0,0,0,0,0,0,0,1,0,0,], 实现这个功能的代码如下:

from keras.utils import to_categorical
print("before change:" ,test_labels[0])
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
print("after change: ", test_labels[0])

上面代码执行后效果如下:

数据格式处理完毕后,我们就把数据输入网络进行训练,这里我们只需要一行代码:

network.fit(train_images, train_labels, epochs=5, batch_size = 128)

上面代码参数需要解析一下,train_images是用于训练的手写数字图片,train_labels对应的是图片的标记,batch_size 的意思是,每次网络从输入的图片数组中随机选取128个作为一组进行计算,每次计算的循环是五次,这些概念我们后面讲解原理时,会详细解释。这句代码运行结果如下:

网络经过训练后,我们就可以把测试数据输入,检验网络学习后的图片识别效果了,代码如下:

test_loss, test_acc = network.evaluate(test_images, test_labels, verbose=1)
print(test_loss) 
print('test_acc', test_acc)

代码运行的结果如下:

运行结果的意思是,用训练后的神经网络判断test_images中的一万张手写数字图案,网络能够正确识别的比率是0.9128,也就是说网络对给定测试图案识别的正确率是91.28%,这个比率不算太高,里面有若干原因,一是神经网络需要运行在GPU上,二是我的个人电脑只有CPU没有GPU,由于硬件的原因影响了识别效果,而是网络训练的强度不够大,后面我们讲解原理时,会体验到网络是如何改进自己的识别效率的。

最后,我们输入一张手写数字图片到网络中,看看它的识别效果,代码如下:

from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
digit = test_images[1]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
test_images = test_images.reshape((10000, 28*28))
res = network.predict(test_images)

for i in range(res[1].shape[0]):
    if (res[1][i] == 1):
        print("the number for the picture is : ", i)
        break

我们把数据重新加载以便调用神经网络对象的predict接口,将要检测的图片数据传入,接口执行后,会把网络的识别结果返回,上面代码完成后,运行效果如下:

我们将识别的第二张图片显示出来,通过肉眼判断它应该是数字2,神经网络识别后给出的结果也是数字2,可见网络经过训练后,具备了足够强的图像识别能力。在没有深度学习算法前,实现这种功能的算法叫OCR,也就是光字符识别,算法的实现异常复杂,而且效果也是很好,而有了深度学习后,不到百行代码就能更好的完成相应功能,这就是深度学习的强大威力。

如果你点击链接后,没有发现名为《人工智能实战:使用深度学习与神经网络构建图像识别与语义分析系统》的课程,那表明视频还在制作和审批中,敬请期待!

原文发布于微信公众号 - Coding迪斯尼(gh_c9f933e7765d)

原文发表时间:2018-01-26

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据科学与人工智能

【Python环境】R vs Python:硬碰硬的数据分析

我们将在已有的数十篇从主观角度对比Python和R的文章中加入自己的观点,但是这篇文章旨在更客观地看待这两门语言。我们会平行使用Python和R分析一个数据集,...

3059
来自专栏木子昭的博客

白话版 动态规划法

关于动态规划法的解释, 大多都是基于背包问题的, 但背包问题背负了很多算法的解释工作,经常让初学者混淆,刚刚刷leetcode的时候,发现了一个很不错的关于动...

37511
来自专栏大数据挖掘DT机器学习

R语言vs Python:数据分析哪家强?

本文章旨在更客观地看待这两门语言。我们会平行使用Python和R分析一个数据集,展示两种语言在实现相同结果时需要使用什么样的代码。这让我们了解每种语言的优缺点,...

1.2K11
来自专栏Petrichor的专栏

深度学习: 局部响应归一化 (Local Response Normalization,LRN)

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

8784
来自专栏数值分析与有限元编程

Newton–Raphson法解串联弹簧问题

如图所示的串联弹簧,F=100,弹簧刚度为k1 = 50 + 500u ,k2 = 100+ 200u ,u是弹簧伸长量,则平衡方程为 ? ? k1,k2带入得...

2856
来自专栏鸿的学习笔记

写给开发者的机器学习指南(七)

Classifying email as spam or ham (NaiveBayes)

1221
来自专栏微信模式识别中心技术分享

“变形金刚”为何强大:从模型到代码全面解析Google Tensor2Tensor系统

      Tensor2Tensor(T2T)是Google Brain Team在Github上开源出来的一套基于TensorFlow的深度学习系统。该系统...

2.9K9
来自专栏机器学习算法工程师

LightGBM大战XGBoost,谁将夺得桂冠?

如果你是一个机器学习社区的活跃成员,你一定知道 **提升机器**(Boosting Machine)以及它们的能力。提升机器从AdaBoost发展到目前最流行的...

3283
来自专栏祁旭翔的专栏

【 SPA 大赛】win10 python3.5.X 下开启 lightgbm 支持

GBDT (Gradient Boosting Decision Tree) 是机器学习中一个长盛不衰的模型,其主要思想是利用弱分类器(决策树)迭代训练以得到最...

3.3K0
来自专栏Python攻城狮

Python数据科学(九)- 使用Pandas绘制统计图表1.信息可视化

因为人对图像信息的解析效率比文字更高,所以可视化可以使数据更为直观,便于理解,使决策变得高效,所以信息可视化就显得尤为重要。

1103

扫码关注云+社区

领取腾讯云代金券