本次训练一个能够识别图片的手写数字的机器学习模型。
从第一课我们可以知道需要一个数据集来训练模型。
这个数据集就是图片,来源于一个开源的训练数据集—MNIST。
MNIST数据集的官网是 http://yann.lecun.com/exdb/mnist/
大家可以到官网去下载图片的数据集。
同时TensorFlow也提供了一个库,可以用来自动下载安装MNIST。
代码如下:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
运行之后,会自动下载数据集并且解压到当前代码同级目录下面的MNIST_data文件夹下。
代码之中的one_hot = true,表示将样本标签转换为one_hot编码。因为本例是识别数字,计算机在得出结果后,会通过该种方式表达得到的结果。比如一张图片被识别为数字1,则计算机表达为[1.0.0.0.0.0.0.0.0.0],如果是被识别为数字2,则计算机表达为[0.1.0.0.0.0.0.0.0.0],被识别为3的话,则计算机表达为[0.0.1.0.0.0.0.0.0.0]。后面的以此类推,且只需要表示0~9的数字。
在MNIST数据集的图片,每张图片是28×28的像素值。
图片黑色的地方的RGB值为0。
关于像素值和RGB可以看看之前我写的图像处理的博客的前面一部分:
博文链接:https://blog.csdn.net/qq_44807642/article/details/98205162
我们先将数据集的信息打印出来,看一看具体内容。
import tensorflow as tf #导入tensorflow库
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
import pylab
print ('输入数据:',mnist.train.images)
print('数据为:',mnist.train.images.shape)
im = mnist.train.images[1]
im = im.reshape(-1,28)
pylab.imshow(im)
pylab.show()
在图中,输入数据是图每点的RGB值,数据是代表有55000张这样的图片。相当于一个55000×784的二维数组。
第一个维度的数字55000的可以用来识别是哪张图片。
第二个维度的数字784的可以识别该点的RGB值。
MNIST包含三个数据集,分别是
训练数据集:用于训练
测试数据集(mnist.test):用于评估训练中的准确度
验证数据集(mnist.validation):用于评估模型的准确度。
因为输入图片是个550000×784的矩阵。所以可以先创建一个[None,784]的占位符x和一个[None,10]的占位符y(因为电脑输出结果用one_hot编码表示,所以用到[None,10]的占位符)
tf.reset_default_graph() #tf.reset_default_graph函数用于清除默认图形堆栈并重置全局默认图形。
# tf 输入
x = tf.placeholder(tf.float32, [None, 784]) # mnist data维度 28*28=784
y = tf.placeholder(tf.float32, [None, 10]) # 0-9 数字
第三行代码中的None,表示此张量第一个的维度可以是任何长度的,x就代表能够输入任意数量的MNIST图像,每一张图可以展成784维的向量。
在这个模型里面一样需要定义w(权重值),b(偏执值)。
W = tf.Variable(tf.random_normal([784, 10]))
b = tf.Variable(tf.zeros([10]))
学过线性代数可以知道,比如两个矩阵[x,y]和[y,n]相乘,会得到一个[x,n]的新矩阵。
所以这里就是我们为什么要把W定为[784,10]的原因。
因为我们最后需要的是一个10维的one_hot编码。
我们用一个784维的图片向量去乘以W,就可以得到一个10维向量了。
pred = tf.nn.softmax(tf.matmul(x, W) + b)
其中matmul函数的源代码是
matmul(
a,
b,
transpose_a=False,
transpose_b=False,
adjoint_a=False,
adjoint_b=False,
a_is_sparse=False,
b_is_sparse=False,
name=None
)
就是将矩阵 a 乘以矩阵 b,生成a * b。
softmax的功能就是把一个N*1的向量归一化为(0,1)之间的值。达到分类的效果。
# Minimize error using cross entropy
cost = tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred), reduction_indices=1))
#参数设置
learning_rate = 0.01 #学习率
# 使用梯度下降优化器
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
将上面生成的pred与样本标签y进行一次交叉熵的运算,后取平均值。
tf.reduce_sum()函数计算一个张量的各个维度上元素的总和。
tf.reduce_mean()计算张量的各个维度上的元素的平均值。
不停更新W,b使其cost值越来越小。
在训练模型中,我们将模型迭代25次,一次取100条数据训练,间隔一次就进行显示状态。然后开始训练。
training_epochs = 25
batch_size = 100
display_step = 1
saver = tf.train.Saver()
model_path = "log/521model.ckpt"
# 启动session
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())# Initializing OP
# 启动循环开始训练
for epoch in range(training_epochs):
avg_cost = 0.
total_batch = int(mnist.train.num_examples/batch_size)
# 遍历全部数据集
for i in range(total_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
_, c = sess.run([optimizer, cost], feed_dict={x: batch_xs,
y: batch_ys})
avg_cost += c / total_batch
# 显示训练中的详细信息
if (epoch+1) % display_step == 0:
print ("Epoch:", '%04d' % (epoch+1), "cost=", "{:.9f}".format(avg_cost))
print( " Finished!")
在训练完成之后,我们就可以直接使用啦。
# 测试 model
correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
# 计算准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print ("Accuracy:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))
这一段代码为测试代码,可以先看下模型准确率
save_path = saver.save(sess, model_path)
print("Model saved in file: %s" % save_path)
用这两句代码对模型进行保存,并输出保存路径。
并且在session创建之前添加saver和model_path的定义。
saver = tf.train.Saver()
model_path = "log/521model.ckpt"
然后我们就可以在代码的同级目录下找到log文件夹,里面有有如下文件。
在模型储存好后,我们用两张图片来实验一下,用下面的session代码替换掉以前的session。
with tf.Session() as sess:
# Initialize variables
sess.run(tf.global_variables_initializer())
# Restore model weights from previously saved model
saver.restore(sess, model_path)
# 测试 model
correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
# 计算准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print ("Accuracy:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))
output = tf.argmax(pred, 1)
batch_xs, batch_ys = mnist.train.next_batch(2)
outputval,predv = sess.run([output,pred], feed_dict={x: batch_xs})
print(outputval,predv,batch_ys)
im = batch_xs[0]
im = im.reshape(-1,28)
pylab.imshow(im)
pylab.show()
im = batch_xs[1]
im = im.reshape(-1,28)
pylab.imshow(im)
pylab.show()