导语:WolfgangBeyer的一篇优秀的博文,详细介绍了如何使TensorFlow搭建一个简单的图像识别系统。
本篇主要对该教程实践过程做了简单的整理。
实践目标
- 学习Tensorflow编程思想
- 实现简单的机器学习系统,识别图像并打上正确的标签
数据集:标准的CIFAR-10数据集
- 10个不同的分类,每类包含6000幅图片。
- 规格:32x32像素。
机器学习框架流程
首先,定义一个通用的数学模型,将输入图像转换为输出标签。
这个模型的实际输出不仅仅依赖于图像本身,还依赖模型内建的参数。这些参数并不是由我们提供,而是由计算机通过学习获得。
这个过程可以被理解为一个参数的优化问题,主要步骤如下:
- 定义一个模型并提供初始的参数值
- 向模型输入图像数据集和已知的正确标签进行训练
- 模型重复校验,训练数据,持续调整参数值
- 直至找到合适的参数使模型输出尽可能多的正确结果
- 当训练完成,找到最优(接近最优的模型参数),该模型即可用于图像集以外的图像分类。
上述学习过程即监督学习—输入包括数据以及标签。
工具及环境
- Python2.7及以上
- Tensorflow
- CIFAR-10数据集:下载Python版本的数据集。
注意:cifar-10-batches-py需要解压到python源代码的目录下,其余工具及环境自行配置
Tensorflow源码分析
代码分析过程中主要通过代码+注释的形式,请不要忽略注释。
定义Tensorflow图
在这个过程中不执行任何操作
1. 导入需要的包
# 为了python2和python3的兼容性
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
import time
import data_helpers #包内函数主要用于加载和处理数据集的函数
读取数据部分的函数单独放在data_helper.py文件中,负责读取包含数据集的文件,并把数据放入一个方便我们操作的数据结构中。
2. 准备数据集
data_sets = data_helpers.load_data()
load_data()将数据集进行处理,返回一个dictionary类型数据,便于训练时喂养模型使用:
- images_train:将训练集转换为50000*3072的数组,其中3072=32像素×32像素×3个颜色通道rgb
- lables_train:训练集的50000个标签(每个数字从0到9代表图像训练集的10个分类)
- images_test:测试集(100003232*3)
- lables_test:测试集的10000个标签
- classes:10个文本标签,将数字转换成文字
值得注意的是,load_data()函数将60000幅图像分为训练集和测试集。训练集包含50000幅图像,用于训练我们的模型。测试集包含1000幅图像,用于训练完成后检验模型的性能。
3. 定义训练恒参
# Parameter definitions
batch_size = 100 #将数据集随机分批喂给模型,每批100个数据
learning_rate = 0.005 #梯度优化时的学习速率
max_steps = 1000 #训练次数
4.定义模型内建参数
# Define variables (these are the values we want to optimize)
weights = tf.Variable(tf.zeros([3072, 10])) #3072*10的零矩阵
biases = tf.Variable(tf.zeros([10])) #大小为10的列表
内建参数就是我们在训练过程中想要优化的参数。我们将每幅图像以3072个浮点数(size=3027的列表)表示,作为输入;最终结果以10个浮点数(size=10的列表)表示每个种类的得分。
5.定义placeholder用于接收数据集
images_placeholder = tf.placeholder(tf.float32, shape=[None, 3072])
labels_placeholder = tf.placeholder(tf.int64, shape=[None])
placeholder主要在需要运行时给节点输入数据时使用。在这里相当于提供了一个接收训练数据输入的接口,每次训练需要输入数据时只需要使用feed_dict={images_placeholder: , labels_placeholder: }即可。
6.定义用于描述模型预测结果的表达式
logits = tf.matmul(images_placeholder, weights) + biases
7.定义预测结果与真实值之间的损失量表达式
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits,
labels=labels_placeholder)) #tf.reduce_mean求损失值均值,softmax函数将logits转化为概率值,能表示特征的输出。
将预测值与正确的分类标签进行比较,损失越小表示预测值越接近正确标签。
8.定义对损失值做梯度下降优化的动作
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
9.定义计算准确率的表达式
#tf.argmax(x,1)按行找,找到每一行中最大数值的下标,返回结果是一个列表
#correct_prediction是一个布尔型
correct_prediction = tf.equal(tf.argmax(logits, 1), labels_placeholder)
#tf.cast(x,dtype)将x转换为dtype数据格式
#计算平均准确度/平均分
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
执行Tensorflow图
将操作的执行放在Session会话中进行。
1.对所有变量完成初始化
sess.run(tf.global_variables_initializer())
2.循环迭代,每次随机抽取一批数据喂养模型
for i in range(max_steps):
# Generate input data batch
indices = np.random.choice(data_sets['images_train'].shape[0], batch_size)
images_batch = data_sets['images_train'][indices]
labels_batch = data_sets['labels_train'][indices]
# 每100次迭代,对模型训练数据批的当前精确率进行检查。直接调用先前定义的精确率操作来完成。
if i % 100 == 0:
train_accuracy = sess.run(accuracy, feed_dict={
images_placeholder: images_batch, labels_placeholder: labels_batch})
print('Step {:5d}: training accuracy {:g}'.format(i, train_accuracy))
# Perform a single training step
sess.run(train_step, feed_dict={images_placeholder: images_batch,
labels_placeholder: labels_batch})
每次训练随机抽取训练数据中的一批图像。每训练一批数据都会更新一遍模型的参数,因此批的大小代表了参数更新的频率。
批的大小需要选择相对合适的值,如果太大,每次迭代参数的更新都需要大量的计算;如果太小,会造成高频率的参数更新,但更有可能向错误的方向频繁修正。
在这个模型中,每次训练的数据大小为0-batch_size之间随机指定的一个值。
3.训练完成后,使用测试数据集测试模型效果
test_accuracy = sess.run(accuracy, feed_dict={
images_placeholder: data_sets['images_test'],
labels_placeholder: data_sets['labels_test']})
print('Test accuracy {:g}'.format(test_accuracy))
模型评估总结
在命令行模式中,python softmax.py
运行softmax.py脚本,通过打印的training accuracy,我们可以看到两点:
- 在这个测试集中训练模型的估计精度为31%左右。相比较随机猜测,该模型显然有一定的性能优势;但总的来说,该模型还比较低级,因为它只单独检测每个像素的颜色,对具体的图像比如线和形状等完全没有考虑。
- 对当前模型的性能而言,即使增加迭代训练次数也并不能改善模型的准确率。观察结果发现,训练的准确率随着迭代次数的增加并不是稳定上升,而是在一定范围内波动,说明当前数据量已经达到了模型的极限。