tensorflow识别MNIST数据集

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_38854519/article/details/81514896

目录

数据准备

1、引入MNIST数据集

2、保存前30条数据的原始图片

 一、softmax实现单神经元模型

1、初始化变量

2、向前传播以及损失函数

3、向后传播以及优化参数

4、开始训练

5、评估模型

补充

二、两层卷积网络分类

1、初始化变量

2、预定义函数

3、卷积层

4、全连接层

5、定义交叉熵损失以及测试的准确率

6、开始训练

总结


数据准备

简单的说,MNIST就是一组最基础的数据集,M代表Modified,NIST代表国家标准和技术研究所,包括从0~9的训练数字的图片,这个分类问题是机器学习最简单和最广泛使用的测试之一。

1、引入MNIST数据集

from tensorflow.examples.tutorials.mnist import input_data
# 从MNIST_data/中读取MNIST数据。这条语句在数据不存在时,会自动执行下载
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# 查看训练数据的大小
print(mnist.train.images.shape)  # (55000, 784)
print(mnist.train.labels.shape)  # (55000, 10)

# 查看验证数据的大小
print(mnist.validation.images.shape)  # (5000, 784)
print(mnist.validation.labels.shape)  # (5000, 10)

# 查看测试数据的大小
print(mnist.test.images.shape)  # (10000, 784)
print(mnist.test.labels.shape)  # (10000, 10)

MNIST官网下载的四个数据包放在MNIST_data中。不需要解压,不需要解压,不需要解压。

若没有数据包,Tensorflow会检测到并且会自动下载到MNIST_data文件夹中。

2、保存前30条数据的原始图片

import scipy.misc
import os

# 我们把原始图片保存在MNIST_data/raw/文件夹下
# 如果没有这个文件夹会自动创建
save_dir = 'MNIST_data/raw/'
if os.path.exists(save_dir) is False:
    os.makedirs(save_dir)

# 保存前30张图片
for i in range(30):
    # 请注意,mnist.train.images[i, :]就表示第i张图片(序号从0开始)
    image_array = mnist.train.images[i, :]
    # TensorFlow中的MNIST图片是一个784维的向量,我们重新把它还原为28x28维的图像。
    image_array = image_array.reshape(28, 28)
    # 保存文件的格式为 mnist_train_0.jpg, mnist_train_1.jpg, ... ,mnist_train_19.jpg
    filename = save_dir + 'mnist_train_%d.jpg' % i
    # 将image_array保存为图片
    # 先用scipy.misc.toimage转换为图像,再调用save直接保存。
    scipy.misc.toimage(image_array, cmin=0.0, cmax=1.0).save(filename)

print('Please check: %s ' % save_dir)

 一、softmax实现单神经元模型

1、初始化变量

import tensorflow as tf
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]) 

因为图片是28x28像素的,所以1张图片,即x中的一张图片转化成(1,784)的向量,它的便签值y_也转化为向量(1,10)。

因为不确定样本的数量,所以用“占位符(placeholder)”占据一定形式的内存空间,等待用户传值来决定具体的样本数量。我理解成一个有784个小格子高度的容器,由用户来决定有多少个这样的容器。

w,b为“变量”,规定了维度具体大小,即规定了有784个10个格子高度的容器,并把格子中装的值初始化为0。

因为x的值是固定的,所以预测值y的值主要由w,b来决定。

思考:

a、占位符和变量的区别是什么?

b、什么是softmax?为什么使用softmax?

 

2、向前传播以及损失函数

为了确定预测的y与标签值y_的差距,需要定义cost function去评估预测的准确性,即算法的优良性。

cross_entropy =  tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y)))

思考:

a、该损失函数的具体原理是什么?

 

3、向后传播以及优化参数

为了最小化损失函数,需要向后传播计算出dw以及db,即w和b对损失函数的影响程度,然后通过w-学习率*dw、b-学习率*db更新w和b的值。当然,Tensorflow将这两步通过一行代码同时实现了:

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

 代码中学习率为0.01

 

4、开始训练

首先初始化所有变量并申请内存空间:

init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

 

 之后,梯度下降1000步:

for _ in range(1000):
    batch_xs,batch_ys = mnist.train.next_batch(100)
    sess.run(train_step,feed_dict={x:batch_xs,y_:batch_ys})

 运行完后,模型便已被训练完成了,即参数w,b已经被训练好,尽可能的使y(预测值)接近y_(标签纸),在损失函数的图像上,使值尽可能的接近最凹的点,即最优的点。

 

5、评估模型

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}))

输出: 

0.9168

思考:

a、为什么使用tf.argmax来进行评估?

 

补充

1、占位符和变量的区别是什么?

占位符和变量都属于Tensor(张量:一个数组中的元素分布在若干维的规则网格中,则称之为张量)。

占位符不依赖于其他Tensor,具体的值由用户传入,一般用来存储样本数据和标签值。

变量是计算过程中可以改变的值,每次计算后变量的值都会被保存下来,一般用来存储模型的参数。

2、什么是softmax?为什么使用softmax?

