写点代码识别手写数字I - 构建神经元网络

举报
黄生 发表于 2021/02/10 11:33:50 2021/02/10
【摘要】 看一下识别手写数字的流程,这个图里说明的很清楚了我们不从图中的最左边开始,而是从准备构建神经元网络DNN开始,说到神经元网络,从这个名称听上去就有点玄学了难道人类对于人类大脑里的神经元,都已经研究清楚了?最近看书有看到模型评估里,提出有一点叫“可解释性”,说是比如医疗啊交通啊在AI的应用中,如果出现了不好的结果,要求可以回溯,能够解释为什么会出现问题个人感觉,实际中如果出了问题,承担相应的责...

看一下识别手写数字的流程,这个图里说明的很清楚了

2021-01-22 20-42-29 的屏幕截图.png

我们不从图中的最左边开始,而是从准备构建神经元网络DNN开始,说到神经元网络,从这个名称听上去就有点玄学了
难道人类对于人类大脑里的神经元,都已经研究清楚了?
最近看书有看到模型评估里,提出有一点叫“可解释性”,说是比如医疗啊交通啊在AI的应用中,如果出现了不好的结果,要求可以回溯,能够解释为什么会出现问题
个人感觉,实际中如果出了问题,承担相应的责任就可以了,可解释性就像是找借口。而且这个可解释性,还要和你一样牛的人才有这个沟通基础才能解释的清楚,像我这种基础的,理解就是炼丹和玄学,表现不好时就是不好,有什么好解释的~
写代码是需要工具的,就是IDE
不同领域的编码,一般来说都使用不同的工具,每个领域都有自己优秀的IDE
这样有一点点小烦恼,就是我们学习不同的语言时,要分别去安装不同的IDE
有没有一统天下唯我独尊的IDE呢?没有。虽然也有一些IDE是做成可以通用扩展,来适用不同领域的语言(比如eclipse, vs code等),但比起专注于某一领域的IDE,还是差那么一点
IDE不准备用notebook,notebook适合于学习和分享,但它基本的代码提示和补全功能都没有啊~
也没打算安装专用的IDE,比如pycharm,先偷个懒看行不行
就打算用cloudide了,先试试看
好了开始构建一个神经元网络

import tensorflow as tf
mnist=tf.keras.datasets.mnist
#load后看一下形状如:x_train.shape : (60000,28,28)
(x_train,y_train),(x_test,y_test)=mnist.load_data()


在tensorflow里有一个keras, 在keras里有很多数据集datasets,在数据集里有一个简单的minist数据集,是我们这次要用到的
然后我们用load_data()来装载这个数据集,python里是可以返回多个结果的,比如这里就是2个元组,相对于其他编程语言,python就像是贴心小棉袄
在使用公用数据集时,我们要保持一颗感恩的心,虽然我们很简单的就可以使用到,但要珍惜和感恩他人的工作成果。这里虽然只是一个简单的Minist手写数据集,包含6W张图片,但都是经过辛苦而枯燥的工作,采集清洗整理而形成的,也是不容易的,要珍惜。
在返回的元组(x_train, y_train)中,x_train代表了28x28的6W张图片,y_train代表这6W张图片的标签值,也就是图片对应的数字。
可以来看一个其中的一个图片,在本地应该可以显示图片,但在cloudide里是没有显示的

>>> import matplotlib.pyplot as plt
>>> plt.imshow(x_train[0])
<matplotlib.image.AxesImage object at 0xffff9e4829b0>
>>> y_train[0]  #看一个标签,是数字5,那么x_train[0]展示出来的应该是一张手写着5的图片
5


x_train代表了28x28的6W张图片的数字化表示,我们来看一下它就怎么表示的

>>> x_train[0][0]
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0], dtype=uint8)
>>> x_train[0][14]
array([  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        81, 240, 253, 253, 119,  25,   0,   0,   0,   0,   0,   0,   0,
         0,   0], dtype=uint8)
>>> x_train[59999][14]
array([  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 190, 196,  14,
         2,  97, 254, 252, 146,  52,   0,   0,   0,   0,   0,   0,   0,
         0,   0], dtype=uint8)
