Windows | Tensorfow Softmax Regerssion

Tensorflow 实现 Softmax Regression 识别手写数字

        学习一门语言当然是从 Hello World 开始,接下来我们就以一个机器学习领域的 Hello World 任务 —— MNIST 手写数字识别来研究学习 Tensorflow。MNIST ( Mixed National Institute of Standards and Technology DataBase) 是一个简单的机器视觉数据集,MNIST 由几万张28像素*28像素的手写数字组成且这些图片只包含灰度值信息。


        首先加载 MNIST 数据集,Tensorflow为我们提供了一个方便的封装,可以直接加载 MNIST 数据。在自己的Python编辑器里输入运行下面的代码(推荐编译器 Sublime Text3:安装配置 Sublime Text3)。

        然后我们可以查看 MNIST 这个数据集的情况,可以看到训练集有55000个样本,测试集和验证集一共15000个样本。每一个样本都有它对应的标注信息(Labels)。MNIST实战的任务就是在训练集上训练模型,然后在验证集上检验效果并决定何时结束训练,最后在测试集评测模型的效果和准确率以及召回率(运行以下代码查看原数据集情况)。


        接下来就是设计代码来训练模型,前面说到这几万张图片只有灰度信息,即有笔迹的地方根据颜色的深浅有0到1之间的取值。同时,不难发现每张样本都有784维的特征(28*28=784个灰度值)。这也意味着我们将原来2维的图像转换成了一个很长的一维向量(或许有的人会问:很多情况下图像的二维都是存在价值的,为什么要破坏图像2维价值?)。因为MNIST的实战是Tensorflow的第一次尝试,所以我们不需要建立一个太复杂的模型,故这里将图像的2维转换成了1维向量(如下图所示)。


        从上图可以知道我们训练数据的特征是一个55000*784的张量(Tensor),第一个维度(上图的横坐标)是图片的编号,第二个维度(上图的纵坐标)是图片中像素点的编号。同时训练数据 Label 是一个55000*784张量(Tensor)。如下图所示,这里对10个种类进行了one_hot编码,Label是一个10维的向量,只有一个值为1其余都为0(即二进制用来储存10个数字)。如数字5的编码是[0,0,0,0,0,1,0,0,0,0] 数字2的编码是[0,0,1,0,0,0,0,0,0,0] 数字0的编码是[0,0,0,0,0,0,0,0,0,0]。


        准备好数据后接下来就要设计算法了,这里使用一个叫做 Softmax Regression 算法它的工作原理很简单,将可以判断为某类的特征相加,然后将这些特征转化为判断是这一个类的概率。我们可以将这些特征写成如下图第一条公式:i代表第i类(共10类) j代表一张图片的第j个像素(共784个像素) bi是bias(数据偏置,即如果大部分是数据都是0那么0的特征对应bias就会很大)。计算完特征后,对所有的特征计算 Softmax 如下图第二条公式(即将所有特征都计算一次 Exponential 函数,然后标准化让所有输出的概率值和为1)。最后判定这个特征为第i类概率就由下图第三条公式得到。


        接下来就是使用 Tensorflow 实现 Softmax Regression。首先载入 Tensorflow 并创建一个新的 InteractiveSession 让程序运行在这个 Session 里(不同的 Session 之间的数据和运算是相互独立的)。接下来创建一个 Placeholder 用来输入数据  Placeholder 的第一个参数是数据类型(float32),第二个参数[None,784]代表数据的尺寸(784维不限条数的输入)。


        然后要给 Softmax Regession 模型中的 Weights(权重)和 Biases(偏置)创建 Variable 对象,首先将 weights 和 biases 全部初始化为0,因为模型训练时会自动学习合适的值,所以对于这个简单模型来说初始值并不是很重要。初始化值完成后就要实现 Softmax Regession 算法下图第三条代码。Softmax 是 Tensorflow.nn 的一个函数且 Tensorflow.nn 包含了大量神经网络组件,同时因为 Tensorflow 包含了矩阵乘法函数 matmul 所以我们只用了一行代码就完成定义。


        为了训练模型,我们需要定义一个 Loss Function 来描述模型对问题的分类精度。Loss越小代表模型的分类结果与真实值的偏差越小也就意味着模型越精确。对于多分类的问题,通常使用 Cross-Entropy 作为 Loss Function(Cross-Entropy最早出自信息论中的信息熵,这里使用 Cross-Entropy 来计算损失Cross-Entropy的定义如下图,其中 y 是预测的概率分布 y_ 是真实的概率分布(即Label的one_hotb编码)通常可以用它来判断模型对真实概率分布估计的准确程度。


        现在我们有了算法 Softmax Regression 的定义,又有了损失函数 Cross-Entropy 的定义,只需要在定义一个优化算法即可以开始我们的训练。这里采用常见的随即梯度下降 SGD(Stochastic Gradient Descent)定义好优化算法后 Tensorflow 就可以根据我们定义的整个计算图自动求导并根据反向传播(Back Propagation)算法进行训练,在每一轮迭代时更新参数来减小损失(Loss)我们直接调用 Tensorflow.train.GradientDescentOptimizer 并设置0.5的学习速率,优化目标设定为 Cross-Entropy 得到进行训练的操作 train_step 下图第一条代码。然后使用 Tensorflow 的全局参数初始化器下图第二条代码并执行 Run 方法。




        最后一步我们开始迭代地执行训练操作 train_step 每次都随即从训练集中抽取100条样本并调用 train_step 对这些样本进行训练。使用一小部分样本进行训练称为随即梯度下降(如果每次训练都使用全部样本那么计算量就非常大)因此对于大部分机器学习的问题我们都只使用一小部分数据进行随即梯度下降,这样会比全样本训练的收敛速度快很多。


        现在我们已经完成了训练,接下来就算对模型的准确率进行验证。下面代码中的 tf.argmax 是从一个张量(Tensor)中寻找最大值的序号 tf.argmax(y,1)就算秋各个预测的数字中概率最大的那一个 tf.argmax(y_,1)则是找样本的真是数字类别。而 tf.equal 方法则用来判断预测的数字类别是否就是正确的类别,最后返回计算分类是否正确的 Correct_Predition 操作。然后我们用 tf.cast 将 Correct_Predition 输入的 Bool 值转换成 Float32 再求平均。



最后我们将测试数据的特征和 Label 输入评测流程 accuracy 计算模型在测试集上的准确率,再将结果打印出来。使用 Softmax Regression 对 MNIST 数据进行分类识别,在测试集上的平均准确率可达 91% 左右。通过上面这个简单的例子,我们使用 Tensorflow 实现了一个简单的机器学习的算法 Softmax Regression 这可以算作是一个没有隐含层的最浅的神经网络。