1、MNIST数据集简介:
MNIST数据集主要由一些手写数字的图片和相应标签组成,图片总共分为10类,分别对应0~9十个数字。
如上图所示,每张图片的大小为28×28像素。而标签则由one-hot向量表示,一个one-hot向量除了某一位数字为1外,其余各唯独都是0。比如[1,0,0,0,0,0,0,0,0,0,0]表示数字“0”, [0,0,0,0,0,0,0,0,0,0,1]表示数字“9”,以此类推。
2、下载MNIST数据集
可以使用如下代码下载MNIST数据集到mnist_data文件夹
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("mnist_data", one_hot=True)
下载成功后,可以发现mnist_data文件夹下有以下四个文件:
train-images-idx3-ubyte.gz
t10k-images-idx3-ubyte.gz
train-labels-idx1-ubyte.gz
t10k-labels-idx1-ubyte.gz
3、将MNIST数据集保存为图片
为了更直观的了解MNIST数据集,我们可以把上面的训练集文件前50张训练图保存成图片。代码如下:
from tensorflow.examples.tutorials.mnist import input_data
import os
import scipy.misc as sm
import numpy as np
mnist = input_data.read_data_sets("mnist_data", one_hot=True)
save_dir = 'mnist_data/image/'
if os.path.exists(save_dir) is False:
os.mkdir(save_dir)
for i in range(50):
image_array = mnist.train.images[i, :]
one_hot_label = mnist.train.labels[i, :]
label = np.argmax(one_hot_label)
image_array = image_array.reshape(28, 28)
filename = save_dir + 'image_train_%d_%d.jpg' % (i, label)
sm.toimage(image_array).save(filename)
效果如下:
4、Softmax回归介绍
Softmax回归是一个线性的多类分类模型。对于MNIST数据集的分类问题中,一个有10个类别(0~9),我们希望对输入的图像计算出它属于某个类别的概率,比如属于9的概率是80%,属于1的概率是5%等等,最后模型预测的结果就是概率最大的那个类别。
Softmax公式如下,
Softmax函数的主要功能是将各个类别的“打分”转化成合理的概率值,它将所有的类别转化为0~1之间的概率,而所有类别的概率加起来为1。
假设x是单个样本的特征,W、b是Softmax模型的参数,则计算x属于数字i类别的公式如下:
则整个Softmax模型可以用下面的式子表示:
Softmax回归模型可以用下图解释:
将上图写成等式:
用矩阵乘法和向量加法表示:
5、损失函数和优化器
训练模型的输出值和实际值肯定存在一定偏差,这种偏差越小,表示模型预测越准确,而衡量这种偏差的函数就是损失函数。Softmax回归模型中一般使用交叉熵来做损失函数。
交叉熵是判断一个输出向量与期望向量的接近程度的常用方法之一。它是分类问题中使用比较广的一种损失函数。
假设y是我们预测的概率分布, y' 是实际的分布,则交叉熵公式为:
既然有损失,那么我们肯定就得去优化以减小这个损失。优化损失的函数有很多,我们这里使用梯度下降法。
6、tensorflow代码实现
6.1、首先需要导入tensorflow模块
#coding:utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
6.2、加载MNIST数据
mnist = input_data.read_data_sets('mnist_data', one_hot=True)
6.3、创建占位符和变量,用于存放图片数据和W权重,以及偏置
#创建x占位符,用于临时存放MNIST图片的数据,
# [None, 784]中的None表示不限长度,而784则是一张图片的大小(28×28=784)
x = tf.placeholder(tf.float32, [None, 784])
#W存放的是模型的参数,也就是权重,一张图片有784个像素作为输入数据,而输出为10
#因为(0~9)有10个结果
#b则存放偏置项
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros(10))
#y表示Softmax回归模型的输出
y = tf.nn.softmax(tf.matmul(x, W) + b)
#_存的是实际图像的标签,即对应于每张输入图片实际的值
y_ = tf.placeholder(tf.float32, [None, 10])
6.4、损失函数及优化函数
#定义损失函数,这里用交叉熵来做损失函数,y存的是我们训练的结果,而y_存的是实际标签的值
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y)))
#优化函数,这里我们使用梯度下降法进行优化,0.01表示梯度下降优化器的学习率
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
6.5、使用Saver将训练结果保存
#将训练结果保存,如果不保存我们这次训练结束后的结果也随着程序运行结束而释放了
saver = tf.train.Saver()
等训练结束后,再用saver.save(sess, './saver/mnist.ckpt')将会话保存到指定文件即可
6.6、创建会话并初始化变量
#上面所做的只是定义算法,并没有真的运行,tensorflow的运行都是在会话(Session)中进行
with tf.Session() as sess:
#初始化所有变量
tf.global_variables_initializer().run()
6.7、开始训练
#开始训练,这里训练一千次
for _ in range(1000):
#每次取100张图片数据和对应的标签用于训练
batch_xs, batch_ys = mnist.train.next_batch(100)
#将取到的数据进行训练
sess.run(train_step, feed_dict={x:batch_xs, y_:batch_ys})
6.8、检测训练结果,并将模型保存
#检测训练结果,tf.argmax取出数组中最大值的下标,tf.equal再对比下标是否一样即可知道预测是否正确
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#correct_prediction得到的结果是True或者False的数组
#我们再经过tf.cast将其转为数字的形式,即将[True, True, Flase, Flase]转成[1, 1, 0, 0]
#最后用tf.reduce_mean计算数组中所有元素的平均值,即预测的准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#开始预测运算,并将准确率输出
print (sess.run(accuracy, feed_dict={x:mnist.test.images, y_:mnist.test.labels}))
#最后,将会话保存下来
saver.save(sess, './saver/mnist.ckpt')
6.9、运行结果
Extracting mnist_data/train-images-idx3-ubyte.gz
Extracting mnist_data/train-labels-idx1-ubyte.gz
Extracting mnist_data/t10k-images-idx3-ubyte.gz
Extracting mnist_data/t10k-labels-idx1-ubyte.gz
0.9215
可以看到用Softmax模型预测的准确率大概为92.15%左右
7、完整代码
#coding:utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
mnist = input_data.read_data_sets('mnist_data', one_hot=True)
#创建x占位符,用于临时存放MNIST图片的数据,
# [None, 784]中的None表示不限长度,而784则是一张图片的大小(28×28=784)
x = tf.placeholder(tf.float32, [None, 784])
#W存放的是模型的参数,也就是权重,一张图片有784个像素作为输入数据,而输出为10
#因为(0~9)有10个结果
#b则存放偏置项
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros(10))
#y表示Softmax回归模型的输出
y = tf.nn.softmax(tf.matmul(x, W) + b)
#_存的是实际图像的标签,即对应于每张输入图片实际的值
y_ = tf.placeholder(tf.float32, [None, 10])
#定义损失函数,这里用交叉熵来做损失函数,y存的是我们训练的结果,而y_存的是实际标签的值
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y)))
#优化函数,这里我们使用梯度下降法进行优化,0.01表示梯度下降优化器的学习率
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
#将训练结果保存,如果不保存我们这次训练结束后的结果也随着程序运行结束而释放了
saver = tf.train.Saver()
#上面所做的只是定义算法,并没有真的运行,tensorflow的运行都是在会话(Session)中进行
with tf.Session() as sess:
#初始化所有变量
tf.global_variables_initializer().run()
#开始训练,这里训练一千次
for _ in range(1000):
#每次取100张图片数据和对应的标签用于训练
batch_xs, batch_ys = mnist.train.next_batch(100)
#将取到的数据进行训练
sess.run(train_step, feed_dict={x:batch_xs, y_:batch_ys})
print (sess.run(W))
print (sess.run(b))
#检测训练结果,tf.argmax取出数组中最大值的下标,tf.equal再对比下标是否一样即可知道预测是否正确
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#correct_prediction得到的结果是True或者False的数组
#我们再经过tf.cast将其转为数字的形式,即将[True, True, Flase, Flase]转成[1, 1, 0, 0]
#最后用tf.reduce_mean计算数组中所有元素的平均值,即预测的准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#开始预测运算,并将准确率输出
print (sess.run(accuracy, feed_dict={x:mnist.test.images, y_:mnist.test.labels}))
#最后,将会话保存下来
saver.save(sess, './saver/mnist.ckpt')
8、使用训练结果直接进行预测
上面实例既然将训练结果保存了,下面就顺便写写怎么直接使用训练结果进行预测的代码,为了简单起见,不用已保存的计算图,而是直接拷贝上面的代码来改。
其实只要在使用训练结果前,将我们上面保存的训练结果导入即可
saver.restore(sess, './saver/mnist.ckpt')
完整代码如下
# coding: utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
mnist = input_data.read_data_sets('mnist_data', one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
w = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros(10))
y = tf.nn.softmax(tf.matmul(x, w) + b)
y_ = tf.placeholder(tf.float32, [None, 10])
saver = tf.train.Saver();
with tf.Session() as sess:
#导入
saver.restore(sess, './saver/mnist.ckpt')
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print (sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
总结:
训练神经网络的过程:
1、定义神经网络的结构和前向传播输出结果
2、定义损失函数以及选择反向传播优化的算法
3、生成会话(tf.Session)并且在训练数据上反复运行反向传播优化算法