>>> x_train[60000][14]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: index 60000 is out of bounds for axis 0 with size 60000


x_train[0]到x_train[59999]代表60000张图片
x_train[0][0]到x_train[0][27]代表第1张图片的所有像素,从第1行的28个像素,到第28行的28个像素,构成28X28的一张图片表达。我猜是这样的
然后是做normalize
就是将每一个像素的表示,从0-255的范围,转换为0-1的范围
但是具体是除以多少做到转换,为什么是除以这个数,还不太清楚


【插播】有一件事情一直是如鲠在喉不吐不快,那就是本来使用cloudide是看中它最起码可以代码提示和补全
但是在代码的过程中,发现好像并不太灵,比如鼠标放在load_data()上,就没有方法的说明提示出来啊?
还好我早有准备,这时终于排上用场了,
参考这个帖子,三步搞定
https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=87626
感谢这个帖子里的大牛,很有效,头二步

mkdir -p ~/.local/virtual-site-packages/
ln -s ~/.local/lib/python3.7/site-packages/tensorflow_core ~/.local/virtual-site-packages/tensorflow


第三步,是按ctrl+,  > workspace > edit in settings.json > 添加以下内容

{
"python.autoComplete.extraPaths": ["/home/user/.local/virtual-site-packages/"]
}


然后就可以完美的做代码提示了

2021-01-31 10-15-20 的屏幕截图.png
【插播结束】



做好了Normalize之后,可以开始构建神经网络和开始训练了
#normalize就是除以?,这样变为0到1之间的数值

x_train=tf.keras.utils.normalize(x_train,axis=1)
x_test=tf.keras.utils.normalize(x_test,axis=1)


compile构建神经网络时,参数很多,这里用到的参数optimizer,loss,metrics,除了metrics能够理解一点它的含义外,其他2个的值都很古怪,
那很古怪不能理解怎么办呢,不理他就可以了

