准备工作
由于将TensorFlow安装到了Conda的tensorflow环境,虽然可以用Jupyter notebook打开,但是没有提示,写代码不方便,所以使用PyCharm进行编写。设置如下:
- 如果是新建项目,在选择使用python的地址的地方,找到anaconda目录,点击envs ----> tensorflow -----> bin -----> python2.7(我的是2.7)
- 如果已经创建了项目,但是没有用该环境下的python,就进入项目的设置里,找到project interpreter这一项,做同上面相同的事。
MNIST数据集简介
该数据集是机器学习入门级别的数据集,也是tensorflow在教程中使用的数据集。包含手写数字图片以及图片的标签(标签告诉我们图片中是数字几)。数据集分为三部分:mnist.train(训练数据),包含55000个数据点;mnist.test(测试数据),包含10000个数据点;mnist.validation(验证数据),包含5000个数据点。
开始之前
先将下面代码拷贝到pycharm中,试试能否运行(不必懂,主要先试运行,测试环境是否有问题)。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
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)
# Training
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)
# run
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
# evaluate
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
分析模型
每个图片的大小都由28*28=784个像素点组成,可以抽象成一个784维的向量,每一位的值代表像素强度。下图横坐标代表图片索引,纵坐标代表每个像素值。
每个图片有一个标签,代表它是数字几,那么下图的横坐标代表图片索引,纵坐标代表数字几。
我们给每个数字的每个像素都标一个权重,如果是这个数字该有的部分,则为正圈中,如果是不该有的部分,则标为负权重,如下图,蓝色代表正权重,红色代表负权重。
我们再给每个像素添加一些偏差b,则可以得到下面公式
再用softmax函数将evidence转化成我们想要的一系列可能性y
为啥这么做呢,假设输入一个手写图片,那么像素点值大的地方肯定是那个数字,把我们刚才设置的所有权重都和这个图的像素点做一下上面公式的运算,就能得出10个图,最后再看这些图,假设这个图是1,那么它和1的权重图运算后是1的部分就会变更大更黑,是1的可能性也就越大,我们用softmax函数的目的就是给出没种运算后的可能性,根据one-hot编码让我们知道它是数字几。
用图表示会更形象:
开始
- 新建python文件,导入tensorflow,输入下面两行,可以自动下载并读取mnist数据集:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
写完这里有个疑问,如果我想读取别的数据集怎么办?追踪input方法,发现一大堆读取的代码,为了不偏离主线,先放过,过后查询。
还有一个发现,括号里的one_hot=True没有空格,加了空格反而会显示:unexpected spaces around keyword/parameter equals,所以看来和java不同,键值之间的等号不能加空格。
还有,import语句一定写在最上面,虽然这是常识,不过由于教程里面是先讲的自动下载数据集,然后讲的import tensorflow,所以我还是试了试如果把import放下面咋办,果然报错了。
- 设置占位符x
x = tf.placeholder(tf.float32, [None, 784])
tensorflow是需要我们先绘制一个dataflow graph,这个graph我理解其实就是设置变量、参数、用的激活函数、损失函数等等,把公式先写好,未知数用一个占位符先占着,这里的x就是上图中的[x1,x2,x3,x4],None代表该维度可以任意长。
- 设置变量
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
W的第一个维度代表784个像素,第二个维度代表10个类,初始化成0。
b的维度代表10个类,初始化成0。
- 设置softmax求出结果
y = tf.nn.softmax(tf.matmul(x, W) + b)
- 训练
在tensorflow里,我们也先用占位符来表示预期结果
y_ = = tf.placeholder(tf.float32, [None, 10])
为了训练我们的模型,通常会定义它怎么样才算一个好模型,在机器学习里,我们通过比对模型输出和预期值的差异,成为损失函数或者代价函数,差异越小越好,“交叉熵”是经常使用的损失函数,公式如下:
y是预期分布,y'是真实分布。
用tensorflow实现交叉熵函数:
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
因为这种写法得到的分布值不平稳,所以常用 tf.nn.softmax_cross_entropy_with_logits
函数来得到平稳的结果
到这里,tensorflow知道了整个graph,它会自动通过反向传播算法找到让损失函数最小的变量值,它还提供了一些优化算法来帮助让损失函数最小。如梯度下降法:
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
- run tensorflow
- 初始化变量
init = tf.global_variables_initializer()
这里只是定义了,还没有执行初始化。
- 创建session,执行初始化
sess = tf.Session()
sess.run(init)
- 训练
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
运行1000次,每次采样100个x和y,放在batch里,替换占位符(相当于赋值给占位符)。
- 衡量模型
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
tf.argmax(y, 1)
第二个参数代表维度,correct_prediction给了我们一个布尔列表;
accuracy一句将布尔集合转换为数字集合,比如[True, True, False, False, False],转换为[1, 1, 0, 0, 0],正确率为0.4,对所有正确率求平均数;
最后一句,运行精度计算,得到精度。
遇到的问题
对他的dimension表示疑惑,可能受其他语言影响,认为[1,2,3,...,784]是一个一维数组,[1][2]才是2维数组,但是它说了个784-dimensional vector,一下子把我搞蒙了,不过后来似乎转过弯了,[1,2,3,...,784]就是一个784维的向量,不是要在空间画出来,只是这样表示而已,[784,10]代表784列10行的一个二维矩阵。
在运行后,发出警告,说The TensorFlow library wasn't compiled to use SSE4.1/SSE4.2 /AVX/AVX2/FMA instructions, but these are available on your machine and could speed up CPU computations.
那么怎么使用这些提高CPU计算速度呢,到StackOverFlow上查了一下,说是最好从sources编译它,应该就是说安装的时候从sources安装,但是我是通过anaconda安装的,等实在忍不下去这个速度了再从sources编译吧,就先不在这里耗时了,毕竟我花了两天才安装好它……
后续将补充的知识
今天的主要目的是跑通并理解整个程序,所以没有深究所有算法的原理,接下来的几天将进行下面知识补充:
- softmax regression
- Python数组问题
- 交叉熵
- 激活函数
- 反向传播算法