Tensorflow入门程序MNIST学习

本文介绍了TensorFlow的基本应用,通过MNIST数据集展示了如何使用TensorFlow进行手写数字识别。首先介绍了MNIST数据集及其下载方式,接着分析了数据集的结构。文章详细解释了使用Softmax回归和卷积神经网络(CNN)两种方法进行模型训练,并对比了它们的效果。
摘要由CSDN通过智能技术生成

一.TensorFlow简介

TensorFlow是一个非常强大的用来做大规模数值计算的库。其所擅长的任务之一就是实现以及训练深度神经网络。(TensorFlow中文社区网址:http://www.tensorfly.cn/)其安装过程这里就不做详细的介绍了,网上有很多教程可以顺利安装,下面就开始介绍如何使用TensorFlow吧~

二.示例程序MNIST

1.MNIST简介

好比编程入门有Hello World,机器学习入门有MNIST。

MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片:

它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是5,0,4,1。

2.MNIST数据集下载

下载地址:http://wiki.jikexueyuan.com/project/tensorflow-zh/tutorials/mnist_download.html

点击图中蓝色的文件链接即可下载。MNIST数据集被大体分为两部分:60000行的训练数据集和10000行的测试数据集。具体分为四个部分,分别为训练图片集,训练标签集,测试图片集,测试标签集。

也可以在程序中进行自动下载,代码如图:


2.MNIST数据集分析

在MNIST图片集中,所有的图片都有28×28=784个像素。因此,在MNIST训练数据集中,mnist.train.images 是一个形状为 [60000, 784] 的张量,第一个维度数字用来索引图片,第二个维度数字用来索引每张图片中的像素点。在此张量里的每一个元素,都表示某张图片里的某个像素的强度值,值介于0和1之间。

相对应的MNIST数据集的标签是介于0到9的数字,用来描述给定图片里表示的数字。我们使标签数据是"one-hot vectors"。 一个one-hot向量除了某一位的数字是1以外其余各维度数字都是0。比如,标签0将表示成([1,0,0,0,0,0,0,0,0,0,0])。因此, mnist.train.labels 是一个 [60000, 10] 的数字矩阵。




3.研究方法分析

MNIST问题本质上也是一个分类问题,只不过与我们经常接触的二分类问题不同(逻辑回归),它是一个多分类问题,所以需要一个分类模型来给不同的对象分配概率,在此用到了经典的Softmax回归模型。TensorFlow中文社区中对Softmax回归模型讲解的十分清楚(http://www.tensorfly.cn/tfdoc/tutorials/mnist_beginners.html

4.简单算法

(代码如果运行出现错误可能是tensorflow的版本有问题,我用的是r1.2的版本,以前版本的语法请自行百度)

# -*- coding: utf-8 -*- 

import tensorflow as tf

#导入input_data用于自动下载和安装MNIST数据集
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

#创建一个交互式Session
sess = tf.InteractiveSession()

"""
创建两个占位符,x为输入网络的图像,y_为输入网络的图像类别
placeholder的作用是先hold住变量,等到sess启动之后可以从外部传入值,与feed_dict配合使用,下面有使用到
"""
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])

#W为权重,b为偏置
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

#初始化变量并启动sess
sess.run(tf.initialize_all_variables())

#实现softmax模型,y为预测的概率分布
y = tf.nn.softmax(tf.matmul(x,W) + b)

"""
在机器学习,通常定义指标来表示一个模型是坏的,这个指标称为成本(cost)或损失(loss),然后尽量最小化这个指标
在这里我们使用交叉熵,用来衡量我们的预测用于描述真相的低效性,其值越小表示预测的越准确
"""
cross_entropy = -tf.reduce_sum(y_*tf.log(y))

"""
TensorFlow用梯度下降算法(gradient descent algorithm)以0.01的学习速率最小化交叉熵
梯度下降算法(gradient descent algorithm)是一个简单的学习过程,TensorFlow只需将每个变量一点点地往使成本不断降低的方向移动。
"""
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

#开始训练模型,这里我们让模型循环训练1000次!
for i in range(1000):
  batch = mnist.train.next_batch(50)
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})

"""
tf.argmax 函数能给出某个tensor对象在某一维上的其数据最大值所在的索引值
由于标签向量是由0,1组成,因此最大值1所在的索引位置就是类别标签
比如tf.argmax(y,1)返回的是模型对于任一输入x预测到的标签值,而 tf.argmax(y_,1) 代表正确的标签
我们可以用 tf.equal 来检测我们的预测是否真实标签匹配(索引位置一样表示匹配)

"""
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

#计算所学习到的模型在测试数据集上面的正确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

print accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels})

运行结果:

可以看到,简单的使用softmax回归最后的精确度只有0.9175,效果不是十分理想,所以需要改进代码,这里使用卷积神经网络来改善效果。

5.使用卷积神经网络改进之后的算法

# -*- coding: utf-8 -*- 

import tensorflow as tf

#导入input_data用于自动下载和安装MNIST数据集
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

#创建一个交互式Session
sess = tf.InteractiveSession()

#创建两个占位符,x为输入网络的图像,y_为输入网络的图像类别
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])

