使用TensorFlow分类手写数字

使用TensorFlow分类手写数字

回到2013年,我写了一篇关于使用Python进行数字识别的帖子。 从那时起,Python数据生态系统发生了很大变化。 Google给了我们Tensorflow,scikit-learn已经成熟,“AI”现在是最新的热潮。

所以我认定是时候把精力放到手写识别这个领域。 它仍然是一个非常简单,但迷人的概念:收集某人的手写素材,并试图预测这个人写的东西。 好消息是,在过去几年我们已经学习并掌握了几个新的技巧,我会在这里与大家分享一些。

近几年来的显著区别

PS: 想直接体验应用吗? 在这里查看:

Yhat: End-to-End Data Science Platform

1我们在做什么

其中之一我想改变手写识别器的是使它更“实时”。 而不是让用户绘制的东西,然后点击“猜”,如果应用程序主动尝试弄清楚你正在绘制什么是不是更有趣呢?

为此,我们需要一种途径使得在用户绘制数字时调用我们的模型。 这可能看起来很简单,但这意味着我们可以(1)对图像做足够快的预测以跟上某人的手写,(2)我们可以从我们的应用程序(可能使用像Javascript)来回收发预测。

幸运的是,自从我写的第一篇文章以来,Yhat做了一些大的性能改进:它现在可以做几千个预测每秒,而不是几年前500-700个。

2数据

制作一个不断进行预测的应用程序的后果之一是我们需要对不完整数据进行模型训练。

让我们假设你写了一半数字5. 这可能看起来像一个6,9,甚至1(取决于你的书法风格)。 为了处理这些种类的部分数据情况,我们需要在部分完成的数字上(或在我们的提供图像)收集数据。

为此,我做了一个小的Web应用程序,执行以下操作

  1. 用空白画布呈现访问者并要求他们绘制一个随机数字。
  2. 当用户绘制数字时,将图像保存到S3桶(分类和标记)
  3. 一旦用户完成,选择一个新的数字并重复步骤一和二

说服我的同事后,我们很兴奋的完成超过80000 个图片。

我们收集在不同的绘制阶段总共超过8万个数字。 为了将这些图像转换为Python我使用了skimage库,它提供了一个一致的、在OpenCV、scipy和其他python图像工具易于使用的API。

你可以看到通过循环每个图像文件并使用get_image_data函数将其转换为numpy数组。 get_image_data获取一个图像文件,并执行以下操作:

  • 打开它,并将其作为数组读入python
  • 将其从彩色转换为灰度(节省大小)
  • 将图片缩小25x(这可能看起来很多,但它不会对我们的分类产生显着差异)
  • 将其从2维阵列(20×20)平铺到1维阵列(1×400)

def get_image_data(filename):
img = io.imread(f, as_grey=True)
return transform.downscale_local_mean(img, (25, 25)).

flatten( )

data = [ ]

labels = [ ]

for i, (label, filename) in enumerate(files):
image = get_image_data(filename)
data.append(image)

classes = np.zeros(10)
classes[label] = 1.0
labels.append(classes)

if i%100==0:
print ” %d of %d (%2f)” % (i, len(files), float(i) / len(files))

下一步是构建一个可以解释它们的分类器!

3分类我们的图片

分类手写数字是机器学习库中相当常见的教程/教科书问题。 MNIST数据集通常被引用,您可以在诸如scikit-learn,Tensorflow和Keras等库的文档中找到它。 所以幸运的是,我们有很多伟大的起点。 我们的问题可以简化为应用其中的示例我们的探索中。

对于这篇文章,我决定使用Tensorflow。 他们实际上有两个使用MNIST数据集构建分类器的示例,这对我们非常方便!

  • 基本示例
  • 高级示例

我将使用现在的基本示例,因为它使用更少的代码和更直接。

4模型代码

Tensorflow需要基于对基础图/网络中大量的“底层”理解和配置。 说实话,我不会推荐使用它,除非你相信你知道你在做什么。

设置我们的模型,我们将创建“占位符”变量(如下面的x)。 这些占位符在实例化时不会执行。 相反,评估将延迟,直到您实际操作您的数据。

我们还将创建2个变量,W和b,它们代表我们模型的“权重”和“偏差”。 最初,我们将它们全部设置为0,但是一旦我们开始训练我们的模型,这些变量将被更新以反映训练数据。

最后,我们将使用tf.nn.softmax定义我们的模型。 在这种情况下,我们使用softmax算法,但有很多其他选项可用。

import tensorflow as tf

x = tf.placeholder(tf.float32, [None, len(data[0])])

W = tf.Variable(tf.zeros([len(data[0]), 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)

好,到这一步。只需完成初始化变量的任务,并开始tensorflow任务的执行!

init = tf.initialize_all_variables( )

sess = tf.Session( )

sess.run(init)

5训练

现在一切都设置完毕:我们可以开始训练我们的模型。 Tensorflow是很好的,因为它支持迭代训练 – 这意味着你不必在单步或单线(你认为scikit-learn)做到100%的训练。 所以,当你获得更多的数据,你可以更新你的模型和微调你的权重。下面你可以看到实际的训练代码。 我们每次在1000个数据点上进行10,000批训练。 我写了一个帮助函数叫next_batch随机提供给模型数据。

def next_batch(n):
idx = np.random.randint(0, len(data), n)
return data[idx], labels[idx]

for i in range(10000):
batch_xs, batch_ys = next_batch(1000)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

if i%100==0:
print ” epoch %d” % i

6做预测

好的,现在我们有我们的模型,我们可以开始做预测! 这在tenserflow中非常不直观,但是我没有写API:

print sess.run(y, feed_dict={x: mnist.test.images })

我继续使用ScienceOps(无耻的插件)部署这个模型,并关联到的应用程序上。 我现在可以在用户绘制特定数字时实时生成预测。 相当精巧! 我的模型耗费了些许精力,但它是非常酷,看到它的预测变得更好,当你给它更多的信息(当你接近完成你的绘图)。

文章来源 / The Yhat Blog

原文作者 / Greg

译 / 刘霄阳

编辑 / 珺妹妹, ZZ