如何快速使用Python神经网络识别手写字符?(文末福利)

简介: 在本文中,我们将进一步探讨一些使用Python神经网络识别手写字符非常有趣的想法。如果只是想了解神经网络的基本知识,那不必阅读本文,可以先阅读《Python神经网络编程》前面2章节的内容。 这是一个有趣的额外部分,所以节奏会稍微加快一些,但是我们仍然尝试使用简单的语言来解释这些想法。

​点击标题下[异步社区]可快速关注

在本文中,我们将进一步探讨一些使用Python神经网络识别手写字符非常有趣的想法。如果只是想了解神经网络的基本知识,那不必阅读本文,可以先阅读《Python神经网络编程》前面2章节的内容。

这是一个有趣的额外部分,所以节奏会稍微加快一些,但是我们仍然尝试使用简单的语言来解释这些想法。

 1.1 自己的手写数字

在本文中,我们一直使用来自MNIST数据集的数字图片。为什么不使用自己的笔迹呢?

在这个实验中,我们将使用自己的笔迹创建测试数据集。我们也将尝试使用不同的书写风格,使用嘈杂或抖动的图片,来观察神经网络的应对能力如何。

你可以使用任何喜欢的图像编辑或绘画软件来创建图片。不必使用昂贵的Photoshop,GIMP是免费开源的替代软件,适用于Windows、Mac和Linux等系统。甚至可以用一支笔将数字写在纸上,并用智能手机、相机或任何合适的扫描仪,将手写数字变成图片格式。唯一的要求是图片为正方形(宽度等于长度),并且将其保存为PNG格式。在喜欢的图像编辑器中,保存格式选项的菜单通常为“File→Save As”或“File→Export”。

下面是我制作的一些图片。

​数字5就是我的笔迹。数字4是用粉笔而不是马克笔写的。数字3是我的笔迹并有意切成一段一段的。数字2是传统的报纸或书籍字体,但是进行了模糊处理。数字6有意做成抖动的样子,好像是在水中的倒影。最后一张图片与前面的数字相同,但是添加了噪声,来看看我们是否可以增加神经网络的工作难度。

虽然这很有趣,但是这里蕴含了很严肃的一点。人类大脑在遭受损害后,其能力依然能够得到良好发挥,科学家对此深感震惊。这暗示着,神经网络将它们所学到的知识分布在几条链接权重上,也就是说,如果若干链接权重遭受了一定损害,神经网络也可以表现得相当好。这同时意味着,如果输入图像被损坏或不完整,神经网络也可以表现得相当好。这是一种很强大的功能,这就是我们希望用上图中断断续续的3进行测试的能力。

我们需要创建较小的PNG图片,将它们调整到28个像素乘以28个像素,这样就可以匹配曾经用过的来自MNIST数据集的图片。你可以使用图像编辑器做到这一点。

Python库再次帮助了我们,它从常见的图像文件格式中(包括PNG格式)读取和解码数据。看看下面这段简单的代码:​

​scipy.misc.imread()函数帮助我们从图像文件,如PNG或JPG文件中,读取数据。必须导入scipy.misc库来使用这个函数。参数“flatten=True”将图像变成简单的浮点数数组,如果图像是彩色的,那么颜色值将被转换为所需要的灰度。

下一行代码重塑数组,将其从28×28的方块数组变成很长的一串数值,这是我们需要馈送给神经网络的数据。此前,我们已经多次进行这样的操作了。但是,这里比较新鲜的一点是将数组的值减去了255.0。这样做的原因是,常规而言,0指的是黑色,255指的是白色,但是,MNIST数据集使用相反的方式表示,因此不得不将值逆转过来以匹配MNIST数据。

最后一行代码是我们很熟悉的,它将数据值进行缩放,使得它们的范围变成0.01到1.0。演示读取PNG文件的示例代码可以在GitHub上找到:

· https://github.com/makeyourownneuralnetwork/makeyourownneuralnetwork/ blob/master/part3_load_own_images.ipynb

我们需要创建基本的神经网络,这个神经网络使用MNIST训练数据集进行训练,然后,不使用MNIST测试集对网络进行测试,而是使用自己创建的图像数据对网络进行测试。

在GitHub上,可通过如下链接获得新程序:

·https://github.com/makeyourownneuralnetwork/makeyourownneuralnetwork/ blob/master/part3_neural_network_mnist_and_own_data.ipynb

这样做成功了吗?当然成功了。下图总结使用我们自己制作的图像查询的结果。

