分类应用入门—MNIST手写数字识别

背景:MNIST 数据集来自美国国家标准与技术研究所,National Institute of Standardsand Technology (NIST).

数据集由来自250个不同人手写的数字构成,其中50%是高中学生,50%来自人口普查局(the Census Bureau)的工作人员
其中,训练集55000验证集5000 测试集10000。MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取,也可以不下载因为TensorFlow提供了数据集读取方法。

一、数据下载和读取

1.1数据下载

import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

MNIST数据集文件在读取时如果指定目录下不存在,则会自动去下载,需等待一定时间如果已经存在了,则直接读取。

1.2数据读取

import tensorflow.examples.tutorials.mnist.input_data as input_data

mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)
print('训练集train 数量:',mnist.train.num_examples,',验证集 validation 数量:',mnist.validation.num_examples,',测试集test 数量:',mnist.test.num_examples)

print('train images shape:',mnist.train.images.shape,'labels shaple:',mnist.train.labels.shape)
#(55000,784)意思是5w5千条,每一条784位(图片大小28*28);(55000,10):10分类 One Hot编码

1.2.1数据的批量读取

MNIST数据包里提供了  .next_batch方法,可实现批量读取

 

 

 1.3可视化image

def plot_image(image):
      plt.imshow(image.reshape(28,28),cmap='binary')
      plt.show()
plot_image(mnist.train.images[1])

 二、标签数据与独热编码

2.1独热编码简介

一种稀疏向量,其中:一个元素设为1,所有其他元素均设为0
独热编码常用于表示拥有有限个可能值的字符串或标识符
例如:假设某个植物学数据集记录了15000个不同的物种,其中每个物种都用独一无二的字符串标识符来表示。在特征工程过程中,可能需要将这些字符串标识符编码为独热向量,向量的大小为15000

      为什么要采用one hot编码?

  • 将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点
  • 机器学习算法中,特征之间距离的计算或相似度的常用计算方法都是基于欧式空间的
  • 将离散型特征使用one-hot编码,会让特征之间的距离计算更加合理

  独热编码如何取值?

 非独热编码的标签值:

 三、模型构建

3.1定义待输入数据的占位符

#mnist 中每张图片共有28*28=784个像素点
x=tf.placeholder(tf.float32,[None,784],name="X")
#0-9一共10个数字=>10个类别
y=tf.placeholder(tf.float32,[None,10],name="Y")

3.2定义模型变量

在本案例中,以正态分布的随机数初始化权重W,以常数0初始化偏置b

W= tf.Variable(tf.random_normal([784,10]),name="W")
b= tf.Variable(tf.zeros([10]),name="b")

3.3定义前向计算和结果分类

forward = tf.matmul(x, W) + b #前向计算

  当我们处理多分类任务时,通常需要使用Softmax Regression模型。
  Softmax Regression会对每一类别估算出一个概率。
  工作原理:将判定为某一类的特征相加,然后将这些特征转化为判定是这一类的概率。

pred = tf.nn.softmax(forward) #Softmax分类

 四、训练模型

4.1设置训练参数

train_epochs = 50   #训练轮数
batch_size=100      #单次训练样本数(批次大小)
total_batch= int(mnist.train.num_examples/batch_size)#一轮训练有多少批次
display_step=1     #显示粒度
learning_rate=0.01   #学习率

4.2定义损失函数,选择优化器

loss_function = tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),reduction_indices=1))   #定义交叉熵损失函数
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function)  #梯度下降优化器

4.3定义准确率

#检查预测类别tf.argmax(pred,1)与实际类别tf.argmax(y.1)的匹配情况,argmax能把最大值的下标取出来
correct_prediction = tf.equal(tf.argmax(pred,1),tf.argmax(y,1))#相等则返回True
#准确率,将布尔值转化为浮点数,并计算平均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
sess = tf.Session()#声明会活
init = tf.global_variables_initializer()#变量初始化
sess.run(init)

拓展部分:argmax()用法

 

 

 

 4.4训练过程

