基于TensorFlow卷积神经网络与MNIST数据集设计手写数字识别算法

Python之王

共 9376字,需浏览 19分钟

 ·

2021-12-27 15:35


随着数字化的普及和信息技术的发展,在编号处理、数量读取、价格统计等场合,手写数字识别系统的应用需求越来越强烈,如何将数字方便、快速地输入到计算机中已成为关系到计算机技术普及的关键问题。数字识别技术的研究不仅可以解决当下面临的数字识别问题,同时在图像识别、机器学习等方面也有铺垫作用。由于手写数字识别难于建立精确的数学模型,本文基于TensorFlow卷积神经网络设计手写数字识别算法,导入MNIST数据集进行训练,并测试网络模型的识别准确率。

TensorFlow

TensorFlow是一个基于Python和基于数据流编程的机器学习框架,由谷歌基于DistBelief进行研发,并在图形分类、音频处理、推荐系统和自然语言处理等场景下有着丰富的应用。2015年11月9日,TensorFlow依据Apache 2.0 开源协议开放源代码。

TensorFlow具有灵活的架构,可部署于各类服务器、PC终端、移动设备和网页并支持GPU和TPU高性能数值计算,提供了各类主流编程语言的API。

数据流图中用“结点”(nodes)和“线”(edges)的有向图来描述数学计算。这些数据“线”可以输运“size可动态调整”的多维数据数组,即“张量”(tensor)。张量从图中流过的直观图像是这个工具取名为“TensorFlow”的原因。一旦输入端的所有张量准备好,节点将被分配到各种计算设备完成异步并行地执行运算。

Tensor和Flow是TensorFlow最为基础的要素。Tensor意味着data;Flow意味着流动,意味着计算,意味着映射,即数据的流动,数据的计算,数据的映射,同时也体现数据是有向的流动、计算和映射。

MNIST

MNIST是一个经典的计算机视觉数据集,来自美国国家标准与技术研究所(NIST),由纽约大学的Yann LeCun教授主导建立。

MNIST数据集由250个不同的人手写而成,包含各种手写数字图片,以及每一张图片对应的数值标签。它包含60000个训练样本和10000个测试样本,每个样本都是一张28 * 28像素的灰度手写数字图片,存储在28 * 28的二维数组中。

MNIST数据集在深度学习中的地位,就像Hello,World!在编程中的地位。

自建立以来,它便被广泛应用于检验各种机器学习算法、测试各种模型,为机器学习的发展做出了不可磨灭的贡献,其当之无愧为历史上最伟大的数据集之一。

MNIST数据集已经被集成在Keras中,可以直接使用keras.datasets来访问。

环境安装与数据集

(1)环境信息

  1. Python 3.81. Visual C++库1. Conda包管理工具

(2)查看NVIDIA驱动版本

nvidia-smi
cac7b67044d2d2302ddac36b71b2cdb9.webp



电脑的NVIDIA驱动版本高于418.x,故可以安装GPU版本。

(3)GPU版本的依赖库安装

  1. 安装CUDA Toolkit
conda install cudatoolkit=10.1
f0f9ba4aec72f5276f785d5627d69635.webp

(之前已经安装好了)

2.安装cuDNN库

conda install cudnn=7.6.5
45ac44572b72ebb80c4cec9c8e25d9ac.webp

(4)Conda配置文件

3ea0c095a5a13d7d3318c840d080bb49.webp

5ad00254238008184484731cba6c10d5.webp

(5)下载安装tensorflow-gpu

pip install tensorflow-gpu -i https://pypi.douban.com/simple
dbb3cf707053872ce013d2a64bc1feb0.webp

(6)安装matplotlib和jupyter notebook

pip install matplotlib notebook -i https://pypi.douban.com/simple
ebbf6268c1222938a18f498f2c17938d.webp

(7)使用可视化终端

jupyter notebook
7546961a4d7bff968fce38864af7c4f9.webp
  1. 查看Tensorflow版本7e0946da7704d9b126547f21159d72a1.webp

安装版本是2.3.1。

2.测试GPU版本是否正确安装

f53cabc1dcd098edb939d9913126b959.webp

结果为True,安装正确。

算法原理与设计

(1)加载MNIST数据

(2)定义变量

  1. 定义占位符placeholder     通过shape参数,TensorFlow能够自动捕捉因数据维度不一致导致的错误。

2.定义权重和偏置Variable

(3)构建多层卷积网络

整个网络由两个卷积层(包含激活层和池化层),一个全连接层,一个Dropout层和一个Softmax层组成。

**      1.权重初始化**

**      2.卷积和池化 **

卷积是提取特征的过程。将输入图片,处理就很困难。

池化来把卷积结果进行压缩,进一步减少全连接时的连接数。这里采用最大池化,在选中区域中找最大的值作为抽样后的值。

3.密集连接层

Reshape为向量,建立第一个全连接层。

**     4.Dropout层**

**     5.Softmax层**

** 6.训练和评估模型**