​可以看到,神经网络能够识别我们创建的所有图像,包括有意损坏的数字“3”。只有在识别添加了噪声的数字“6”时失败了。

使用你自己的图像,尤其是手写的图像试试看,证明你的神经网络确实能够工作。

并且,仔细观察,要将图像损坏或变形到什么程度,神经网络才会失败。神经网络的弹性将会给你留下深刻的印象。

 1.2 神经网络大脑内部

在求解各种各样我们不知道如何使用简约明快的规则解决的问题时,神经网络发挥了重要作用。想象一下,写下一组规则,将这些规则应用于手写数字图像,来确定数字是什么,这件事并不是那么容易,并且我们的尝试也可能不会那么成功。

1.2.1 神秘的黑盒子

一旦神经网络得到了训练,并且在测试数据上表现良好,那么基本上你就拥有了一个神秘的黑盒子。你不知道这个黑盒子如何计算出答案,但是它确实成功地计算出了答案。

如果你只对答案感兴趣,而不真正关心它们如何得出这个答案的,那么对你来说,这就不是一个问题了。但是,我要指出这是这些机器学习方法类型的缺点,即虽然黑盒子(神经网络)已经学会如何求解问题,但是其所学习到的知识常常不能转化为对问题的理解和智慧。

让我们来看看是否可以到神经网络内部一探究竟,是否能够理解神经网络所学习到的知识,将神经网络通过训练搜集到的知识可视化。

我们可以观察权重,这毕竟是神经网络学习的内容。但是,权重不太可能告诉我们太多信息。特别是,神经网络的工作方式是将学习分布到不同的链接权重中。这种方式使得神经网络对损坏具有了弹性,这就像是生物大脑的运行方式。删除一个节点甚至相当多的节点,都不太可能彻底破坏神经网络良好的工作能力。

这里有一个疯狂的想法。

1.2.2 向后查询

在通常情况下,我们馈送给已受训练的神经网络一个问题,神经网络弹出一个答案。在我们的例子中,这个问题是人类的手写数字图像。答案是表示数字0到9中的某个标签。

如果将这种方式反转,向后操作,会发生什么呢?如果馈送一个标签到输出节点,通过已受训练的网络反向输入信号,直到输入节点弹出一个图像,那会怎么样?下图显示了正常的正向查询和疯狂的反向向后查询的想法。

​我们已经知道如何通过网络传播信号,使用链接权重调节信号,在应用激活函数之前在节点处重新组合信号。除了使用的是逆激活函数以外,所有这一切操作也都适用于反向传播信号。如果y = f(x) 是正向激活函数,那么这个函数的逆就是x = g(y)。使用简单的代数,求出逻辑函数的逆,也并非难事:

y = 1 / (1 + e-x)

1 + e-x = 1/y

e-x = (1/y) -1 = (1 - y) / y

-= ln [ (1-y) / y ]

x = ln [ y / (1-y) ]

这就是所谓的对数函数,就像Python为逻辑S函数提供scipy.special.expit()一样,Python中的scipy.special库也提供了这个函数,即scipy.special.logit()。

在应用逆激活函数logit()之前,我们需要确保信号是有效的。这是什么意思呢?还记得吧,逻辑S函数接受了任何数值,输出0和1之间的某个值,但是不包括0和1本身。逆函数必须接受相同的范围0和1之间的某个值,不包括0和1,弹出任何正值或负值。为了实现这一目标,我们简单地接受输出层中的所有值,应用logit(),并将它们重新调整到有效范围。我选择的范围为0.01至0.99。

这段代码在网上始终可用,请访问GitHub以获取:

·https://github.com/makeyourownneuralnetwork/makeyourownneuralnetwork/ blob/master/part3_neural_network_mnist_backquery.ipynb

1.2.3 标签“0”

来看看如果我们使用标签“0”进行反向查询,会发生什么情况。也就是说,我们向输出节点展示了一些值,除了使用值0.99展示给第一个节点表示标签“0”,其余节点都展示了0.01。换句话说,也就是数组[0.99, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01,0.01]。

下图显示了输入节点弹出的图像。

​这真是太有趣了!

这个图像让我们对神经网络的“大脑”有了一种深刻的见解。这个图像是什么意思?该如何解释这个图像呢?

我们注意到最主要的特征是,图像中的圆形。我们是在询问神经网络——对于答案“0”,最理想的问题是什么,因此,这个图像是有道理的。

我们也注意到深色、浅色和一些介中的灰色区域。

