手写数字识别
MNIST数据集(修改的国家标准与技术研究所——Modified National Institute of Standards and Technology),是一个大型的包含手写数字图片的数据集。该数据集由0-9手写数字图片组成,共10个类别。每张图片的大小为28 * 28。
加载必要的库。
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data import matplotlib.pyplot as plt
下载数据集
调用read_data_sets,可以下载mnist数据集到指定的目录,如果目录不存在,可自定创建。
如果数据已经下载,则直接从文件中提取数据。
说明:
如果因为网络原因,导致下载不成功,可以去MNIST官网进行下载。
# 通过指定的路径(第1个参数)获取(加载)手写数字数据集。如果指定的路径中文件 # 不存在,则会进行下载。(下载速度可能非常慢)。 # 如果文件已经存在,则直接使用。 mnist = input_data.read_data_sets("data/", one_hot=True)
MNIST数据集查看
MNIST数据集共有70000张图像,其中训练集60000张,测试集10000张。训练集分为55000张训练图像与5000张验证图像。
MNIST图像为单通道。
display(mnist.train.images.shape) display(mnist.train.labels.shape)
mnist.train.labels[0] • 1
显示指定的图
可以通过matplotlib库显示指定的图像。
plt.imshow(mnist.train.images[1].reshape((28, 28)), cmap="gray")
实现
我们使用单层神经网络来实现该任务。使用softmax激活函数。
图像的每个像素可以看做一个特征,而每个像素点对应着一个权重,来衡量该像素点对目标的影响大小。
# 定义输入。 X = tf.placeholder(dtype=tf.float32, shape=[None, 784]) y = tf.placeholder(dtype=tf.float32, shape=[None, 10]) # W = tf.Variable(tf.random_normal(shape=[784, 10], stddev=0.1)) # 对于单层的神经网络,权重初始化不那么重要,但是对于多层神经网络,权重的初始化就比较重要了。 W = tf.Variable(tf.zeros(shape=[784, 10])) b = tf.Variable(tf.zeros(shape=[1, 10])) # 计算净输入。(logits值) z = tf.matmul(X, W) + b # 多分类,使用softmax。传递logits值,返回属于每个类别的概率。 a = tf.nn.softmax(z) # 定义交叉熵损失函数。 loss = -tf.reduce_sum(y * tf.log(a)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss) # tf.argmax(y, axis=1) 求真实的类别的索引。 # tf.argmax(a, axis=1) 求预测的类别的索引。 # correct是一个布尔类型的张量。 correct = tf.equal(tf.argmax(y, axis=1), tf.argmax(a, axis=1)) # 计算准确率。 rate = tf.reduce_mean(tf.cast(correct, tf.float32)) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(1, 3001): batch_X, batch_y = mnist.train.next_batch(100) sess.run(train_step, feed_dict={X: batch_X, y: batch_y}) if i % 500 == 0: # 传入测试数据,查看测试集上的准确率。 print(sess.run(rate, feed_dict={X: mnist.test.images, y: mnist.test.labels}))
0.894
0.92
0.9183
0.9031
0.9207
0.9152
改进
采用中间加入一隐藏层(多层神经网络)来实现,查看准确率是否改善。
X = tf.placeholder(dtype=tf.float32, shape=[None, 784]) y = tf.placeholder(dtype=tf.float32, shape=[None, 10]) # 如果将权重初始化为0,则准确率非常低。10%左右。 # W = tf.Variable(tf.zeros(shape=[784, 256])) # 如果标准差设置不当,准确率也非常低。 # W = tf.Variable(tf.random_normal(shape=[784, 256], stddev=0.05)) # 使用标准正态分布,标准差0.05,准确率为97%左右。 # W = tf.Variable(tf.random_normal(shape=[784, 256], stddev=0.05)) # 也可以使用截断正态分布,准确率与标准正态分布差不多。使用截断正态分布时,标准差设置为0.1不会出现问题。 W = tf.Variable(tf.truncated_normal(shape=[784, 256], stddev=0.1)) b = tf.Variable(tf.zeros(shape=[1, 256])) z = tf.matmul(X, W) + b # 使用Relu激活函数。a是当前层神经元的输出值,会作为下一层神经元的输入值。 a = tf.nn.relu(z) # W2 = tf.Variable(tf.random_normal(shape=[256, 10], stddev=0.05)) W2 = tf.Variable(tf.truncated_normal(shape=[256, 10], stddev=0.1)) b2 = tf.Variable(tf.zeros(shape=[1, 10])) z2 = tf.matmul(a, W2) + b2 a2 = tf.nn.softmax(z2) loss = -tf.reduce_sum(y * tf.log(a2)) # 这里不再计算softmax,再计算交叉熵,而是直接用tf.nn.softmax_cross_entropy_with_logits直接计算。 # 但是,使用该方法后,准确率有所下降。 # loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=z2, labels=y)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss) correct = tf.equal(tf.argmax(y, axis=1), tf.argmax(a2, axis=1)) # correct = tf.equal(tf.argmax(y, axis=1), tf.argmax(z2, axis=1)) rate = tf.reduce_mean(tf.cast(correct, tf.float32)) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(1, 3001): batch_X, batch_y = mnist.train.next_batch(100) sess.run(train_step, feed_dict={X: batch_X, y: batch_y}) if i % 500 == 0: print(sess.run(rate, feed_dict={X: mnist.test.images, y: mnist.test.labels}))
0.9619
0.9716
0.9749
0.974
0.9773
0.9746