这篇文章是学习《TensorFlow实战-黄文坚》过程中的笔记,具体的实现细节请参考原书。
MNIST(Mixed National Istisute of Standards and Technology databast)是一个简单的机器视觉数据集,由几万张28*28像素的手写数字图片组成,图片只包含灰度信息。目标是使用Softmax对手写数字图片进行分类,数字为0~9一共10类。MNIST数据集由55000个训练样本,10000个测试样本,5000个验证样本。每一个样本都有对应的标注信息(label)。在样本集上训练模型,在验证集上检验效果病决定何时完成训练,最后在测试集上评测模型的效果。由于样本是28*28像素,展开之后会变成784维的向量(每一个点对应一个维度),这是一种简单的处理方法,舍去了图片的二维结构方面的信息。最终的训练数据的特征是一个55000*784的Tensor,第一个维度是图片的编号,第二个维度是图片中像素点的编号。训练数据的Label是55000*10的Tensor,对10个类进行one-hot编码处理,Lebel是一个10维的向量,只有一个值为1,其余全部为零。
在spyder中载入数据集后,可以用如下命令查看数据的维度(完整代码见之后的实现部分):
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
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)
输出结果
(55000, 784) (55000, 10) #训练集和对应标签的维度
(10000, 784) (10000, 10) #测试集和对应标签的维度
(5000, 784) (5000, 10) #验证集和对应标签的维度
分类器默认数据数据是连续的,并且是有序的,但实际使用的分类标签并不是有序的,而是随机分配的。one-hot编码又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。可以这样理解,对于每一个特征,如果它有m个可能值,那么经过独热编码后,就变成了m个二元特征。并且,这些特征互斥,每次只有一个激活。因此,数据会变成稀疏的。
这样做的好处主要有:
1. 解决了分类器不好处理属性数据的问题
2. 在一定程度上也起到了扩充特征的作用
Softmax的原理比较简单,将可以判定为某一类的特征相加,转化为判定是某一类的概率,分别计算每一种类别对应的概率,再通过比较这些概率的大小,找出概率最大的类对应的数字作为模型的输出结果。其中,权重是模型根据数据自动学习,训练得出。
首先载入TensorFlow库,并新建一个InteractiveSession(会将这个session注册为默认的session,之后的运算也默认在这个session中,不同session之间的数据和运算应该都是相互独立的)。接下来创建一个Placeholder,即输入数据的地方。其中第一个参数是数据类型,第二个参数是tensor的shape,None代表不限条数的输入。
import tensorflow as tf
sess = tf.InteractiveSession()
x = tf.placeholder(tf.float32, [None, 784])
接下来给Softmax Regression模型中的weights和biases创建Variable对象。因为Softmax Regression模型比较简单,将weights和biases都初始化为0,不会影响训练的过程。Variable对象在模型训练迭代中是持久化的,它可以长期存在并且在每轮迭代中被更新;另一种存储数据的tensor在使用之后则会消失。
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
利用y=softmax(Wx + b)实现Softmax Regression算法:
y = tf.nn.softmax(tf.matmul(x, W) + b) #注意x和W的行数和列数要满足矩阵乘法的运算规则
其中,tf.nn包含了大量神经网络的组件,softmax只是其中的一个函数。
为训练模型,需要定义一个loss function来描述模型对问题的分类精度。Loss越小,代表分类结果与真实值的偏差越小,拟合结果越精确。在初始化过程中,给模型填充了全零的参数,这样模型会有一个初始的loss,在训练过程中不断将这个loss减小,直到达到全局或者局部的最优值。对于多分类问题,通常使用cross-entropy作为loss function。在TensorFlow中定义cross-entropy:
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
其中,tf.reduce_sum函数的意义为降维求和,可以参考知乎
接下来需要定义优化算法,这里采用常见的**随机梯度下降算法**SGD(Stochastic Gradient Descent)
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
设置学习速率为0.5,优化目标设定为cross-entropy最小,得到训练操作的train_step
下一步使用全局参数初始化器,并直接执行run方法:
tf.global_variables_initializer().run()
最后迭代执行训练操作:
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
train_step.run({x:batch_xs, y_:batch_ys})
这里每次随机从训练集中抽取100条样本构成一个mini-batch,并feed给placeholder,然后调用train_step对这些样本进行训练。使用县部分样本进行训练称为随机梯度下降,大多数时候这种方法比全样本训练的收敛速度快很多。
完成训练后需要对模型的准确率进行验证。
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}) #输出
其中,tf.argmax就是返回最大的那个数值所在的下标,具体的参数定义可见 tf.argmax()以及axis解析,注意数组维度的起始值为0。
在TensorFlow上实现一个机器学习算法,主要工作可以分为以下部分:
1. 定义算法公式,也就是神经网络forward时的计算
2. 定义loss,选定优化器,定义loss function
3. 迭代对数据进行训练
4. 在测试集或验证集上对准确率进行评测
注意:定义的各个公式只是Computation Graph,在执行这些代码时,计算实际上还没有发生,直到调用run方法,并且feed数据时,计算才真正执行。其中的cross-entropy、train_step、accuracy等都是计算图中的节点,并不是数据的结果,可以用run方法来执行节点或者说运算操作来获取结果。
from tensorflow.examples.tutorials.mnist import input_data # load mnist data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
print(mnist.train.images.shape, mnist.train.labels.shape)
print(mnist.train.images.shape, mnist.test.labels.shape)
print(mnist.train.images.shape, mnist.validation.labels.shape)
sess = tf.InteractiveSession()
x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(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)
tf.global_variables_initializer().run()
for i in range(1000):
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}))
开始进入了机器学习这个天坑,这篇文章只是对书中一些关键点做了一些笔记,对一些不懂的细节查找资料进行解释。希望之后能够耐心坚持下去~
参考链接:
http://blog.csdn.net/dulingtingzi/article/details/51374487
https://www.zhihu.com/question/51325408?from=profile_question_card
http://blog.csdn.net/qq575379110/article/details/70538051