#权重初始化函数
def weight_variable(shape):
    #输出服从截尾正态分布的随机值
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

"""
偏置初始化函数,由于我们使用的是ReLU神经元
因此比较好的做法是用一个较小的正数来初始化偏置项
以避免神经元节点输出恒为0的问题(dead neurons)

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

"""
*************************************卷积池化解释*************************************
在卷积的过程中,如果x和y方向的跨度太大,会导致图片的信息丢失,所以在这里,
我们使x和y移动的步长都为1,然后通过池化移动的步长为2来进行图像压缩!

创建卷积
卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入是同一个大小
x 是一个4维张量,shape为[batch,height,width,channels]
卷积核移动步长为1。填充类型为SAME,可以不丢弃任何像素点
strides=[1,x_movement,y_movement,1],第一位和第四位必须为1!!!

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

"""
创建池化
采用最大池化max pooling,也就是取窗口中的最大值作为结果
x 是一个4维张量,是conv2d卷积之后传出的结果,shape为[batch,height,width,channels]
ksize表示pool窗口大小为2x2,也就是高2,宽2
strides,表示在height和width维度上的步长都为2,

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

"""
*************************************创建神经网络层*************************************
第一层卷积层
初始化W为[5,5,1,32]的张量,表示卷积核patch大小为5像素*5像素,
第一层网络的输入图片高度为1(只有黑白颜色),输出图片高度为32个单位
相应偏置量b初始化为[32],即输出大小

"""
W_conv1 = weight_variable([5,5,1,32])
b_conv1 = bias_variable([32])

#为了使用卷积层,我们把x变成一个4维向量
#第一维(-1)表示自动推测这个维度的size
#其第2、第3维对应图片的宽(28像素)、高(28像素),最后一维代表图片的颜色通道数
#(因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3)

x_image = tf.reshape(x, [-1,28,28,1])

#我们把x_image和权值向量进行卷积,加上偏置项,然后应用ReLU激活函数,最后进行max pooling 
#h_conv1的大小为28*28*32,因为卷积的padding方式为”SAME"表示卷积前后图片的长宽不变为28,图片的高度变为了32
#h_pool1的输出即为第一层网络输出,shape为[batch,14,14,32],大小为14*14*32,因为在池化时步长为2,所以长宽都缩小一倍为14
#卷积加上池化可以更好的保存原始图片的信息!!!

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

"""
第二层卷积层
卷积核大小依然是5*5,这层的输入图片高度和输出图片高度为32和64

"""
W_conv2 = weight_variable([5,5,32,64])
b_conv2 = weight_variable([64])

#h_pool2的大小为14*14*64
#h_pool2即为第二层网络输出,shape为[batch,7,7,64],大小为7*7*64
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

"""
第三层全连接层
图片尺寸减小到7x7,我们加入一个有1024个神经元的全连接层,用于处理整个图片,让图片高度变得更高
W的第1维size为7*7*64,7*7是h_pool2输出的size,64是第2层输出神经元个数

"""
W_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])

#把池化层输出的向量[batch,7,7,64]reshape成向量[batch, 7*7*64],batch表示样本的数量,-1表示自动推测这个维度的size
#处理之后乘上权重矩阵,加上偏置,然后对其使用ReLU
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("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

"""
输出层
最后,添加一个softmax层
可以理解为另一个全连接层,只不过输出时使用softmax将网络输出值转换成了概率
输出为0-9十个数字的概率

"""
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

"""
*************************************训练和评估预测模型*************************************
"""
#预测值和真实值之间的交叉墒
cross_entropy = -tf.reduce_sum(y_ * tf.log(y_conv))

#train op, 与上一个简单的代码不同,对于这个庞大的系统,这里使用ADAM优化器来做梯度下降更优。学习率为0.0001
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

#评估模型,tf.argmax能给出某个tensor对象在某一维上数据最大值的索引。
#因为标签是由0,1组成了one-hot vector,返回的索引就是数值为1的位置
correct_predict = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))

#计算正确预测项的比例,因为tf.equal返回的是布尔值,
#使用tf.cast把布尔值转换成浮点数,然后用tf.reduce_mean求平均值
accuracy = tf.reduce_mean(tf.cast(correct_predict, "float"))

#初始化变量
sess.run(tf.initialize_all_variables())

#开始训练模型,循环20000次,每次随机从训练集中抓取50幅图像
for i in range(20000):
    batch = mnist.train.next_batch(50)
    if i%100 == 0:
        #每100次输出一次日志
        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})

运行结果:

可以看到,应用卷积神经网络之后的预测准确率提升到了0.9935,效果还是很不错的。

6.总结两种算法

简单算法中,没有对数据进行处理,直接用SoftMax回归进行预测,效果不是特别理想。

卷积神经网络算法中,首先创建了两层卷积网络,每层都是先通过卷积提取信息,再通过池化压缩信息,两层卷积之后,将结果reshape成一般的shape,然后传入平常使用的神经网络系统之中进行训练与预测。

好啦,这就是TensorFlow的入门程序介绍,希望对这个方向有兴趣的同学看过这篇博客可以有所收获,以上~


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值