·深色区域是问题图像中应该使用笔来标记的部分,这部分图像组成了支持证据,证明答案为“0”,可以这样理解,这些部分看起来组成了0的形状轮廓。

· 浅色区域是问题图像中应该没有任何笔痕的部分,这支持了答案为“0”。同样,可以这样理解,这些部分形成了0形状的中间部分。

· 大体上,神经网络对灰色区域不是很敏感。

因此,粗略来讲,我们实际上已经理解了,针对如何将图像归类为标签“0”,神经网络已经学习到的知识。

这是一种难得的见解,对于较多层、较复杂的神经网络或较复杂的问题而言,可能没有如此容易解释的结果。我们鼓励你进行实验,亲自动手试一试。

1.2.4 更多的大脑扫描

下图显示了其他数字向后查询的结果。

​哇!同样是一些非常有趣的图像,就像使用超声波扫描神经网络的大脑一样。

关于这些图像,我们做了一些注解:

·“7”真的很清楚。可以看到在查询图像中标记的深色位置,强烈暗示了这是标签“7”。也可以看到额外的“白色”区域,这些区域没有任何标记。这两个特点结合起来,指示出了这是“7”。

· 这同样适用于数字“3”,有标记的深色区域指示出了“3”,白色的区域也非常清晰。

·“2”和“5”具有类似的清晰度。

· 数字“4”有点有趣,这个形状出现在4个象限中,是4个互相分隔的区域。

· “8”主要是由“雪人”构成的,这个“雪人”由白色区域形成,表明8的特征在于保持了“头部和身体”区的标记。

· 数字“1”令人相当费解。这看起来好像神经网络较多关注无需标记的区域,而较少关注需要标记的区域。没关系,这就是网络从样本中学到的知识。

· 数字“9”一点都不清楚。它有一个明确的深色区域,还有一些形状相对精细的白色区域。这就是神经网络所学习到的知识,总体来说,当与网络学会的其他数字结合时,这允许神经网络的表现达到了97.5%的准确度。我们观察一下这个图片,并得出结论,有更多的培训样本将有助于神经网络学到更清晰的“9”的模板。

现在,你对神经网络大脑的工作方式应该有了一个深刻的了解了吧。

 1.3 创建新的训练数据:旋转图像

如果思考一下MNIST训练数据,你就会意识到,这是关于人们所书写数字的一个相当丰富的样本集。这里有各种各样、各种风格的书写,有的写得很好,有的写得很糟。

神经网络必须尽可能多地学习这些变化类型。在这里,有多种形式的数字“4”,有些被压扁了,有些比较宽,有些进行了旋转,有些顶部是开放的,有些顶部是闭合的,这对神经网络的学习都是有帮助的。

如果我们能够创造更多的变化类型作为样本,会不会有用处呢?如何做到这一点呢?再多收集几千个人类手写数字样本,对我们来说有点不太容易。我们可以这样做,但是工作量有点大。

一个很酷的想法就是利用已有的样本,通过顺时针或逆时针旋转它们,比如说旋转10度,创建新的样本。对于每一个训练样本而言,我们能够生成两个额外的样本。我们可以使用不同的旋转角度创建更多的样本,但是,目前,让我们只尝试+10和-10两个角度,看看这种想法能不能成功。

同样,Python的许多扩展包和程序库都很有用。ndimage.interpolation.rotate()可以将数组转过一个给定的角度,这正是我们所需要的。请记住,由于我们将神经网络设计成为接收一长串输入信号,因此输入的是784长的一串一维数字。我们需要将这一长串数字重新变成28×28的数组,这样就可以旋转这个数组,然后在将这个数组馈送到神经网络之前,将数组解开,重新变成一长串的784个信号。

假设得到了先前的scaled_input数组,下列代码演示了如何使用ndimage.interpolation.rotate()函数:​

​可以看到,原先的scaled_input数组被重新转变为28乘以 28的数组,然后进行了调整。reshape=False,这个参数防止程序库过分“热心”,将图像压扁,使得数组旋转后可以完全适合,而没有剪掉任何部分。在原始图像中,一些数组元素不存在,但是现在这些数组元素进入了视野,cval就是用来填充数组元素的值。由于我们要移动输入值范围,避免0作为神经网络的输入值,因此不使用0.0作为默认值,而是使用0.01作为默认值。

小型MNIST训练集的记录6(第7条记录)是一个手写数字“1”。在下图中可以看到,原先的数字图片和使用代码生成的两个额外的变化形式。

