笔记整理者:王小草
笔记整理时间2017年2月24日 原文地址 http://blog.csdn.net/sinat_33761963/article/details/56837466?fps=1&locationNum=5git
Tensorflow官方英文文档地址:https://www.tensorflow.org/get_started/mnist/beginners
本文整理时官方文档最近更新时间:2017年2月15日算法
本文是跟着Tensorflow官方文档的第二篇教程–识别手写数字。数组
MNIST是一个简单的计算机视觉数据集,它是由一系列手写数字图片组成的,好比: 数据结构
在数据集中,每一张图片会有一个标签label,表示该张图片上的数字是什么。好比以上图片所对应的标签是:5,0,4,1机器学习
对于初学者,为何开篇就要介绍这个案例呢?举个栗子, 当咱们学习写程序的时候,第一句打印的就是“Hello world”。那么MNIST相对于机器学习,就如同“Hello world”相对于程序ide
本文要介绍的是训练一个模型,使得这个模型能够根据输入的图片预测出上面写的是什么数字。可是本文的目的可不是去教你们训练一个具备超级优秀表现的完美模型哦(这个在以后的文档中会给出),而只是去创建一个简单的模型(softmax regression)让你们初尝tensorflow情滋味.函数
虽然要完成这个模型,对tensorflow只是几行代码的事,但理解这背后tensorflow运做的原理以及核心的机器学习概念也是至关重要呢。因此,接下去会对整个过程与原理都进行详细解释。学习
MNIST数据集能够在网站http://yann.lecun.com/exdb/mnist/下载到。
可是在TensorFlow中为了方便学习者获取这个数据,封装了一个方法,咱们只须要调用这个方法,程序就会自动去下载和获取数据集。代码以下:测试
// 导入input_data这个类
from tensorflow.examples.tutorials.mnist import input_data //从这个类里调用read_data_sets这个方法 mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
获取到的数据集有3部分组成:
(1)55,000个训练样本(用来训练模型)
(2)10,000个测试样本(用来测试模型,避免过拟合)
(3)5,000个验证样本(用来验证超参数)
(通常在机器学习的建模中,都须要准备这3类数据集。)优化
对于每个样本点,有两部分数据组成:
(1)手写数字图片,记作x
(2)标签,记作y
手写数字图片由28*28像素组成,能够将其转换成28*28的由数字组成的数组。以下例子:
而这个28*28的数组又能够铺平成1*784的一个向量。至于铺平的方式无所谓,只要保证全部图片被铺平的方式都同样就行啦。因此,一个图片能够被一个1*784的向量所表示。
可能你会问,把图片这样从二维空间铺平会不会丧失了一些信息,会带来坏的影响吗?这个你放心,如今那些最好的计算机图像处理方法都是用了这个结构的,这在以后的教程中会有讲到。
好了,若是运行以上两行代码成功,那么数据就已经下载下来了,能够直接调用mnist.train.images,获取训练数据集的图片, 这是一个大小为[55000, 784]的tensor,第一维是55000张图片,第二维是784个像素。像素的强度是用0-1之间的数字表示的。
另外上面也说了,每一个图片会对应一个标签,表示这个图片上对应的手写数字。
根据须要,咱们须要将这0-9的数字标签转换成one-hot编码,什么是One-hot编码,举个例子一看便知,好比原来的标签是3,编码以后就变成了[0,0,0,1,0,0,0,0,0,0],也就是生成一个1*10的向量,分别对应0-9的数字在3对应的位置上为1,其他位置上都是0.
通过这样编码以后,训练集的标签数据就变成了[55000,10]的浮点类型的数组了。
恩恩,数据都下载下来,而且咱们也知道数据的具体格式和内容啦,接下去,让咱们开始创建模型吧~~
由于咱们的目的是区分出0-9的数字,也就是要将图片在这10个类中进行分类,属于多元分类模型。对于一张图片,咱们想要模型获得的是属于这10个类别的几率,举个例子,若是模型判断一张图片属于9的几率由80%,属于8的几率是5%,属于其余数字的几率都很小,那么最后这张图片应被归于9的类别。
Softmax Regressions是一个很是经典的用于多分类模型的方法。就算是以后的笔记中讲到的更复杂的模型,他们的最后一层也是会调用Softmax 这个方法的。
一个Softmax Regressions主要有2步:
(1)分别将输入数据属于某个类别的证据相加
(2)将这个证据转换成几率
好了,那么首先这个证据是个神马东东呢,其实就是一个线性模型,由权重w,与偏执项b组成:
i表示第i类,j表示输入的这张图片的第j个像素,也就是求将每一个像素乘以它的权重w,在加上偏执项的和。
求出了evidence以后,就要使用softmax函数将它转换成几率了。
这里的softmax其实至关因而一个激活函数或者链接函数,将输出的结果转换成咱们想要的那种形式(在这里,是转换成10各种别上的几率分布)。那么这个softmax的过程是通过了什么样的函数转换呢?以下公式:
展开以上公式:
也就是说,将刚刚的线性输出evidence做为softmax函数里的输入x,先进过一个幂函数,而后作正态化,使得全部的几率相加等于1.
将softmax regression的过程画出来以下:
若是写成公式,那就是以下:
将以上公式作改进,变成矩阵和向量的形式:
要是想简单直观一点,那么就这样:
至此,咱们知道了多元分类Softmax Regressions的计算原理,那么接下去就能够去尝试用tensorflow来实现Softmax Regressions啦~
1.要使用tensorflow,实现导入tensorflow的库:
import tensorflow as tf
2.为输入数据x建立占位符
x = tf.placeholder(tf.float32, [None, 784])
这里的x并非具体的数值,而是一个占位符,就是先给要输入的数据霸占一个位置,等当真的让TensorFlow运行计算的时候,再传入x的真实数据。由于咱们的输入数据n个是1*784的向量,能够表示成2层的tensor,大小是[None,784],None表示到时候后传输的数据能够任何长度,也就是说能够是任何数量的样本点。
3.建立两个权重变量
w和b是在训练过程当中不断改变不断优化的,使用Variable来建立:
W = tf.Variable(tf.zeros([784, 10])) b = tf.Variable(tf.zeros([10]))
以上,咱们初始化两个权重都为0,在以后的训练与学习中会不断被优化成其余值。注意,w的大小是[784,10]表示784个像素输入点乘以10维的向量(10个类别)。b的大小是[ 10 ]
4.创建softmax模型
y = tf.nn.softmax(tf.matmul(x, W) + b)
以上代码可见,咱们先将x与W相乘了,而后加上了b,而后将线性输出通过softmax的转换。
嗯,至此softmax的模型就写好了。
1.创建损失函数
上面咱们搭建了一个初始的softmax的模型,注意模型中的参数w,b是本身随便定义的。那么训练模型的目的是让模型在学习样本的过程当中不断地优化参数,使得模型的表现最好。
那么如何评价模型表现的好坏呢?在机器学习中,咱们通常使用损失函数来评价模型的好坏。若是模型预测的结果与真实的结果相差越远,那么损失大,模型的表现就越很差。所以,咱们渴望去最小化损失从而获得最优的模型。
这里介绍一个最经常使用的损失函数:交叉熵损失。公式以下:
y表示模型预测出来的几率分布,y’表示真实的类别几率分布(就是之间one-hot编码以后的标签)。yi表示预测为第i个类的几率, yi’表示真实属于i类的几率(只有i类为1,其他为0)
交叉熵从必定意义上能够度量模型对于真实状况的拟合程度,交叉熵越大,则模型越不拟合,表现力越差。
要实现交叉熵函数,代码以下:
// 为真实的标签添加占位符
y_ = tf.placeholder(tf.float32, [None, 10]) // 建立交叉熵函数 cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
解释一下上面的代码,tf.log表示将y的每个元素都作log运算;而后将其乘以对应的真实标签的类别y_中的元素。tf.reduce_sum表示的是将索引为1的值进行求和。tf.reduce_mean表示对全部样本的交叉熵求均值。
注意注意,在源码中,咱们没有使用这个公式,由于这样计算下去数值不稳定。取而代之的是直接在线性函数以后应用了tf.nn.softmax_cross_entropy_with_gogits(即,没有单独通过softmax函数),这样会更加稳定。
2.使用BP算法优化参数
损失函数就是咱们的目标函数,要找到目标函数的最小值,就是对参数求偏导等于0.咱们可使用优化器去不断地下降损失寻找最优参数。好比说最经常使用的是梯度降低法。代码以下:
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
上面使用了梯度降低法最小化交叉熵损失,学习率设置为0.5,每一次迭代,w,b两类参数都会改变,直到损失达到最小的时候,就得到了最优的w,b。
不过tensorflow也提供了不少其余的优化器(后续介绍)
3.运行迭代
模型训练的graph基本已经完成,如今咱们能够初始化变量,建立会话,来进行循环训练了。
// 建立会话
sess = tf.InteractiveSession() // 初始化全部变量 tf.global_variables_initializer().run() //循环1000次训练模型 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})
在每次循环中,都会从训练集中获取一批样本,每批有100个样本。而后运行train_step这个操做,而且给以前的占位符喂入数据。
你可能会以为奇怪,为何不直接拿全部的训练集来作循环训练,为啥每次要随机地拿100个样本呢?这里应用了随机梯度降低法。直接使用全部样原本作循环迭代的“梯度降低法”当然更理想,可是会大大增长计算的成本,而“随机梯度降低法”减小了计算量而且也保持了相对一致的准确率。
经过模型的训练,咱们获得了最优的参数,可是在这个最优的参数下,模型的表现力到底如何呢?
咱们能够看看在测试集上模型预测的label与样本真实的Label相同的有多少比例。
tf.argmax返回的是一个tensor里在某个维度上最大值的索引,好比tf.argmax(y,1)取出的是预测输出的10个类别的几率向量中最大几率的那个索引(对应某个类别),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, tf.float32))
如今咱们喂入测试数据集,来运行计算测试集上的准确率:
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
打印出来大概是92%。
这个结果好吗?额。。其实并无呢,并且能够说挺差的。。
模型表现很差的缘由在于咱们使用的是一个很简单的模型,作一些小的改良,正确率能够达到97%。最好的模型能够达到99.7的准确率!
至此,咱们介绍了完整的用tensorflow来训练softmax regression多元分类模型的案例。