softmax函数是用于区分多个类别的函数,例如,对(a,b,c)三个类别进行softmax后,每个类别的概率为(\LARGE \frac{e^{a}}{e^{a}+e^{b}+e^{c}},\LARGE \frac{e^{b}}{e^{a}+e^{b}+e^{c}},\LARGE \frac{e^{c}}{e^{a}+e^{b}+e^{c}}),每个数值都在0-1,并且和为1。

相比于“hardmax”只将值表示为0或者1,softmax更详细的输出了每个类别的概率并且能够进行多个类别的判断,所以这里使用它。

3、 tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y))) 损失函数的具体原理是什么?

只从代码来看表示将 y_-{}\times (-\ln y)  公式的矩阵中所有值求和最后再求平均值。因为y的值肯定在0-1之间,为了保证损失值为正,添加符号取负。

若要损失函数的值最小:

当y_向量中某元素为0时,具体含义表示该图片不是某一张图,该项的损失函数值也为0,即相当于最后将10个类别的损失值求和的时候不考虑。

当y_向量中某元素为1时,只有当y的对应元素的值尽可能的接近1时,y_-{}\times (-\ln y)才尽可能最小,即尽可能接近0。所有让损失值最小的过程就是让预测值y的值无限接近真实值的情况。

4、为什么使用tf.argmax(y,1)来进行评估?

该函数表示取得最大值的下标,而值最大的元素的下标值就表示图片中真实数字的值。所以tf.argmax(y_,1)取得的下标值为真实图片的数字值,例如[0,2,7,1];tf.argmax(y,1)取得y向量中,对每个类别的预测值里最大值的下标值,即预测的图片的数字值,例如[8,2,7,5]。最后tf.equal进行比较,得到类似[0,1,1,0]的数组,通过tf.reduce_mean得到平均值0.5,表示预测准确率。

 

二、两层卷积网络分类

 采用单神经元进行预测,最后的准确率为大约为91.6%,采用卷积网络进行图片识别可将准确率提高到99%

1、初始化变量

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

#读入数据
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

#创建占位符
x = tf.placeholder(tf.float32,[None,784])
y_ = tf.placeholder(tf.float32,[None,10])

#将向量还原,-1表示第一维度由x的具体数据确定,即由x的矩阵中样本个数来确定
x_image = tf.reshape(x,[-1,28,28,1])

2、预定义函数

def weight_variable(shape):
    inital = tf.truncated_normal(shape)
    return tf.Variable(inital)

def bias_variable(shape):
    inital =tf.constant(0.1,shape=shape)
    return tf.Variable(inital)

def conv2d(x,W):
    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1,2,2,1],strides=[1,2,2,1], padding='SAME')

分别表示得到一定维度的参数,指定值的偏执项,卷积函数,2x2最大池化函数。

这里池化函数的过滤器为2x2,步长为2x2,当为此情况时,输出图片的维度是输入图片维度的一半

3、卷积层

#第一卷积层
w_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, w_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

#第二卷积层
w_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, w_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

第一卷积层:

32个5x5的卷积核进行卷积,padding为same,所以h_conv1的维度为(-1,28,28,32),-1表示该维度由具体样本数量决定;最后经过2x2最大池化卷积,得到h_pool,维度为(-1,14,14,32)

第二卷积层:

进行立体卷积,立体卷积时要保证卷积核的通道数与将要处理图片的通道数相同,所以卷积核维度为(5,5,32),有64个卷积核。h_conv2的维度为(-1,14,14,64),经过2x2池化层后,h_pool2的维度为(-1,7,7,64)

 

4、全连接层

#全连接层
w_fc1 = weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, w_fc1)+ b_fc1)

#使用dropout
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

#最后一层全连接层
w_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv = tf.matmul(h_fc1_drop,w_fc2)+b_fc2

第一层全连接层:

将h_pool2后三维转化成一维向量,输出1024维的向量;使用dropout,每一步训练时,一定概率的去掉全连接层中某些连接,防止过度拟合。

第二层全连接层:

将1024维度h_fc1_drop转化为10个类别的打分。

 

5、定义交叉熵损失以及测试的准确率

y_conv相当于softmax的logit(即wx+b),所以当然可以用softmax定义将其转换为10个类别的概率,再定义交叉熵损失。但是tensorflow有打包好的函数,直接对logit定义交叉熵损失: 

cross_entropy =  tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_,logits=y_conv))

 取预测后结果的平均值得到准确率:

correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

 

6、开始训练

#创建Session,对变量初始化
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())

# 训练20000步
for i in range(20000):
    batch = mnist.train.next_batch(50)
    # 每100步报告一次在验证集上的准确度
    if i % 100 == 0:
        train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})
        print("step %d, training accuracy %g" % (i, train_accuracy))
    train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})


# 训练结束后报告在测试集上的准确度
print("test accuracy %g" % accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

 

总结

主要完成了Tesorflow建立Softmax回归模型以及两层卷积的神经网络,了解如何读入数据集以及Tensorflow建立模型的基本流程:

  1. 创建还没有执行的tensor(以及自定义辅助函数)
  2. 给tensor间书写逻辑
  3. 初始化各个tensor
  4. 建立以及运行会话

 

展开阅读全文

没有更多推荐了,返回首页