​可以清楚地看到这种方式的好处。原始图像的版本旋转+10度,提供了一个样本,就像某些人的书写风格是将1向后倾斜。将原来图片的版本顺时针旋转10度更有趣。和原始的版本相比,这个版本在某种意义上是更具代表性的学习图片。

让我们创建新的Python Notebook,使用原来的神经网络代码,不过,现在我们将原始图片朝顺时针和逆时针两个方向旋转10度,作为额外的训练样本,来训练神经网络。这段代码在GitHub上可以得到,请访问以下链接:

·https://github.com/makeyourownneuralnetwork/makeyourownneuralnetwork/ blob/master/part2_neural_network_mnist_data_with_rotations.ipynb

设定学习率为0.1,并且只使用一个训练世代,初始运行神经网络,所得的性能是0.9669。这对于没有使用额外旋转图像进行训练的神经网络的性能0.954而言,是一个长足的进步。这样的表现,和列在Yann LeCeun网站中的记录相比也已经是名列前茅了。

让我们进行一系列的实验,改变世代的数目看看是否能够让已经不错的表现更上一层楼。现在,我们创建了更多的训练数据,可以采用更小、更谨慎的学习步长,因此将学习率减少到0.01,这样就总体上延长了学习时间。

请记住,由于特定的神经网络架构或训练数据的完整性,事情很可能存在内在的限制,因此我们不会期待得到98%或以上的准确度,或者甚至是100%的准确度。我们说“特定的神经网络架构”,意思是在每一层节点数目的选择、隐藏层的选择和激活函数的选择等。

我们旋转训练图像的角度,将其作为额外的训练样本,下图显示了在这种情况下的神经网络的性能。同时,下图也显示了没有使用额外旋转的训练样本时神经网络的性能,以便进行简单的比较。

​可以看到,在5个世代的情况下,最好的结果是0.9745或97.5%的准确度。这再一次打破了我们先前的纪录。

值得注意的是,如果旋转的角度过大,神经网络的性能会出现下降。由于旋转较大的角度意味着创建了实际上不能代表数字的图像,因此神经网络的性能出现了下降,这是可以理解的。想象一下,将“3”向一个方向旋转90度,这就不再是3了。因此,将过度旋转的图像添加到训练样本中,增加了错误样本,降低了训练的质量。对于最大化附加数据的价值,10度看起来是最佳角度。

在10个世代的情况下,神经网络的性能出现了峰值,打破了记录,达到了0.9787,几乎到达98%!对于这种简单的神经网络而言,这是一个惊人的结果,也是最佳的一种状态。请记住,有些人会对神经网络或数据进行一些巧妙的处理,我们还未这样做,我们只是保持简单的神经网络,但是却依然取得了令人骄傲的结果。

​做得好!

 1.4 结语

在本文中,我希望你已经明白,人类能够轻而易举解决的一些问题,对传统计算机而言却难以解决。图像识别就是这些所谓的“人工智能”的挑战之一。

神经网络使图像识别以及广泛的其他各类难题,都获得了空前的进步求解这类难题的早期动力的一个关键性部分是生物大脑,如鸽子或昆虫的大脑,虽然这些生物大脑比起今天的超级计算机似乎简单一些,反应也较慢,但是它们依然能够执行复杂的任务,如飞行、喂食、建设家园。这些生物大脑对损害或对不完美的信号,也非常有弹性。数字计算机和传统计算却不能拥有这种能力。

今天,在人工智能中,神经网络是一些神奇的应用程序成功的关键部分。人们对神经网络和机器学习,特别是深度学习——也就是使用了有层次结构的机器学习方法,依然充满了巨大兴趣。在2016年年初,在古老的围棋对弈领域,谷歌的DeepMind击败了世界级大师。和国际象棋相比,围棋需要更深入的战略,更加微妙,研究人员原本以为计算机需要好几年的时间才能下得好围棋。因此,此次事件成为了人工智能史上一个巨大的里程碑。神经网络在计算机的成功中发挥了关键作用。

我希望你已经明白了,神经网络背后的核心思想其实是非常简单的。我希望你也可以从神经网络的实验中找到乐趣。也许,你已经有了探索其他类型的机器学习和人工智能的兴趣。

如果你做到了这些事情,那么我就算大功告成了。


本文摘自《Python神经网络编程》

​《Python神经网络编程》

 [英]塔里克·拉希德(Tariq Rashid) 著 

点击封面购买纸书


