本人学习TensorFlow中的一些学习笔记和感悟,仅供学习参考,有疑问的地方可以一起交流讨论,持续更新中。
本文学习地址为:TensorFlow官方文档,在此基础上加入了自己的学习笔记和理解。
文章是建立在有一定的深度学习基础之上的,建议有一定理论基础之后再同步学习。
1.准备MNIST数据集
1.1 数据集下载及导入
MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片:
它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是5,0,4,1。
MNIST数据集在官方文档中提供了一个脚本文件下载,但是我个人用这个文件无法下载数据集,所以建议直接去MNIST数据集官网下载,下载下面四个文件并将其放在MNIST_data文件夹中。
然后在python文件中只要加入以下代码,MNIST数据集就存在mnist这个变量中了。
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
在上式中,one-hot=True表示label向量中除了对应位置的数字是1以外其余各维度数字都是0,即label式一个10维的向量,例如数字3的标签为[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]。如果没有one-hot则label直接存储数字的标签,例如数字3的标签为3
1.2 MNIST数据格式
我们可以利用下列指令查看mnist数据集大小和标签
print('train_size:', mnist.train.images.shape)
print('train_label_size:', mnist.train.labels.shape)
print('val_size:', mnist.validation.images.shape)
print('val_label_size:', mnist.validation.labels.shape)
print('test_size:', mnist.test.images.shape)
print('test_label_size:', mnist.test.labels.shape)
输出结果为:
train_size: (55000, 784)
train_label_size: (55000, 10)
val_size: (5000, 784)
val_label_size: (5000, 10)
test_size: (10000, 784)
test_label_size: (10000, 10)
(55000, 784)代表的含义是:训练集中共有55000张图片,一行数据就代表了一张图片。每张图片28*28的大小被reshape为1*784。(55000, 10)代表共55000张图片被分为10类(0~9),每一个行向量代表对应图片的标签,例如某行向量为[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]则代表该图片对应的数字为3。
1.3 MNIST图像展示
了解过MNIST的数据格式之后将其用图像展示出来,利用下列代码:
def data_trainsform(a):
b = np.zeros([28, 28])
for i in range(0, 27):
for j in range(0, 27):
b[i][j] = a[28 * i + j]
return b
tile = data_trainsform(mnist.train.images[1])
print(mnist.train.labels[1])
plt.figure()
plt.imshow(tile, 'bone')
plt.show()
可以展示训练集中的第二张图片,如下所示。以及其对应的label向量[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]。
至此,对于mnist数据格式以及存储方式有了一个大致的了解,我们继续往下学习。
2.MNIST机器学习入门
2.1 模型构造
导入MNIST和TensorFlow:
import tensorflow as tf
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)#这里MNIST_data/是存MNIST的路径,自己修改
我们现在要做的就是实现机器学习中最基础的回归模型——线性回归y=wx+b。先对这几个参数做出定义:
x = tf.placeholder(tf.float32, [None, 784]) #placeholder 产生一个占位符
W = tf.Variable(tf.zeros([784, 10])) #Variable 定义一个变量
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W) + b) #matmul(A,B) 表示矩阵乘法A*B
y_hat = tf.placeholder('float', [None, 10])
结合MNIST数据格式,上述代码并不难理解。placeholder相当于定义了变量x,只不过这时候x是没有具体值的,x只有第二维度的值被固定为784,因为输入的MNIST图片大小是固定的。但是因为输入数量无法确定,所以x的第一维度是None,能随着输入的改变而改变。W初始赋值为784*10的零矩阵。其他语句基本类似,不再赘述。y表示预测值,也表示我们要用的模型是线性回归。y_hat是真实标签。
2.2 训练模型
定义完各个变量后和模型之后开始训练这个模型。为了训练我们的模型,我们首先需要定义一个指标来评估这个模型是好的。其实,在机器学习,我们通常定义指标来表示一个模型是坏的,这个指标称为成本(cost)或损失(loss),然后尽量最小化这个指标。但是,这两种方式是相同的。
一个非常常见的,非常漂亮的成本函数是“交叉熵”(cross-entropy)。交叉熵产生于信息论里面的信息压缩编码技术,但是它后来演变成为从博弈论到机器学习等其他领域里的重要技术手段。它的定义如下:
y 是我们预测的概率分布, y' 是实际的分布,即为上述变量y_hat。比较粗糙的理解是,交叉熵是用来衡量我们的预测用于描述真相的低效性。
交叉熵的实现
cross_entropy = -tf.reduce_sum(y_hat*tf.log(y))
评估指标现在也有了,那么我们就可以开始训练这个模型了。一句话就是利用梯度下降算法使cross_entropy最小,此时的模型参数W,b就是我们想要的模型参数。整个训练过程如下所示:
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) #用梯度下降算法以0.01的学习速率最小化交叉熵
sess = tf.Session() #Session是运行TensorFlow操作的类
sess.run(tf.initialize_all_variables()) #初始化所有参数,这一步是必须的
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_hat: batch_ys})
Session的作用就是来运行TensorFlow的各种操作的,例如我们现在运行下列两个命令:
print('print b get:', b)
print('print sess.run(b) get:', sess.run(b))
可以得到下列结果:
print b get: <tensorflow.python.ops.variables.Variable object at 0x10efa0eb8>
print sess.run(b) get: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
如果不放在Session里面run是没法直接得到各个变量或者操作的值的。
2.3 评估模型
模型已经训练好了,接下来需要做的就是去用测试集测试评估这个模型。
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_hat, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float')) #tf.cast 类型转换函数
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_hat: mnist.test.labels}))
tf.argmax
是一个非常有用的函数,它能给出某个tensor对象在某一维上的其数据最大值所在的索引值。由于标签向量是由0,1组成,因此最大值1所在的索引位置就是类别标签,比如tf.argmax(y,1)
返回的是模型对于任一输入x预测到的标签值,而 tf.argmax(y_,1)
代表正确的标签,我们可以用 tf.equal
来检测我们的预测是否真实标签匹配(索引位置一样表示匹配)。
最终结果大约91%左右。
3.完整代码
放上完整代码,欢迎交流讨论
import tensorflow as tf
import input_data
import matplotlib.pyplot as plt
import numpy as np
def data_trainsform(a):
b = np.zeros([28, 28])
for i in range(0, 27):
for j in range(0, 27):
b[i][j] = a[28 * i + j]
return b
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
print('train_size:', mnist.train.images.shape)
print('train_label_size:', mnist.train.labels.shape)
print('val_size:', mnist.validation.images.shape)
print('val_label_size:', mnist.validation.labels.shape)
print('test_size:', mnist.test.images.shape)
print('test_label_size:', mnist.test.labels.shape)
tile = data_trainsform(mnist.train.images[1])
print(mnist.train.labels[1])
plt.figure()
plt.imshow(tile, 'bone')
plt.show()
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_hat = tf.placeholder('float', [None, 10])
cross_entropy = -tf.reduce_sum(y_hat * tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
print('print b get:', b)
print('print sess.run(b) get:', sess.run(b))
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_hat: batch_ys})
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_hat, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_hat: mnist.test.labels}))