计算交叉熵、梯度下降法、精确度计算。再使用Saver,将训练的权重和偏置保存下来,在评价程序中可以再次使用。最后训练100次,进行验证。

使用过程

(1)测试Tensorflow是否安装成功、MNIST数据集是否可以成功调用

**        1.下载MNIST数据集**

#导入tensorflow库  
import tensorflow as  
#mnist数据集的完整前缀和名称    
mnist=tf.keras.datasets.mnist  
#使用minist数据集的load_data( )加载数据集  
(train_ x,train y), (test_ x,test_ y) = mnist.load_data( )  
#在第一次执行时本地磁盘中没有这个数据集会自动的通过网络下载,并显示地址和进度。

5d7500314fc3e537f0999bdca63bb428.webp

**   2.训练集和测试集的长度**

print("Training set:",len(train_ x))
print(" Testing set:",len(test X))  

1cbe03d747c80c4afc15dbeb78233776.webp

** 3.输出图像数据和标记数据的形状**

print("train_ x:",train_ x. shape, train_x.dtype)  
print("train_ y:",train_y. shape, train_ y.dtype)


0368068e970fe392c94234a9c1e521e2.webp

图像数据是一个三维数组,有60000个样本,每一个样本是一个28 * 28的二维数组,是8位无符号整数。

标签是一个一维数组,对应60000个数据值,是8位无符号整数。

4.输出数据集中的第一个样本

train_x[0]

大量的0,其中不为0的表示笔画。

5.显示图片

导入matplotlib内的pyplot方法  
import matplotlib.pyplot as plt  
plt.axis("off")  
用imshow方法来显示图片,参数为数据集的第一个样本  
plt.imshow(train_x[0],cmap='gray')  
plt.show  


03f06d4e0b8e0fc5111c5c4eba9a6739.webp
train_y[0]

0b16b38feda42a46965453fa91013f42.webp

输出这个图片的标签,结果是5,表明这个图像是数字。

6.测试

随机显示4幅手写数字图片:

  #循环四次  
  for i in range(4):  
  #随机产生一个1到60000之间的整数,作为样本的索引值     
      num=np.random.randint(1,60000)  
      #将画布划分为一行四列的四个子图局域,依次绘制子图  
      plt.subplot(1,4,i+1)  
      plt.axis("off")  
  #imshow函数显示图像,参数为训练集中随机生成的样本  
      plt.imshow(train_x[num],cmap=gray’)  
  #将图像的标签显示在子图标题位置  
      plt.title(train_y[num])  
  #显示整个绘图  
  plt.show()  


测试结果:

d6563cb7ece34306ecb9bda68fd627bd.webp

第二次测试结果:

ba8d9623e4413252c431602b98b8a37a.webp

(2)创建MNIST数据集模型

用于导入MNIST数据集-创建模型-保存模型到指定路径。

(1)源代码:

**         1.创建MNIST数据集模型**

  from tensorflow.examples.tutorials.mnist import input_data  
    
  import tensorflow.compat.v1 as tf  
  tf.disable_v2_behavior()  
    
  mnist = input_data.read_data_sets(r'D:\All_Downloads\TIM_Downloads\AI\MNIST_data', one_hot=True) #MNIST数据集所在路径  
    
  x = tf.placeholder(tf.float32, [None, 784])  
    
  y_ = tf.placeholder(tf.float32, [None, 10])  
    
    
  def weight_variable(shape):  
      initial = tf.truncated_normal(shape,stddev = 0.1)  
      return tf.Variable(initial)  
    
  def bias_variable(shape):  
      initial = tf.constant(0.1,shape = shape)  
      return tf.Variable(initial)  
    
  def conv2d(x,W):  
      return tf.nn.conv2d(x, W, strides = [1,1,1,1], padding = 'SAME')  
    
  def max_pool_2x2(x):  
      return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')  
    
  W_conv1 = weight_variable([5, 5, 1, 32])  
  b_conv1 = bias_variable([32])  
    
  x_image = tf.reshape(x,[-1,28,28,1])  
    
  h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)  
  h_pool1 = max_pool_2x2(h_conv1)  
    
  W_conv2 = weight_variable([5, 5, 32, 64])  
  b_conv2 = bias_variable([64])  
    
  h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)  
  h_pool2 = max_pool_2x2(h_conv2)  
    
  W_fc1 = weight_variable([7 * 7 * 64, 1024])  
  b_fc1 = bias_variable([1024])  
    
  h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])  
  h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)  
    
  keep_prob = tf.placeholder("float")  
  h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)  
    
  W_fc2 = weight_variable([1024, 10])  
  b_fc2 = bias_variable([10])  
    
  y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)  
    
  cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))  
  train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)  
  correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))  
  accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))  
    
  saver = tf.train.Saver() #定义saver  
    
  with tf.Session() as sess:  
      sess.run(tf.global_variables_initializer())  
      for i in range(20000):  
          batch = mnist.train.next_batch(50)  
          if i % 100 == 0:  
              train_accuracy = accuracy.eval(feed_dict={  
                  x: batch[0], y_: batch[1], keep_prob: 1.0})  
              print('step %d, training accuracy %g' % (i, train_accuracy))  
          train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})  
      saver.save(sess, 'D:/All_Downloads/TIM_Downloads/AI/MNISTDataModel/model.ckpt'#模型储存位置  
    
      print('test accuracy %g' % accuracy.eval(feed_dict={  
          x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))  


** 2.运行结果**f6ce057399e3e660e9eadaa876438745.webp

6fb014cb10b5586e4f3e0defbc9ef67e.webp

ae7ca904772347c6857f3b90d6785b4a.webp

00d36d4ad1b98a76cf5e418979c899aa.webp

136e7172529beb0f8c0db5223f3211bd.webp

73358196d14ac0c59fef1e6fc05b24a7.webp

生成的模型准确率高达99.19%。

(3)测试刚创建的模型

1.源代码

  from PIL import Image, ImageFilter  
  import tensorflow.compat.v1 as tf  
  tf.disable_v2_behavior()  
  import matplotlib.pyplot as plt  
  import time  
    
  def imageprepare():  
      ""
      This function returns the pixel values. 
      The imput is a png file location. 
      "
""  
      file_name='C:/Users/14796/Tensorflow_DataSet/MNIST/4.png'#导入自己的图片地址  
      #in terminal 'mogrify -format png *.jpg' convert jpg to png  
      im = Image.open(file_name)  
      plt.imshow(im)  
      plt.show()  
      im = im.convert('L')  
    
      im.save("C:/Users/14796/Tensorflow_DataSet/MNIST/sample.png")  
        
        
      tv = list(im.getdata()) #get pixel values  
    
      #normalize pixels to 0 and 1. 0 is pure white, 1 is pure black.  
      tva = [ (255-x)*1.0/255.0 for x in tv]   
      print(tva)  
      return tva  
    
    
    
      ""
      This function returns the predicted integer. 
      The imput is the pixel values from the imageprepare() function. 
      "
""  
    
      # Define the model (same as when creating the model file)  
    
  result=imageprepare()  
    
    
  x = tf.placeholder(tf.float32, [None, 784])  
    
  y_ = tf.placeholder(tf.float32, [None, 10])  
    
    
  def weight_variable(shape):  
      initial = tf.truncated_normal(shape,stddev = 0.1)  
      return tf.Variable(initial)  
    
  def bias_variable(shape):  
      initial = tf.constant(0.1,shape = shape)  
      return tf.Variable(initial)  
    
  def conv2d(x,W):  
      return tf.nn.conv2d(x, W, strides = [1,1,1,1], padding = 'SAME')  
    
  def max_pool_2x2(x):  
      return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')  
    
  W_conv1 = weight_variable([5, 5, 1, 32])  
  b_conv1 = bias_variable([32])  
    
  x_image = tf.reshape(x,[-1,28,28,1])  
    
  h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)  
  h_pool1 = max_pool_2x2(h_conv1)  
    
  W_conv2 = weight_variable([5, 5, 32, 64])  
  b_conv2 = bias_variable([64])  
    
  h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)  
  h_pool2 = max_pool_2x2(h_conv2)  
    
  W_fc1 = weight_variable([7 * 7 * 64, 1024])  
  b_fc1 = bias_variable([1024])  
    
  h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])  
  h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)  
    
  keep_prob = tf.placeholder("float")  
  h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)  
    
  W_fc2 = weight_variable([1024, 10])  
  b_fc2 = bias_variable([10])  
    
  y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)  
    
  cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))  
  train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)  
  correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))  
  accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))  
    
  saver = tf.train.Saver()  
  with tf.Session() as sess:  
      sess.run(tf.global_variables_initializer())  
      saver.restore(sess, "SAVE/model.ckpt"#使用模型  
      #print ("Model restored.")  
    
      prediction=tf.argmax(y_conv,1)  
      predint=prediction.eval(feed_dict={x: [result],keep_prob: 1.0}, session=sess)  
      print(h_conv2)  
    
      print('识别结果:')  
      print(predint[0]) 


** 2.测试图片**

3.运行结果

ef1946e37e8edd022fe360f5eed381ad.webp

识别结果为4,与测试图片内容一致,识别正确。

总结

手写数字识别是模式识别中一个非常重要和活跃的研究领域,数字识别也不是一项孤立的技术,他涉及的问题是模式识别的其他领域都无法回避的;应用上,作为一种信息处理手段,字符识别有广阔的应用背景和巨大的市场需求。因此,对数字识别的研究具有理论和应用的双重意义。

手写数字识别在邮政编码、统计报表、财务报表、快递分拣、银行票据等处理大量字符信息录入的场合中具有广泛应用。另外,图像识别技术的研究为人工智能开启了里程碑,在机器学习、机器人研究等方面起到了关键的作用。这方面的研究很有实用价值,重要性也是不言而喻的。



浏览 32
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报