#弄一个Sequential model,将二维展开成一维,作为输入层(28*28=784)
model=tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten())
#二个隐藏层128,最后一个输出层10(10个数字)
model.add(tf.keras.layers.Dense(128,activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(128,activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(10,activation=tf.nn.softmax))
#参数有很多,这里有调权重的优化器optimizer,判断误差的loss,度量的精度metrics
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
#前面构建好网络后,下面可以给数据开始训练,训练5轮
model.fit(x_train,y_train,epochs=5)


执行后的输出如下:

2021-01-31 11:56:35.440747: W tensorflow/core/platform/profile_utils/cpu_utils.cc:98] Failed to find bogomips in /proc/cpuinfo; cannot determine CPU frequency
2021-01-31 11:56:35.442931: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0xaaab06ef0e90 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2021-01-31 11:56:35.442967: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Train on 60000 samples
Epoch 1/5
60000/60000 [==============================] - 9s 142us/sample - loss: 0.2636 - accuracy: 0.9231
Epoch 2/5
60000/60000 [==============================] - 8s 135us/sample - loss: 0.1061 - accuracy: 0.9679
Epoch 3/5
60000/60000 [==============================] - 8s 133us/sample - loss: 0.0737 - accuracy: 0.9766
Epoch 4/5
60000/60000 [==============================] - 8s 132us/sample - loss: 0.0536 - accuracy: 0.9824
Epoch 5/5
60000/60000 [==============================] - 8s 133us/sample - loss: 0.0420 - accuracy: 0.9866


loss<0.1,accuracy>0.9总就是没什么错了吧
网络构建好,并训练好模型后,来看一下模型的效果怎么样?
使用1w条验证数据来看一下模型的效果,loss和accuracy看上去还不错

>>> val_loss,val_acc=model.evaluate(x_test,y_test)
10000/10000 [==============================] - 1s 53us/sample - loss: 0.0935 - accuracy: 0.9742
>>> predictions=model.predict([x_test[:2]])
>>> predictions  #这里是概率值,最大的那个概率值,对应的位置就是推理出的数字了
array([[2.4085142e-11, 3.2256697e-09, 3.2000057e-07, 4.4580301e-07,
        6.9005613e-12, 2.0706119e-09, 3.1649323e-17, 9.9999869e-01,
        1.0085905e-10, 5.1542270e-07],
       [8.3534533e-11, 1.5416379e-05, 9.9998462e-01, 3.3429095e-09,
        5.9164592e-12, 7.3398452e-09, 3.9103174e-08, 2.3795605e-09,
        2.3187214e-09, 8.2146162e-15]], dtype=float32)
>>> import numpy as np
>>> np.argmax(predictions[0])  #科学计数法看起来不是很直观,用numpy的方法来看比较清楚,直接显示概率值最大的那个数
7


因为在cloudide里面没法用matplot看到图片,没法看到图片是不是数字7,但应该是的
模型训练成功后,模型文件如何保存了,这个可以放到modelarts里去跑吗,这些放到后面再摸索一下
验证数据,和测试数据还是有差别的
我自己手写的数字就是属于测试数据。关于手写数字图片的预处理,在下一部分详细说明,这里先直接拿处理好的图片数据来用。
mnist里的test部分,虽然叫做test,但它是验证数据
现在模型有了,测试数据之前也准备并加工好了,来测试一下:

>>> prediction=model.predict(black_white)
ValueError: Input 0 of layer dense is incompatible with the layer: expected axis -1 of input shape to have value 784 but received input with shape [None, 28]
报错了,得按要求的格式来,所以要转换格式后再测试,也就是把二位数组展开,28*28的二维展开为一维783
>>> flattened_img=black_white.reshape(-1,784)
>>> prediction=model.predict(flattened_img)
>>> prediction
array([[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.]], dtype=float32)


结果是那个什么格式的,好像是叫onehot? 第4个是1,说明推理出来的结果就是3
我写的也是3,那就是没错了。
以下为完整代码:

import tensorflow as tf
 
mnist=tf.keras.datasets.mnist
#load后看一下形状如:x_train.shape : (60000,28,28)
(x_train,y_train),(x_test,y_test)=mnist.load_data()
'''
import matplotlib.pyplot as plt
plt.imshow(x_train[0])
'''
 
#normalize就是除以?,这样变为0到1之间的数值
x_train=tf.keras.utils.normalize(x_train,axis=1)
x_test=tf.keras.utils.normalize(x_test,axis=1)
 
#弄一个Sequential model,将二维展开成一维,作为输入层(28*28=784)
model=tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten())
#二个隐藏层128,最后一个输出层10(10个数字)
model.add(tf.keras.layers.Dense(128,activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(128,activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(10,activation=tf.nn.softmax))
#参数有很多,这里有调权重的优化器optimizer,判断误差的loss,度量的精度metrics
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
#前面构建好网络后,下面可以给数据开始训练,训练5轮
model.fit(x_train,y_train,epochs=5)
#model.save("mnist_dnn_model_test.h5")
 
'''
#用test数据做模型验证
val_loss,val_acc=model.evaluate(x_test,y_test)
predictions=model.predict([x_test[:2]])
import numpy as np
np.argmax(predictions[0])
'''
 
import cv2
img=cv2.imread('num2.jpg')
img_width=img.shape[1]
img_height=img.shape[0]
col_start=(int)((img_width - img_height)/2)
col_end=(int)(col_start+img_height)
cropped_img=img[:,col_start:col_end,:]
#cv2.imwrite('n3.jpg',cropped_img)
gray_img=cv2.cvtColor(cropped_img,cv2.COLOR_BGR2GRAY)
(thresh,black_white)=cv2.threshold(gray_img,128,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)
black_white=cv2.bitwise_not(black_white)
black_white=cv2.resize(black_white,(28,28))
#cv2.imwrite('num3.jpg',black_white)
 
flattened_img=black_white.reshape(-1,784)
prediction=model.predict(flattened_img)
#就是我手写的3:array([[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.]], dtype=float32)
prediction


以上学习材料整理来自:MOOC-Python与机器学习初步

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。