TensorFlow实现识别手写数字

来源:互联网 发布:男装淘宝店铺运营外包 编辑:程序博客网 时间:2024/03/29 03:34

当学习一门新的编程语言的时候,我们总是以输出“hello word”作为学习这门编程语言的开始,表示我们开启了这门编程语言的大门。而在机器学习的领域中,识别手写数字就像输出“hello word”一样作为开启了机器学习的大门。

一、MNIST介绍

MNIST:在实现手写数字识别需要使用到手写数字的图片,是从MNIST下载的。MNIST(Modified National Institute of Standards and Technology)是一个大型数据库的手写数字通常用于训练各种图像处理系统。MNIST将手写数字数据集分为两个部分,训练集和测试集。训练集包括了60000行的训练数据,测试集包括了10000行的测试数据,每一个数据都是有一张手写数字图片和其对应的标签组成。每一张手写数字图片的大小为28*28(长和宽),总共由784个像素点组成。

二、数据的预处理

数据预处理:在机器学习训练模型的过程中,数据的预处理占有非常重要的作用,指从数据源获取数据之后直接处理数据。一般,在使用机器学习训练某一个模型的时候,需要将原数据经过一定的处理之后,再用于模型的训练。在手写数字识别的模型中,输入的数据是一张的图片,为了简化处理,将每张28*28的图片装换成了一个784维的向量,很显然在转换的过程中,不得不丢弃了图片的二维结构信息,如果想要不丢弃图片的二维结构信息,可以使用卷积,在这个例子中,做了简化处理。手写数字识别的模型中,最终的目的是将一张图片与一个数字(0-9)进行对应,其实也就是将这个问题转换成了一个多分类的问题进行处理。在机器学习中,对于多分类问题,可以使用softmax回归进行处理。在MNIST数据集中,mnist.train.images是一个形状为[59999,784]的张量,第一维的大小代表的是MNIST中作为训练数据的大小,所以第一维的大小为0到59999,0表示的就是第一张图片,所以最大是到59999。第二维表示的是这张图片的784个像素在图片上的强度值(在0到1之间),如[0,0,....0.342,0.4232....]。而,mnist.train.labels是一个[59999,10]的张量,第一维的表示是图片的下标,第二维表示的是那个数字,10表示的是一个10维的向量,如9表示就是[0,0,0,0,0,0,0,0,0,1]。

三、softmax函数

softmax是logistic的推广形式,logistic主要用于处理二分类问题,当结果y大于0.5的时候为1类,小于0.5的时候为0类,而softmax则是用于处理多分类问题。softmax函数是逻辑函数的一种推广,它可以将一个含有任意实数的k维向量z“压缩”到另一个k维实向量中,被压缩到的k维实向量中元素的范围都在(0,1)之间,而且所有的元素之和为1。softmax函数的形式如下:


下面引用维基百科的一个例子来形象简单的说明一下softmax:

输入向量{\displaystyle [1,2,3,4,1,2,3]}对应的Softmax函数的值为{\displaystyle [0.024,0.064,0.175,0.475,0.024,0.064,0.175]}。输出向量中拥有最大权重的项对应着输入向量中的最大值“4”。这也显示了这个函数通常的意义:对向量进行归一化,凸显其中最大的值并抑制远低于最大值的其他分量。
下面是使用Python进行函数计算的示例代码:

import mathz = [1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0]z_exp = [math.exp(i) for i in z]  print(z_exp)  # Result: [2.72, 7.39, 20.09, 54.6, 2.72, 7.39, 20.09] sum_z_exp = sum(z_exp)  print(sum_z_exp)  # Result: 114.98 softmax = [round(i / sum_z_exp, 3) for i in z_exp]print(softmax)  # Result: [0.024, 0.064, 0.175, 0.475, 0.024, 0.064, 0.175]
四、交叉熵代价函数
在上一篇博客使用TensorFlow来设计一个线性回归模型的时候,有介绍到平方差代价函数,平方差代价函数也是一种比较常用的函数。但是,它存在一个缺点就是下降的速度太慢,导致需要经过很多次的迭代,才能接近期望的结果。举一个例子,比如说我们在考试的时候做某道题目,当考试卷发下来之后,我们发现这道题目做错了,那么我们下次就不会在犯同样的错误。而,平方差代价函数要经过很多次错误之后,它才能慢慢的改正过来。交叉熵代价函数在保证拥有平方差代价函数的优点之外,它还能很好的弥补平方差代价函数的缺点。

五、代码实现手写数字的识别

from tensorflow.examples.tutorials.mnist import input_dataimport tensorflow as tfif __name__ == "__main__":    #定义输入变量,使用TensorFlow中的占位符    x = tf.placeholder("float",[None,784])    #定义模型的权重,初始化为0    w = tf.Variable(tf.zeros([784,10]))    #定义模型的偏置,初始化为0    b = tf.Variable(tf.zeros([10]))    #定义模型的输出,y是一个大小为10的一维向量,代表这张手写数字图片为0-9的概率    y = tf.nn.softmax(tf.matmul(x,w) +  b)    #使用交叉熵作为代价函数    y_ = tf.placeholder("float",[None,10])    #计算交叉熵,cross_entropy恒为正数,一维y中每个数的大小为0-1之间,所以log(y)小于0    cross_entropy = -tf.reduce_sum(y_ * tf.log(y))    #使用梯度下降来最小化交叉熵    train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)    #初始化Variable变量    init = tf.initialize_all_variables()    session = tf.Session()    session.run(init)    #下载minist的手写数字的数据集    mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)    for i in range(1000):        # 每次迭代使用100个数据        batch_xs,batch_ys = mnist.train.next_batch(100)        # batch_xs为 y = tf.nn.softmax(tf.matmul(x,w) +  b)中的输入x        # batch_ys为模型中的实际输出值        session.run(train_step,feed_dict={x:batch_xs,y_:batch_ys})    # 如果模型的输出与实际的输出相同,则代表预测正确,返回的是一个bool类型的数组    correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(y_,1))    #将bool类型的数组装换成准确率,如[True,Flase,True],准确率为2/3    accuracy = tf.reduce_mean(tf.cast(correct_prediction,"float"))    print(session.run(accuracy,feed_dict={x:mnist.test.images,y_:mnist.test.labels}))    #0.9182


原创粉丝点击