最近做一个索尼公司的商业项目,要用到深度学习的内容,于是这里记录一些东西,方便查阅..
环境:macOS-10.13.4, Python-3.6, Tensorflow-1.4.1
参考: 《TensorFlow实战》
下载数据并进行测试
说明:这个是TensorFlow自带的一个示例,可以通过这些示例去学习各个模型的使用
想做什么:比如下面的这个图片,我们想让计算机识别出来它是1,同理其他的数字也一样,识别手写数字
前提:安装好了TensorFlow并联网…电脑速度不要太慢就可以了
运行下面的python代码:
from tensorflow.examples.tutorials.mnist import input_data
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)
服务器上等待了大约10分钟,得到下列终端输出:
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
((55000, 784), (55000, 10))
((10000, 784), (10000, 10))
((5000, 784), (5000, 10))
前四个代表着在下载训练集和其他的必需的东西。
后面的三行,即上面代码里的三个print,查看mnist的情况。
可以发现,mnist的训练集有55000个样本,测试集10000个样本,验证集5000个样本,每一个样本都有对应的标注信息。
这个集合里面的元素,每一个都是一个28×28的图片,28×28的结果是784,即一个图片有784个像素点,所以上面的输出里带有784,是把每一张图片作为了一个784长度的向量来对待的。
而训练的标签数据是55000×10的Tensor,这个10呢,就是对10个数字0123456789进行了独热编码得到的10个种类。比如:
0的标签是[1,0,0,0,0,0,0,0,0,0]
1的标签是[0,1,0,0,0,0,0,0,0,0]
2的标签是[0,0,1,0,0,0,0,0,0,0]
3的标签是[0,0,0,1,0,0,0,0,0,0]
4的标签是[0,0,0,0,1,0,0,0,0,0]
5的标签是[0,0,0,0,0,1,0,0,0,0]
6的标签是[0,0,0,0,0,0,1,0,0,0]
7的标签是[0,0,0,0,0,0,0,1,0,0]
8的标签是[0,0,0,0,0,0,0,0,1,0]
9的标签是[1,0,0,0,0,0,0,0,0,1]
所以,最后我们准备的数据就是:
55000个784长度的向量,表示55000个样本图片,和配套的55000个标签,每个标签是长度10的向量,表示它的类别,这个作为训练集
10000个上述数据作为测试集
5000个上述数据作为验证集,在验证集上检验效果并决定何时完成训练
数据准备好了,接下来就是设计深度学习模型算法了
Softmax Regression简单概述
在这里我们用一个叫做Softmax Regression的模型来训练手写数字识别的分类模型。
工作原理:比如一张28*28的数字图片,模型会预测出它是10种类别的概率,然后输出概率最大的。比如一个模糊的写有数字5的图片,模型可能分析出来它是1的概率是10%, 2的概率是20%, …, 5的概率是50%, …等等,最后输出一个最大的概率所表示的类别,即5。
即使是卷积神经网络还是循环神经网络,如果是分类模型,最后一层同样是Softmax Regression,它的原理就是判断某类的特征相加,然后把这些特征转化为概率就可以了。
比如这里,我们可以对第i类(一共是十个类别嘛),构造一个特征公式:
\(feature_i = \sum_{j}^{}W_{i, j}*x_j + b_i\)
其中i表示第i类,j表示一张图片的第j个像素,bi表示bias表示偏差,要训练的。
先别管这个公式怎么来的,然后我们继续算一个softmax, 这个是根据所有的特征计算到的,很简单,就是标准化一下,让所有类别的概率相加为1:
\(softmax(x) = normalize(exp(x))\)
那么判断一个图片是几的话,就直接根据下面的公式算出来的就是概率了:
\(softmax(x)i = exp(x_i) / \sum{j}^{}exp(x_i)\)
所以一张图片属于谁的概率就能通过上面的式子来算了,我们只需要训练W和b, 让它得到的结果尽可能的准确,这个模型就能完成了。
所以简单的说,核心可以写成这样的一个公式:
\(y = softmax(Wx + b)\)
然后就是训练W和b这两个参数,让它们的结果的准确率更高。
于是我们可以写代码了。
实现
首先建立一个默认的Session,后面的运算都是建立在这个Session上,然后创建一个数据输入口placeholder:
import tensorflow as tf
sess = tf.InteractiveSession()
x = tf..placeholder(tf.float32, [None, 784])
sess就是默认的会话口,x就是数据输入口,后面的[None, 784]表示输入的数据可以无限,每个输入都是784维的向量
然后建立w和b,用Tensor对象去描述:
w = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
w中的784是特征维数,10是类别。b中需要一个10,全部初始化为0。
核心公式:
y = tf.nn.softmax(tf.matmul(x, w) + b)
也就是上面提到过的\(y = softmax(Wx + b)\)
为了训练模型,我们有了训练集,自然还是需要一个东西去表示模型预测的结果和真实值的偏差,这个偏差越小自然就越准确,训练的目的,就是为了减少偏差。
定义cross-entropy减少偏差,这个具体概念以后再说:
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
这个y_表示的是真实的标签数据,主要就是和算出来的y进行比较,来算出下面的cross_entropy即两者的一个偏差。
然后我们就要想办法减少这个偏差呀,TensorFlow给我们一套优化器去减少偏差,我们这里用GradientDescentOptimizer来优化:
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})
for就是训练的次数,第一行就是得到训练集里的数据,第二行就是输入数据进行训练,没错,这个train_step就是我们之前定义的优化器,里面两个参数x和y_, x表示输入的数据,y_表示输入的数据标签,两个进行对比,训练w和b让两者的偏差变小。
这样训练就完成了,我们验证一下准确率吧:
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.text.images, y_: mnist.test.labels}))
就结束了。
总结
书上说这个事情啊,一共就四个步骤:
Step1: 定义算法公式,也就是上面的那个y = 什么什么w什么什么x什么什么b的那个工数
Step2: 定义loss,选定优化器,指定优化器优化这个loss,也就是上面的GradientDescentOptimizer,传入误差值和需要减少的量即loss
Step3: 迭代对数据进行训练,也就是上面的那个for循环,每一次输入数据和标签,优化器减少两者的误差
Step4: 在验证集上对准确率评测
在我看来所有的一切不过这些过程:
Step1: 收集数据,包括数据和标签,训练集和测试集。
Step2: 构建模型,包括模型的数据输入口,模型的算法
Step3: 根据模型的算法的结果,和标签进行比对(比如作差得到一个loss),然后弄一个优化器去调整模型的参数值(w, b)去减少这个误差
Step4: 迭代去训练几千次几万次,最终那验证集去测试一下准确率
所有代码
# 获取数据
from tensorflow.examples.tutorials.mnist import input_data
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)
import tensorflow as tf
# 定义默认会话Session
sess = tf.InteractiveSession()
# 定义数据输入的入口
x = tf.placeholder(tf.float32, [None, 784])
# 定义weight和bias
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}))
注意
其中全局变量初始化,即:
tf.global_variables_initializer().run()
在老版本中不适用,如果报错的话,请使用initialize_all_variables
这个带all的已经在2017年3月2日弃用。
然后如果报错是编码问题,请去掉上面所有的中文注释
最终输出结果是准确率。我的是0.91左右。