当前位置:   article > 正文

深度学习案例之基于 CNN 的 MNIST 手写数字识别_mnist手写数字集可视化

mnist手写数字集可视化

一、模型结构

本文只涉及利用Tensorflow实现CNN的手写数字识别,CNN的内容请参考:卷积神经网络(CNN)

MNIST数据集的格式与数据预处理代码input_data.py的讲解请参考 :Tutorial (2)

二、实验代码

  1. # -*- coding:utf-8 -*-
  2. """
  3. @Time :
  4. @Author: Feng Lepeng
  5. @File : mnist_cnn_tf_demo.py
  6. @Desc : 手写数字识别的CNN网络 LeNet
  7. 注意:一般情况下,我们都是直接将网络结构翻译成为这个代码,最多稍微的修改一下网络中的参数(超参数、窗口大小、步长等信息)
  8. https://deeplearnjs.org/demos/model-builder/
  9. https://js.tensorflow.org/#getting-started
  10. """
  11. import math
  12. import tensorflow as tf
  13. from tensorflow.examples.tutorials.mnist import input_data
  14. # 数据加载
  15. mnist = input_data.read_data_sets('data/mnist', one_hot=True)
  16. # 手写数字识别的数据集主要包含三个部分:训练集(5.5w, mnist.train)、测试集(1w, mnist.test)、验证集(0.5w, mnist.validation)
  17. # 手写数字图片大小是28*28*1像素的图片(黑白),也就是每个图片由784维的特征描述
  18. train_img = mnist.train.images
  19. train_label = mnist.train.labels
  20. test_img = mnist.test.images
  21. test_label = mnist.test.labels
  22. train_sample_number = mnist.train.num_examples
  23. # 相关的参数、超参数的设置
  24. # 学习率,一般学习率设置的比较小
  25. learn_rate_base = 1.0
  26. # 每次迭代的训练样本数量
  27. batch_size = 64
  28. # 展示信息的间隔大小
  29. display_step = 1
  30. # 输入的样本维度大小信息
  31. input_dim = train_img.shape[1]
  32. # 输出的维度大小信息
  33. n_classes = train_label.shape[1]
  34. # 模型构建
  35. # 1. 设置数据输入的占位符
  36. x = tf.placeholder(tf.float32, shape=[None, input_dim], name='x')
  37. y = tf.placeholder(tf.float32, shape=[None, n_classes], name='y')
  38. learn_rate = tf.placeholder(tf.float32, name='learn_rate')
  39. def learn_rate_func(epoch):
  40. """
  41. 根据给定的迭代批次,更新产生一个学习率的值
  42. :param epoch:
  43. :return:
  44. """
  45. return learn_rate_base * (0.9 ** int(epoch / 10))
  46. def get_variable(name, shape=None, dtype=tf.float32, initializer=tf.random_normal_initializer(mean=0, stddev=0.1)):
  47. """
  48. 返回一个对应的变量
  49. :param name:
  50. :param shape:
  51. :param dtype:
  52. :param initializer:
  53. :return:
  54. """
  55. return tf.get_variable(name, shape, dtype, initializer)
  56. # 2. 构建网络
  57. def le_net(x, y):
  58. # 1. 输入层
  59. with tf.variable_scope('input1'):
  60. # 将输入的x的格式转换为规定的格式
  61. # [None, input_dim] -> [None, height, weight, channels]
  62. net = tf.reshape(x, shape=[-1, 28, 28, 1])
  63. # 2. 卷积层
  64. with tf.variable_scope('conv2'):
  65. # 卷积
  66. # conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC", name=None) => 卷积的API
  67. # data_format: 表示的是输入的数据格式,两种:NHWC和NCHW,N=>样本数目,H=>Height, W=>Weight, C=>Channels
  68. # input:输入数据,必须是一个4维格式的图像数据,具体格式和data_format有关,如果data_format是NHWC的时候,input的格式为: [batch_size, height, weight, channels] => [批次中的图片数目,图片的高度,图片的宽度,图片的通道数];如果data_format是NCHW的时候,input的格式为: [batch_size, channels, height, weight] => [批次中的图片数目,图片的通道数,图片的高度,图片的宽度]
  69. # filter: 卷积核,是一个4维格式的数据,shape: [height, weight, in_channels, out_channels] => [窗口的高度,窗口的宽度,输入的channel通道数(上一层图片的深度),输出的通道数(卷积核数目)]
  70. # strides:步长,是一个4维的数据,每一维数据必须和data_format格式匹配,表示的是在data_format每一维上的移动步长,当格式为NHWC的时候,strides的格式为: [batch, in_height, in_weight, in_channels] => [样本上的移动大小,高度的移动大小,宽度的移动大小,深度的移动大小],要求在样本上和在深度通道上的移动必须是1;当格式为NCHW的时候,strides的格式为: [batch,in_channels, in_height, in_weight]
  71. # padding: 只支持两个参数"SAME", "VALID",当取值为SAME的时候,表示进行填充,"在TensorFlow中,如果步长为1,并且padding为SAME的时候,经过卷积之后的图像大小是不变的";当VALID的时候,表示多余的特征会丢弃;
  72. net = tf.nn.conv2d(input=net, filter=get_variable('w', [5, 5, 1, 20]), strides=[1, 1, 1, 1], padding='SAME')
  73. net = tf.nn.bias_add(net, get_variable('b', [20]))
  74. # 激励 ReLu
  75. # tf.nn.relu => max(fetures, 0)
  76. # tf.nn.relu6 => min(max(fetures,0), 6)
  77. net = tf.nn.relu(net)
  78. # 3. 池化
  79. with tf.variable_scope('pool3'):
  80. # 和conv2一样,需要给定窗口大小和步长
  81. # max_pool(value, ksize, strides, padding, data_format="NHWC", name=None)
  82. # avg_pool(value, ksize, strides, padding, data_format="NHWC", name=None)
  83. # 默认格式下:NHWC,value:输入的数据,必须是[batch_size, height, weight, channels]格式
  84. # 默认格式下:NHWC,ksize:指定窗口大小,必须是[batch, in_height, in_weight, in_channels], 其中batch和in_channels必须为1
  85. # 默认格式下:NHWC,strides:指定步长大小,必须是[batch, in_height, in_weight, in_channels],其中batch和in_channels必须为1
  86. # padding: 只支持两个参数"SAME", "VALID",当取值为SAME的时候,表示进行填充,;当VALID的时候,表示多余的特征会丢弃;
  87. net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
  88. # 4. 卷积
  89. with tf.variable_scope('conv4'):
  90. net = tf.nn.conv2d(input=net, filter=get_variable('w', [5, 5, 20, 50]), strides=[1, 1, 1, 1], padding='SAME')
  91. net = tf.nn.bias_add(net, get_variable('b', [50]))
  92. net = tf.nn.relu(net)
  93. # 5. 池化
  94. with tf.variable_scope('pool5'):
  95. net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
  96. # 6. 全连接
  97. with tf.variable_scope('fc6'):
  98. # 28 -> 14 -> 7(因为此时的卷积不改变图片的大小)
  99. net = tf.reshape(net, shape=[-1, 7 * 7 * 50])
  100. net = tf.add(tf.matmul(net, get_variable('w', [7 * 7 * 50, 500])), get_variable('b', [500]))
  101. net = tf.nn.relu(net)
  102. # 7. 全连接
  103. with tf.variable_scope('fc7'):
  104. net = tf.add(tf.matmul(net, get_variable('w', [500, n_classes])), get_variable('b', [n_classes]))
  105. act = tf.nn.softmax(net)
  106. return act
  107. # 构建网络
  108. act = le_net(x, y)
  109. # 构建模型的损失函数
  110. # softmax_cross_entropy_with_logits: 计算softmax中的每个样本的交叉熵,logits指定预测值,labels指定实际值
  111. cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=act, labels=y))
  112. # 使用Adam优化方式比较多
  113. # learning_rate: 要注意,不要过大,过大可能不收敛,也不要过小,过小收敛速度比较慢
  114. train = tf.train.AdamOptimizer(learning_rate=learn_rate).minimize(cost)
  115. # 得到预测的类别是那一个
  116. # tf.argmax:对矩阵按行或列计算最大值对应的下标,和numpy中的一样
  117. # tf.equal:是对比这两个矩阵或者向量的相等的元素,如果是相等的那就返回True,反正返回False,返回的值的矩阵维度和A是一样的
  118. pred = tf.equal(tf.argmax(act, axis=1), tf.argmax(y, axis=1))
  119. # 正确率(True转换为1False转换为0
  120. acc = tf.reduce_mean(tf.cast(pred, tf.float32))
  121. # 初始化
  122. init = tf.global_variables_initializer()
  123. with tf.Session() as sess:
  124. # 进行数据初始化
  125. sess.run(init)
  126. # 模型保存、持久化
  127. saver = tf.train.Saver()
  128. epoch = 0
  129. while True:
  130. avg_cost = 0
  131. # 计算出总的批次
  132. total_batch = int(train_sample_number / batch_size)
  133. # 迭代更新
  134. for i in range(total_batch):
  135. # 获取x和y
  136. batch_xs, batch_ys = mnist.train.next_batch(batch_size)
  137. feeds = {x: batch_xs, y: batch_ys, learn_rate: learn_rate_func(epoch)}
  138. # 模型训练
  139. sess.run(train, feed_dict=feeds)
  140. # 获取损失函数值
  141. avg_cost += sess.run(cost, feed_dict=feeds)
  142. # 重新计算平均损失(相当于计算每个样本的损失值)
  143. avg_cost = avg_cost / total_batch
  144. # DISPLAY 显示误差率和训练集的正确率以此测试集的正确率
  145. if (epoch + 1) % display_step == 0:
  146. print("批次: %03d 损失函数值: %.9f" % (epoch, avg_cost))
  147. # 这里之所以使用batch_xs和batch_ys,是因为我使用train_img会出现内存不够的情况,直接就会退出
  148. feeds = {x: batch_xs, y: batch_ys, learn_rate: learn_rate_func(epoch)}
  149. train_acc = sess.run(acc, feed_dict=feeds)
  150. print("训练集准确率: %.3f" % train_acc)
  151. feeds = {x: test_img, y: test_label, learn_rate: learn_rate_func(epoch)}
  152. test_acc = sess.run(acc, feed_dict=feeds)
  153. print("测试准确率: %.3f" % test_acc)
  154. if train_acc > 0.9 and test_acc > 0.9:
  155. saver.save(sess, './mnist/model')
  156. break
  157. epoch += 1
  158. # 模型可视化输出
  159. writer = tf.summary.FileWriter('./mnist/graph', tf.get_default_graph())
  160. writer.close()

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/92866
推荐阅读
相关标签
  

闽ICP备14008679号