简介:本文先讲解了手写体识别中涉及到的知识,然后分步讲解了代码的详细思路,完成了手写体识别案例的讲解,希望能给大家带来帮助,也希望大家多多关注我。本文是基于TensorFlow1.14.0的环境下运行的
手写体识别Tensorflow实现
1 MNIST数据集处理
数据集的网址如下:https://yann.lecun.com/exdb/mnist/
他的数据集有训练集 测试集图片与标签四部分组成
被分为两部分 6万行训练数据集和1万行的测试数据集
每一张图片包含2828个像素,把他展开成一维向量,长度是284284 = 784,所以训练集是shape为[60000,784]的张量,第一个维度数字用来索引图片,第二个维度数字用来索引图片中的像素点
他的标签是介于0-9的数字,我们要把它转化为one - hot,也叫做独热 ,比如3 转化为 [0,0,1,0,0,0,0,0,0],他是几就让第几个数字为1.。所以labels将会被转化为一个shape为[60000,10]的矩阵
2 神经网络
根据第一节的内容我们可以设计一个简单的神经网络实现手写体识别,如果想提升准确率,可以在中间加入隐藏层。
3 Softmax函数
就用手写体识别这个举例子,比如说预测了某张图片的shape为[1,10]的可能是[15,3,1,0,2,4,5,1,1,0],我们希望将他转化为概率,且需要所有概率和为1,我们来看softmax的数学公式
这个zi就是对应[1,10]矩阵中的权重,zj这个分母部分是所有的和
这样子计算既满足了归一化的需求
3.1 什么时候用softmax
一般是用在神经网络的输出层,用于分类或者回归
3.2 softmax的优越性
- 满足了人们对归一化的需求
- 指数函数容易求偏导
- 指数函数咋信息论和统计学中常用,可以联系这些,为神经网络的构建提供数学依据
4 代码实现分步讲解
4.1 导包
因为环境和版本等种种原因,他经常会报一些无关痛痒的小警告,所以我们要把这些警告屏蔽掉,然后导入TensorFlow等包
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
4.2 载入数据
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print(x_train)
print(y_train)
4.3 批次batch
这些图片不会一次性处理运算量太大了,比如设置为100,每次都会处理100张图片
batch_size = 100
还需要计算一共有多少个批次
n_batch = len(x_train) // batch_size
print(n_batch)
4.4 placeholder的定义
x = tf.compat.v1.placeholder(tf.float32,[None,784])
y = tf.compat.v1.placeholder(tf.float32,[None,10])
4.5神经网路模型的构建
Weight = tf.compat.v1.Variable(tf.zeros([784,10]))
bias = tf.compat.v1.Variable(tf.zeros([10]))
prediction = tf.nn.softmax(tf.matmul(x,Weight)+bias)
4.6 损失函数
loss = tf.reduce_mean(tf.square(y-prediction))
4.7使用梯度下降
如果您不会用,请阅读我的文章: 线性回归,在该文章中讲解了该函数的具体用法
train_step = tf.compat.v1.train.GradientDescentOptimizer(0.2).minimize(loss)
4.8 初始化 variable
init_option = tf.compat.v1.global_variables_initializer()
4.9 预测结果
4.9.1 tf.equal函数
他的作用是判断预测和真实是否一致
4.9.2 tf.argmax函数
因为我们计算的是某张图是那个数字的概率,所以需要把最大的拿出来当做是这个图的预测结果
最后我们的道德结果是一个由False和True组成的列表
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
4.10计算准确率
4.10.1 tf.cast数据类型转换
我们需要先把布尔类型的结果转化为浮点类型 1…0和0
4.10.2 tf.reduce_mean
他的作用是计算张量的平均值
accuracy_rate = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
4.13 对输入进行处理
# 将输入数据重塑为二维形式(原本图像数据是二维的,这里要展平为一维向量作为神经网络输入)
# 例如原来是 (60000, 28, 28) 变成 (60000, 784),60000是样本数量,784是28*28(图像像素数量)
x_train = x_train.reshape(x_train.shape[0], -1)
x_test = x_test.reshape(x_test.shape[0], -1)
4.12 使用Session进行训练
with tf.compat.v1.Session() as calculate:
calculate.run(init_option)
y_train = calculate.run(tf.one_hot(y_train, depth=10))
# 将测试集标签进行独热编码,显式指定会话参数
y_test = calculate.run(tf.one_hot(y_test, depth=10))
for epoch in range(21):
for batch in range(n_batch):
# 计算当前batch的起始索引和结束索引
start_index = batch * batch_size
end_index = start_index + batch_size
# 从训练数据集中提取当前batch的输入数据和标签数据
batch_x = x_train[start_index:end_index]
batch_y = y_train[start_index:end_index]
# 将当前batch的数据喂入计算图进行训练
calculate.run(train_step, feed_dict={x: batch_x, y: batch_y})
# 在每个epoch结束后,在测试集上计算并打印当前的准确率
acc = calculate.run(accuracy_rate, feed_dict={x: x_test, y: y_test})
print("Epoch {}: Accuracy {}".format(epoch + 1, acc))
4.13代码汇总
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print(x_train)
print(y_train)
batch_size = 100
n_batch = len(x_train) // batch_size
print(n_batch)
x = tf.compat.v1.placeholder(tf.float32,[None,784])
y = tf.compat.v1.placeholder(tf.float32,[None,10])
Weight = tf.compat.v1.Variable(tf.zeros([784,10]))
bias = tf.compat.v1.Variable(tf.zeros([10]))
prediction = tf.nn.softmax(tf.matmul(x,Weight)+bias)
loss = tf.reduce_mean(tf.square(y-prediction))
train_step = tf.compat.v1.train.GradientDescentOptimizer(0.2).minimize(loss)
init_option = tf.compat.v1.global_variables_initializer()
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))
accuracy_rate = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
# 将输入数据重塑为二维形式(原本图像数据是二维的,这里要展平为一维向量作为神经网络输入)
# 例如原来是 (60000, 28, 28) 变成 (60000, 784),60000是样本数量,784是28*28(图像像素数量)
x_train = x_train.reshape(x_train.shape[0], -1)
x_test = x_test.reshape(x_test.shape[0], -1)
with tf.compat.v1.Session() as calculate:
calculate.run(init_option)
y_train = calculate.run(tf.one_hot(y_train, depth=10))
# 将测试集标签进行独热编码,显式指定会话参数
y_test = calculate.run(tf.one_hot(y_test, depth=10))
for epoch in range(21):
for batch in range(n_batch):
# 计算当前batch的起始索引和结束索引
start_index = batch * batch_size
end_index = start_index + batch_size
# 从训练数据集中提取当前batch的输入数据和标签数据
batch_x = x_train[start_index:end_index]
batch_y = y_train[start_index:end_index]
# 将当前batch的数据喂入计算图进行训练
calculate.run(train_step, feed_dict={x: batch_x, y: batch_y})
# 在每个epoch结束后,在测试集上计算并打印当前的准确率
acc = calculate.run(accuracy_rate, feed_dict={x: x_test, y: y_test})
print("Epoch {}: Accuracy {}".format(epoch + 1, acc))
致谢
本文参考了一些博主的文章,博取了他们的长处,也结合了我的一些经验,对他们表达诚挚的感谢,使我对 Tensorflow在手写体识别的使用有更深入的了解,也推荐大家去阅读一下他们的文章。纸上学来终觉浅,明知此事要躬行:
Softmax函数