您的位置:首页 > 其它

tensorflow实战 Softmax Regression识别手写体数字

2018-03-27 21:39 633 查看
首先介绍一下MNIST数据集

MNIST数据集中每个图像是28*28像素大小的灰度图像,空白部分灰度值为0,有笔记的地方灰度值为(0,1]的取值,其中MNIST数据集中,训练样本为55000个,测试样本为10000个,验证集样本为5000个,每一个样本都有其对应的标签信息,即label。它们的图像如下图所示。它们各自的作用为,在训练集上训练模型;在验证集上检验结果并决定何时完成训练;在测试集上测试模型的效果(模型性能的衡量可以采用准确率,召回率(查全率),F1-score等来衡量,它们各自的计算方法,可以参考原来写的这篇博客)。



mnist数据集可以在该链接下下载。下载密码为:ezcj,同时已经将官网中的文件转化为图片。该文件中还包括常用的ATIS数据集以及IMDB数据集。

基于TensorFlow,实现softmax Regression手写体分类:

1. 数据样本的处理:

首先,对于TensorFlow的输入样本进行了处理,由于上述样本是28*28的像素点,所以每个样本有784维特征(softmax regression将二维的结构转化为一维的结构,没有考虑样本的空间信息,对于以后的卷积神经网络等会充分利用图像的空间信息),所以对于训练数据的特征是55000*784的tensor;

对于标签数据采用了one-hot编码(也成为一位有效位编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都有其独立的寄存器位,并且任何时候只有一位有效),所以每个样本的label是一个10维的向量,只有一个值为1,其余均为0。比如数字0,可以使用[1,0,0,0,0,0,0,0,0,0]表示;数字5,可以使用[0,0,0,0,0,1,0,0,0,0]表示。所以对于整个训练集的标签为55000*10的tensor表示。

2. 使用softmax regression实现手写体数字识别分类:

softmax regression会对每一种类别估算一个概率,然后选择概率值最大的类别最为最终的类别,比如预测为数字1的概率为20%,预测为数字5的概率为70%,则最终的类别为数字5。

它的工作原理很简单,将可以判定为某类的特征相加,然后将这些特征转化为判定是这类的概率。它的数学表达式可以理解为:

(1)计算每一个类别的特征:

featurei=∑jWi,jxj+bifeaturei=∑jWi,jxj+bi

其中,ii代表第ii类,jj代表一张图像的第jj个像素。

(2)对所有特征计算softmax,得到预测为每一类的概率:

softmax(featurei)=exp(featurei))∑9a=0exp(f<
10ef8
/span>eaturea))softmax(featurei)=exp(featurei))∑a=09exp(featurea))

其中,分母表示的含义为将每个类别的指数求和,0—9代表10个预测的类别。

它的过程可以理解为先对每个类别的特征求exp函数,然后对它们进行标准化,使得和为1,特征的值越大的类别,最后输出的概率也越大。

整个过程可用使用下图表示:



将上述流程使用矩阵乘法的数学表达式为:



上述的矩阵运算表达式可以简写为:

y=softmax(Wx+b)y=softmax(Wx+b)

softmax Regression可以算作没有隐含层的最浅的神经网络。实现的过程主要分为四个阶段:

1. 定义算法公式,即神经网络前向传播的计算;

2. 定义损失函数,选定优化器,并且制定优化器优化损失函数;

3. 迭代地对数据进行训练;

4. 在测试集或者验证集上对准确率进行计算。

下面介绍使用tensorflow实现softmax手写体识别的代码:

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

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# 输出mnist训练集测试集以及验证集样本以及标签的规模
print(mnist.train.images.shape, mnist.train.labels.shape)
print(mnist.test.images.shape, mnist.test.labels.shape)
print(mnist.validation.images.shape, mnist.validation.labels.shape)

max_step = 1000 #最大迭代次数

# 搭建神经网络结构
# 创建输入数据
x = tf.placeholder(tf.float32, [None, 784])

# 定义权重和偏置,权重和偏置的维度有输入和输出决定
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

# 神经网络的前向传播,并且实现softmax分类
y = tf.nn.softmax(tf.add(tf.matmul(x, W), b))

# 创建真实标签数据
y_ = tf.placeholder(tf.float32, [None, 10])

# 使用交叉熵计算损失
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
reduction_indices = [1]))

# 使用反向传播算法进行模型训练
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

# 创建会话,并且初始化全部变量
init_op = tf.global_variables_initializer()
sess = tf.InteractiveSession()
sess.run(init_op)

# 迭代执行训练操作
for i in range(max_step):
# 每次从训练数据中随机选取100个样本,构成一个mini-batch
batch_xs, batch_ys = mnist.train.next_batch(100)
train_step.run({x: batch_xs, y_: batch_ys})

# 计算模型在训练集中的分类精度
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

# 计算模型在测试集中的分类精度
print(accuracy.eval({x: mnist.test.images, y_:mnist.test.labels}))


下面对上述代码中一些重要的语法做一些简答的介绍:

1. x = tf.placeholder(tf.float32, [None, 784])

在该语法中,[None, 784]其中None代表不限制个数的输入,也就是输入的x可以是任意行,784列的数据。关于placeholder以及session的说明可以查看这篇博客

2. y = tf.nn.softmax(tf.add(tf.matmul(x, W), b))

softmax是tf.nn内部的函数,tf.nn中包含了大量的神经网络的组件。tf.matmul是tensorflow中实现矩阵乘法的语句。

3. cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices = [1]))

对于多分类问题,一般我们采用交叉熵作为损失函数,它的计算公式为:

Hy′(y)=−∑iy′ilog(yi)Hy′(y)=−∑iyi′log(yi)

其中,y是预测的概率分布,y’是真实的概率分布。

上述的tf.reduce_sum(y_ * tf.log(y), reduction_indices = [1]),其中tf.reduce_sum表示求和含义,里面的reduction_indices默认值为None,即把input_tensor降到0维,也就是一个数。对于2维input_tensor,reduction=[0]代表按列维度缩减;reduction=[1]代表按行维度缩减。

4. train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

该语句代表使用随机梯度下降优化算法对损失函数最小化,学习率设置为0.5。这就是tensorflow强大的地方,只要定义好损失函数,训练时会自动的求导并进行梯度下降,同时自动的进行神经网络的前向传播以及反向传播,完成对softmax Regression模型参数的自动学习。

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

该语句实现准确率的验证。其中tf.argmax代表从一个tensor中寻找一个最大值的序号。tf.argmax(y, 1)代表预测的结果中概率最大的一个值的索引,也就是对应的类别;tf.argmax(y_, 1)代表从标签中选择出一个最大的索引,由上面的介绍中我们可以得到,label采用的是one-hot编码,最大值的索引就是真实的类别。

6. accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

tf.cast函数代表的数值类型的转化,上面函数将correct_prediction中的值转化为float32类型。

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

eval是sess.run()的另一种表达方法,上述表达式完全可以修改为sess.run(accuracy, {x: mnist.test.images, y_:mnist.test.labels})

值得注意的是,tensorflow与Spark类似,我们定义的各个公式其实只是计算图,在执行这行代码时,计算实际上还没有进行,只有调用run的时候,并且对feed_dict传入数据时,计算才真正执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息