#开始训练
for epoch in range(train_epochs):
    for batch in range(total_batch):
          xs,ys = mnist.train.next_batch(batch_size)  # 读取批次数据
          sess.run(optimizer,feed_dict={x:xs,y:ys})   # 执行批次训练
    #total_batch个批次训练完成后,使用验证数据计算课差与准确率;验证集没有分批
    loss,acc = sess.run([loss_function,accuracy],feed_dict={x:mnist.validation.images,y:mnist.validation.labels})
    #打印训练过程中的详细信息
    if (epoch+1) % display_step == 0:
        print("Train Epoch:",'%02d' %(epoch+1),"Loss=","{:.9f}".format(loss),"Accuracy=","{:.4f}".format(acc))
print("Train Finished!")

运行结果为:

 

从结果可以看出,损失值Loss是趋于更小的,准确率Accuracy越来越高,可以修改参数,使得准确率(验证集)到90%以上~~

五、评估模型

完成训练后,在测试集上评估模型的准确率

accu_test = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels})
print("Test Accuracy:",accu_test)

Note:测试环节中没有分批,所有测试数据1万条直接执行

 测试结果86.14%,  上面模型训练时是由验证集的数据做出来的,是86.46%。

在训练集上评估模型的准确率

accu_train = sess.run(accuracy,feed_dict={x:mnist.train.images,y:mnist.train.labels})
print("Test Accuracy:",accu_train)

 通过数据集的合理划分,训练和验证效果差不多,准确率比较满意则可以进行模型预测。

六、模型应用和可视化

#模型预测
#由于pred预测结果是one-hot编码格式,所以需要转换为0-9数字
prediction_result = sess.run(tf.argmax(pred,1),feed_dict={x:mnist.test.images})

print(prediction_result[0:10])  #查看预测结果中的前10项

 然而不够直观,不能与数据集的图片相对应。

6.1定义可视化函数

 1 def plot_images_labels_prediction(images,labels,prediction,index,num=10):   #图像列表,标签列表,预测值列表,从第index个开始显示 , 缺省一次显示10幅
 2     fig = plt.gcf() #获取当前图表,get current figure
 3     fig.set_size_inches(10,12)  #1英寸等于2.54cm
 4     if num > 25:
 5         num = 25  #最多显示25个子图
 6     for i in range(0, num):
 7         ax = plt.subplot(5,5,i+1)  #获取当前要处理的子图
 8         ax.imshow(np.reshape(images[index], (28, 28)),cmap='binary')  # 显示第index个图像
 9         title = "label=" + str(np.argmax(labels[index]))# 构建该图上要显示的
10         if len(prediction)>0:
11             title += ",predict="+ str(prediction[index])
12         ax.set_title(title, fontsize=10)  #显示图上title信息
13         ax.set_xticks([])  #不显示坐标轴
14         ax.set_yticks([])
15         index += 1
16     plt.show()

Note:第10行代码意思是如果参数预测值列表为空,也是可以的,这样可以直接用该函数查看训练值

6.2可视化预测结果

plot_images_labels_prediction(mnist.test.images,mnist.test.labels,prediction_result,0,15) #0代表下标从0幅开始,15表示最多显示15幅

运行结果为:

通过可视化,可以更直观的查看哪些预测对了 哪些预测错了。

plot_images_labels_prediction(mnist.test.images,mnist.test.labels,[],0,15) 

如果参数预测列表设为空,也能执行,只不过不显示预测标签的值。这时函数相当于查看训练集,运行结果为:

完整代码如下

#Created by:Huang
#Time:2019/10/9 0009.
import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
import matplotlib.pyplot as plt
import numpy as np

mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)
# print('训练集train 数量:',mnist.train.num_examples,',验证集 validation 数量:',mnist.validation.num_examples,',测试集test 数量:',mnist.test.num_examples)

