Tensorflow实现Softmax Regression识别手写数字
一、MNIST数据集
MNIST数据集是一个非常简单的机器视觉数据集,由几万张28*28像素的手写数字组成,且这些数字只包含灰度值信息。
二、TensorFlow代码实现
1 # -*- coding: utf-8 -*- 2 """ 3 Created on Thu May 16 21:39:25 2019 4 5 @author: CFF 6 """ 7 import tensorflow as tf 8 from tensorflow.examples.tutorials.mnist import input_data 9 mnist = input_data.read_data_sets("MNIST_data", one_hot=True) 10 batch_size = 100 11 X_holder = tf.placeholder(tf.float32) 12 y_holder = tf.placeholder(tf.float32) 13 14 Weights = tf.Variable(tf.zeros([784, 10])) 15 biases = tf.Variable(tf.zeros([1,10])) 16 predict_y = tf.nn.softmax(tf.matmul(X_holder, Weights) + biases) 17 loss = tf.reduce_mean(-tf.reduce_sum(y_holder * tf.log(predict_y), 1)) 18 optimizer = tf.train.GradientDescentOptimizer(0.5) 19 train = optimizer.minimize(loss) 20 21 session = tf.Session() 22 init = tf.global_variables_initializer() 23 session.run(init) 24 25 for i in range(500): 26 images, labels = mnist.train.next_batch(batch_size) 27 session.run(train, feed_dict={X_holder:images, y_holder:labels}) 28 if i % 25 == 0: 29 correct_prediction = tf.equal(tf.argmax(predict_y, 1), tf.argmax(y_holder, 1)) 30 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 31 accuracy_value = session.run(accuracy, feed_dict={X_holder:mnist.test.images, y_holder:mnist.test.labels}) 32 print('step:%d accuracy:%.4f' %(i, accuracy_value))
三、原理分析
①、图像的取值:空白部分全部为0,有笔迹部分根据颜色深浅有0-1之间取值。每一张图片有784维的特征,即由28*28个像素点(28*28=784)展开成1维的结果。故丢弃了图片的二维结构方面的信息,直接把一张图片变成一个很长的1维向量。
②、整个数据集的特征是一个55000*784的Tensor,同时训练的数据Label是一个55000*10维的Tensor,对10个种类进行one-hot编码,Label是一个10维向量。例如对于数字0的标签就是[1,0,0,0,0,0,0,0,0,0]。
③、使用Softmax Regression的算法训练手写数字识别的分类模型,Softmax Regression的原理就行对每一种类别估算一个概率,然后取概率最大的那个数字作为模型的输出结果。即将可以判定为某一类的特征相加,再将这些特征转化为判定这一类的概率。例如某个像素的灰度值大代表很可能是数字n时,这个像素的权值就很大,反之,这个像素的权值就很小。特征的公式表示如下:
featurei=ΣjWi,j*xj+bi
对所有特征计算softmax,即都计算一个exp函数,再进行标准化(即让所有类别输出的概率值为1)。公式如下:
softmax(x)=normalize(exp(x))
判断第i类的概率可以有下列公式计算:
softmax(x)i=exp(xi)/Σjexp(xj)
先对各个类的特征求exp函数,再进行标准化,使得和为1,特征的值越大的类,最后输出的概率就越大,反之,特征的值越小的类,最后输出的概率就越小。Softmax Regression流程如下:
上图对应公式如下:Softmax Regression元素的乘法
变成对应的矩阵乘法如下:
最后变成y=softmax(Wx+b)。
④、使用TensorFlow实现一个softmax regression,首先导入TensorFlow库并创建一个新的InteractiveSession,使用这个命令将这个session注册为默认的session,之后的运算默认在这个session里面跑。接下来创建一个Placeholder,用来输入数据,Placeholder的第一个参数是数据类型,第二个参数[None,784]表示Tensor的shape,None表示输入条数不限,每条输入是一个784维的向量。
1 import tensorflow as tf 2 sess = tf.InteractiveSession() 3 x = tf.placeholder(tf.float32,[None,784])
⑤、给Softmax Regression模型中的weights和biases创建Variable对象,Variable是用来存储模型参数,不同于存储数据的tensor一旦使用掉就会消失,而Variable在模型训练迭代中是持久化的(比如一直存放在显存中),可以长期存在并且在每一轮迭代中被更新。weights和biases全部初始化为0,因为模型训练时会自动学习合适的值。对于这个简单的模型,初始化值不太重要,但对于复杂的卷积网络、循环网络或者比较深的全连接网络,初试值的方法比较重要。W的shape是[784,10],784是特征的维数,10表示有10类,因为Label在one-hot编码后是10维的向量。
1 W=tf.Variable(tf.zeros([784,10])) 2 b=tf.Variable(tf.zeros([10]))
3 y=tf.nn.softmax(tf.matmul(x,w)+b)
Softmax是tf.nn下面的一个函数,tf.nn包含了大量神经网络的组件,tf.matmul是TensorFlow中的矩阵乘法函数。TensorFlow将forward和backward的内容都自动实现。只要接下来定义好loss,训练时将会自动求导并进行梯度下降,完成对Softmax Regression模型参数的自动学习。
⑥、为了训练模型,需要定义loss function来描述模型对问题的分类精度。loss越小,表示模型的分类结果与真实值的偏差越小,即模型精度越高。首先给模型填充全零的参数,模型就有一个初始的loss,训练的目的就是不断将这个loss减小,直到到达一个全局最优或局部最优解。对于多分类,通常使用cross-entropy作为loss function。cross-entropy最早出自信息论中的信息熵(与压缩比率等有关)。Cross-entropy的定义如下:
Hy'(y)=-Σiy’ilog(yi)
其中y是预测的概率分布,y'是真实的概率分布(即Label的one-hot编码),通常使用这个来判断模型对真实概率分布估计的准确程度。
1 y_ = tf.placeholder(tf.float32,[None,10]) 2 cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=[1]))
先定义一个placeholder,输入是真实的label,用来计算cross-entropy。y_*tf.log(y)是y’ilog(yi),tf.reduce_sum也就是求和Σ,而tf.reduce_mean用来对每个batch数据结构求均值。
⑦、定义优化算法,常见的随机梯度SGD,定义好优化算法后,TensorFlow就可以根据定义的整个计算图自动求导,并根据方向传播算法进行训练,每一轮迭代时更新参数来减小loss。TensorFlow会自动在后台添加许多运算操作来实现反向传播和梯度下降,每轮迭代时feed数据放入优化器就可以了。直接调用tf.train.GradientDescentOptimizer,并设置学习率为0.5,优化目标设定为cross-entropy,得到进行训练的操作train_step。
1 train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy) 2 # 使用全局优化器tf.global_variables_initializer,并直接执行run()方法 3 tf.global_variables_initializer().run()
⑧、开始迭代训练操作train_step。每次随机从训练集中抽取100条样本构成一个mini-batch,并feed给placeholder,如何调用train_step对这些样本进行训练。使用一小部分样本进行训练称为随机梯度下降。如果每次训练都使用全部样本,计算量太大,有时也不容易跳出局部最优。对于大部分机器学习问题,都只使用一小部分数据进行随机梯度下降,这种方法收敛速度快很多。
1 for i in range(1000): 2 batch_xs,batch_ys=mnist.train.next_batch(100) 3 train_step.run({x:batch_xs,y_:batch_ys})
⑨、完成训练后,对模型的准确率进行验证。tf.argmax是从tensor中寻找最大的序号,tf.argmax(y,1)就是求各个预测的数字中概率最大的那一个。tf.argmax(y_,1)是找样本的真实数字的类别。tf.equal方法用来判断预测的数据类别是否就是正确的类别,返回计算类别是否正确的操作correct_predition
1 correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(y_,1)) 2 accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) 3 print(accuracy.eval({x:mnist.test.images,y_:mnist.test.labels}))
先用tf.cast将输出的bool值转换为float32,再求平均值。将测试数据的特征和label输入评测流程accuracy,计算模型在测试集上的准确性,再将结果打印出来。
⑩、总结,使用TensorFlow实现一个简单的机器学习算法Softmax Regression,这是一个没有隐藏层的最浅的神经网络。主要分为四个步骤:
(1)定义算法公式,即神经网络forward时的计算
(2)定义loss,选定优化器,并指定优化器优化loss
(3)迭代地对数据进行训练
(4)在测试集或验证集上对准确度进行评测