当前,深度学习和人工智能的发展和应用给人们留下了深刻的印象。神经网络是深度学习和人工智能的关键元素,然而,真正了解神经网络工作机制的人少之又少本书用轻松的笔触,一步一步揭示了神经网络的数学思想,并介绍如何使用Python 3.5编程语言开发神经网络

本书将带领您进行一场妙趣横生却又有条不紊的旅行——从一个非常简单的想法开始,逐步理解神经网络的工作机制。您无需任何超出中学范围的数学知识,并且本书还给出易于理解的微积分简介。本书的目标是让尽可能多的普通读者理解神经网络读者将学习使用Python开发自己的神经网络,训练它识别手写数字,甚至可以与专业的神经网络相媲美。

本书适合想要了解深度学习、人工智能和神经网络的读者阅读,尤其适合想要通过Python编程进行神经网络开发的读者参考。

小福利

关注【异步社区】服务号,转发本文至朋友圈或 50 人以上微信群,截图发送至异步社区服务号后台,并在文章底下留言你的开发经验,或者试读本书感受,我们将选出3名读者赠送《Python神经网络编程》1本,赶快积极参与吧!
活动截止时间:2018年4月25日

​在“异步社区”后台回复“关注”,即可免费获得2000门在线视频课程;推荐朋友关注根据提示获取赠书链接,免费得异步图书一本。赶紧来参加哦!

扫一扫上方二维码,回复“关注”参与活动!

阅读原文,购买《Python神经网络编程》

阅读原文

相关文章
|
8天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
8天前
|
程序员 开发者 Python
Python网络编程基础(Socket编程) 错误处理和异常处理的最佳实践
【4月更文挑战第11天】在网络编程中,错误处理和异常管理不仅是为了程序的健壮性,也是为了提供清晰的用户反馈以及优雅的故障恢复。在前面的章节中,我们讨论了如何使用`try-except`语句来处理网络错误。现在,我们将深入探讨错误处理和异常处理的最佳实践。
|
1月前
|
数据采集 存储 XML
深入浅出:基于Python的网络数据爬虫开发指南
【2月更文挑战第23天】 在数字时代,数据已成为新的石油。企业和个人都寻求通过各种手段获取互联网上的宝贵信息。本文将深入探讨网络爬虫的构建与优化,一种自动化工具,用于从网页上抓取并提取大量数据。我们将重点介绍Python语言中的相关库和技术,以及如何高效、合法地收集网络数据。文章不仅为初学者提供入门指导,也为有经验的开发者提供进阶技巧,确保读者能够在遵守网络伦理和法规的前提下,充分利用网络数据资源。
|
1月前
|
数据采集 机器学习/深度学习 安全
Python爬虫之极验滑动验证码的识别
了解极验滑动验证码、特点、识别思路、初始化、模拟点击、识别缺口、模拟拖动。
57 0
|
15天前
|
数据采集 网络协议 API
python中其他网络相关的模块和库简介
【4月更文挑战第4天】Python网络编程有多个流行模块和库,如requests提供简洁的HTTP客户端API,支持多种HTTP方法和自动处理复杂功能;Scrapy是高效的网络爬虫框架,适用于数据挖掘和自动化测试;aiohttp基于asyncio的异步HTTP库,用于构建高性能Web应用;Twisted是事件驱动的网络引擎,支持多种协议和异步编程;Flask和Django分别是轻量级和全栈Web框架,方便构建不同规模的Web应用。这些工具使网络编程更简单和高效。
|
27天前
|
运维 安全 网络安全
Python灰帽子网络安全实践
旨在降低网络防范黑客的入门门槛,适合所有中小企业和传统企业。罗列常见的攻击手段和防范方法,让网站管理人员都具备基本的保护能力。Python 编程的简单实现,让网络运维变得更简单。各种黑客工具的理论和原理解剖,让人知其然更知道防范于未来。涉及互联网和局域网,让企业级网管工作更轻松。涵盖Linux&Windows 的知识点。
14 1
|
29天前
|
消息中间件 网络协议 API
Python语言的进程通讯及网络
Python语言的进程通讯及网络
|
1月前
|
机器学习/深度学习 算法框架/工具 Python
如何使用Python的Keras库构建神经网络模型?
如何使用Python的Keras库构建神经网络模型?
8 0
|
1月前
|
Python
如何使用Python的Requests库进行网络请求和抓取网页数据?
如何使用Python的Requests库进行网络请求和抓取网页数据?
12 0
|
1月前
|
索引 Python
Python 超高频常见字符操作【建议收藏】
Python 超高频常见字符操作【建议收藏】

热门文章

最新文章