# print('train images shape:',mnist.train.images.shape,'labels shaple:',mnist.train.labels.shape)
#(55000,784)意思是5w5千条,每一条784位(图片大小28*28);(55000,10):10分类 One Hot编码
# def plot_image(image):
#       plt.imshow(image.reshape(28,28),cmap='binary')
#       plt.show()
# plot_image(mnist.train.images[20000])
x = tf.placeholder(tf.float32,[None,784],name="X")#mnist 中每张图片共有28*28=784个像素点
y = tf.placeholder(tf.float32,[None,10],name="Y")#0-9一共10个数字=>10个类别

W= tf.Variable(tf.random_normal([784,10]),name="W")  #定义变量
b= tf.Variable(tf.zeros([10]),name="b")
#用单个神经元构建神经网络
forward = tf.matmul(x, W) + b  #前向计算
pred = tf.nn.softmax(forward)  #Softmax分类

train_epochs = 50   #训练轮数
batch_size=100      #单次训练样本数(批次大小)
total_batch= int(mnist.train.num_examples/batch_size)#一轮训练有多少批次
display_step=1     #显示粒度
learning_rate=0.01   #学习率

loss_function = tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),reduction_indices=1))   #定义交叉熵损失函数
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function)  #梯度下降优化器

#检查预测类别tf.argmax(pred,1)与实际类别tf.argmax(y.1)的匹配情况,argmax能把最大值的下标取出来
correct_prediction = tf.equal(tf.argmax(pred,1),tf.argmax(y,1))
#准确率,将布尔值转化为浮点数,并计算平均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
sess = tf.Session()#声明会活
init = tf.global_variables_initializer()#变量初始化
sess.run(init)

#开始训练
for epoch in range(train_epochs):
    for batch in range(total_batch):
          xs,ys = mnist.train.next_batch(batch_size)  # 读取批次数据
          sess.run(optimizer,feed_dict={x:xs,y:ys})   # 执行批次训练
    #total_batch个批次训练完成后,使用验证数据计算课差与准确率;验证集没有分批
    loss,acc = sess.run([loss_function,accuracy],feed_dict={x:mnist.validation.images,y:mnist.validation.labels})
    #打印训练过程中的详细信息
    if (epoch+1) % display_step == 0:
        print("Train Epoch:",'%02d' %(epoch+1),"Loss=","{:.9f}".format(loss),"Accuracy=","{:.4f}".format(acc))
print("Train Finished!")


accu_test = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels})
print("Test Accuracy:",accu_test)

accu_train = sess.run(accuracy,feed_dict={x:mnist.train.images,y:mnist.train.labels})
print("Train Accuracy:",accu_train)

#模型预测
#由于pred预测结果是one-hot编码格式,所以需要转换为0-9数字
prediction_result = sess.run(tf.argmax(pred,1),feed_dict={x:mnist.test.images})

print(prediction_result[0:10])  #查看预测结果中的前10项


def plot_images_labels_prediction(images,labels,prediction,index,num=10):   #图像列表,标签列表,预测值列表,从第index个开始显示 , 缺省一次显示10幅
    fig = plt.gcf() #获取当前图表,get current figure
    fig.set_size_inches(10,12)  #1英寸等于2.54cm
    if num > 25:
        num = 25  #最多显示25个子图
    for i in range(0, num):
        ax = plt.subplot(5,5,i+1)  #获取当前要处理的子图
        ax.imshow(np.reshape(images[index], (28, 28)),cmap='binary')  # 显示第index个图像
        title = "label=" + str(np.argmax(labels[index]))# 构建该图上要显示的
        if len(prediction)>0:
            title += ",predict="+ str(prediction[index])
        ax.set_title(title, fontsize=10)  #显示图上title信息
        ax.set_xticks([])  #不显示坐标轴
        ax.set_yticks([])
        index += 1
    plt.show()


plot_images_labels_prediction(mnist.test.images,mnist.test.labels,prediction_result,0,15)  #最多显示25张
# plot_images_labels_prediction(mnist.test.images,mnist.test.labels,[],0,15)  #最多显示25张
MNIST_SR7.1 Code
原文地址:https://www.cnblogs.com/HuangYJ/p/11642475.html