Keras快速上手——打造个人的第一个“圣诞老人”图像分类模型

343 阅读9分钟
原文链接: click.aliyun.com

2017 年已到最后一个月的尾巴,那圣诞节还会远吗?不知道各位对于圣诞节有什么安排或一些美好的回忆,我记得最清楚的还是每年圣诞节前一晚那些包装好的苹果,寓意平平安安。那谈到圣诞节,不可或缺的主角 ——“ 圣诞老人 ” 会出现在各地的大街小巷、各种画册上,本文将带领读者使用 Keras 完成 “ 圣诞老人 ” 图像的分类,算是圣诞节前的预热活动吧。

ca45244ee5e44c57cd134224a63a939d2267c6ad

在介绍正式内容前,读者可以先看这篇内容:

如何利用谷歌图片获得训练数据

在本教程的第一部分, 将介绍本文使用的数据集;其次使用Python 和 Keras 训练一个卷积神经网络模型,该模型能够检测一个图像中是否存在圣诞老人, 所选的网络结构类似于LeNet 网络; 最后, 在 一系列的图像 上 评估 本文搭建的 模型,然后讨论一 下本文方法的局限性以及如何拓展等 。

“圣诞老人”和“非圣诞老人” 数据集

794a0fa87e8a9ba4c2f3be9292f13521139fde21 为了 训练搭建的模型 , 本文 需要两 类 图像 集 :

  • 图像 含 圣诞老人(“ 圣诞老人” );
  • 图像 不包含 圣诞老人(“ 不是圣诞老人” )

上周我们用谷歌图片 迅速 获取 训练图像 数据集,数据集中包含461 张有 圣诞老人 的 图像中 ,如图1 (左)所示;此外从UKBench数据集 中随机获取461 张不包含圣诞老人,如图 1 (右)所示。

基于卷积神经网络和Keras搭建的第一个图像分类器

150719573d00f7ad726c7858acff2dcaccefdf8f

如图2 所示,该图是一个典型的 Lenet 网络结构, 最初 被用来数字手写体的分类 , 现将其 扩展到其他类型的图像。 本教程 主要是介绍如何将 深度学习 应用于 图像分类 中 , 所以不会对Keras 和 Python 语句介绍得非常详细,感兴趣的读者可以看下Deep Learning for Computer Vison with Python 这本书 。 首先 先定义网络架构。 创建一个 新文件 并命名为lenetpy ,并插入以下代码: 7e098bc8c6debdac033d14903c51fbbdb900cf74
第2-8 行是 需要 导入的Python 包 ,其中conv2d 表示 执行卷积 ,maxpooling2d 表示执行 最大 池化,Activation 表示 特定的激活函数 类型,Flatten 层用来将输入 “ 压平 ” ,用于卷积层到全连接层的过渡, Dense 表示全连接层。 真正创建Lenet 网络结构是代码的第10-12 行, 每当定义了一个新的卷积神经网络结构 时, 我喜欢:

  • 把它 放在 自己的类 中 ( 为了 命名空间 及便于 组织)
  • 创建一个静 立建造函数,来完成整个模型的建立 

建立的模型时 需要大量的参数:

  • weight:输入图像的宽度
  • height:输入图像的高度
  • depth:输入图像的通道数(1表示单通道图像灰度,3表示标准的RGB图像)
  • claclasses:想要组织的层类别总数

第1第4 行定义我们的模型,第 15 行 初始化inputshape ,第18-19 行 正常更新inputshape

现在我们已经初始化我们的模型 , 可以开始添加 其它 层, 代码如下 : 4ec53448ee702e6d428bed68ebc346d593f6e1e1 第21-25 行创建第一个 CONV->RELU->POOL 层, 卷积层使用20 个大小 5x5 的滤波器,之后紧跟 RELU 激活函数,最后使用窗口大小为 2x2 的最大池化操作; 之后定义第二个CONV->RELU->POOL 层: a4f0b0625b6df7469b472232754ba2c791b3cf3d 这次 卷积层使用50 个 滤波器 ,滤波器个数的增加加深整个 网络体系结构。 最终的代码块 是将数据“ 压平 ” 以连接全连接层: 5b700e1a6f1914ef441931c2b6e9d1cbef63871d 第33 行能 将maxpooling2d 层 的输出 压扁成一个单 向量; 第34 行显示 全连接层包含500 个节点,然后 紧跟一个ReLU 激活 函数; 第38 行 定义另一个全连接层, 该层的 节点数等于 分类 的类别数,Dense 层送入softmax 分类器 输出每类的概率值;

第42 行 返回 模型的 调用函数 ;

使用Keras训练卷积神经网络图像分类器

打开一个新的文件 并命名为train_networkpy ,并插入以下代码打开

a48db281781b1c5c56b2e69232e0ecb5237a0e5b

第2 - 18 行导入程序 需要的 数据 包 ;

下面开始 解析命令行参数:

cd76407f865d888a849b1af970e6d8c3a81e3181

这里有两个需要命令行参数,--dataset 和--model ,以及accuracy/loss 图 的路径选择 。其中--dataset 表示模型的训练集, --model 表示训练分类器后保存的模型 ,如果--plot 未指定,则默认为plot.PNG 。

接下来,设置一些训练变量 、 初始化列表并 设置 图像路径:

da8f4c1fc977e644724810074f81ceb9f926b3c1

第32-34 行定义模型的 训练次数 、 初始学习率 以及 批量大小 ;

第38 和 39 行 初始化数据和标签列表 , 这些列表 对应 存储图像 以及类别标签;

第42-44 行获取输入图像路径并将图像随机打乱;

现在 对 图像进行预处理:

291e97447a8e5e621f674e0947fa3f36a866c5b0

该循环简单的将每个图像的尺寸重新调整为28×28 大小 (为LeNet 所需要的空间尺寸)

能够提取标签是由于 我们的数据目录结构 如下所示 :

11bf89631e64bebe6d10aed38542e674cc09ddec

因此,imagePath 的一个例子为 :

553b927b15916c1998bf9ea1486efaffad827285

从ImagePath 提取 标签 ,结果 为 :

505c24a50c9a24a372d4c933ca711ddb71cc4e80

下一步,将数据集分为训练数据集和测试数据集:

820577bce7f3aa93791c9ea6f5fea2a5d5144a58

第61 行 进一步预处理输入数据 , 按比例 将 数据点[ 0, 255 ] 缩放到[ 0, 1 ] 范围内;

然后 第66-67 行将 75% 数据作为训练集, 25% 数据作为测试集;第 70-71 行对标签进行独热编码; 随后, 通过以下操作增加数据量:

ec05ddb47634423e87fa721b29114a55d957ce82

第74-76 行 创建一个图像发生器 ,对数据集图像 进行随机旋转 、 移动 、 翻转 、剪切等,通过这种操作允许我们能用 一个较小的数据集实现 好 的结果。

继续深入学习Keras 训练 图像 分类器:

330f3a9e6644e05f7a105d269ed3db7f122e3dec

第80-83 行使用 Adam 优化器, 由于本文是一个二分类问题,可以 使用二进制交叉熵损失函数 (binary cross-entropy )。但 如果执行的分类 任务多于两类 , 损失函- 数更换为 类别交叉熵 (categorical_crossentropy )

第87-89 行调用 model.fit_generator 开始训练网络,第 93 行保存模型参数,最后画出图像分类器的性能结果:

bb43119155aa0a9adb643f9030683d3dcb675d62

为了 训练网络 模型 , 需要 打开一个终端执行以下命令:

599eca63e184e422d6674d9216ccd4907b21638e

可以看到, 当 网络训练了25 个回合后, 模型的测试精度为97.40% ,损失函数也很低 ,如下图 所示 :

40aa6bc8c87caf1078e2135a494f7cc6bb85cd90

评估卷积神经网络图像分类器

打开一个新的文件 并命名为test_networkpy ,然后开始进行评估 :

1a8faecccd34d5bb7a4c145a930aa4662c43ccbf

第2-7 行导入 需要的 数据 包 ,另外注意导入的load_model 是训练过程中保存的模型 。

下一步,解析命令行参数:

c6d6a24f7ce0fc95e7b21992d9af19ce0bbda9c6

需要两个命令行参数:--model 和输入--image ,然后加载图像预处理:

17360190ac291697e136d8cfc0b278410270dfbe

预处理与前面几乎一模一样,这里不做过多的解释,只是第25 行通过 np.expand_dims 对数据额外 添加 了 一个维度 , 如果忘记添加维度,它将导致 调用model.predict 时出现 错误 。现在加载 图像分类器模型 并 进行预测:

d147012b150cac9f8a992d4a77c04be81895d828

第29 行加载模型,第 32 行做出预测。 最后 画出头像以及预测标签 :

e5d9a9d5f9397cfe151833a65f0d55180d247ffa

第35 行建立标签,第 36 行选择对应的概率值,第 37 行将标签文本显示在图像的左上角, 第40-42 行调整 图 像 大小为标准的宽度以确保它 适应电脑 屏幕,最后, 第45 行 显示输出图像 ,第46 行表示当 一个键被按下 结束显示。

以下是包含圣诞老人图像的实验结果:

dbf05757ac76ff9eaffb6561bbe6e57771d32b0b

1371eb19a5095b7cd6566382bc0cc530456425cd

以下是不包含圣诞老人图像的实验结果:

0a46ad8dd516e87af55b4c83ae6a163d4269aa61

8b641c89cb08c3c898aa80aeb3df2889140cfbf5

本文图像分类模型的局限性

本文 图像分类 器有一些局限性:

第一个是 输入图像尺寸28×28 很小 。 一些示例图像 (图像中圣诞老人本身已经很小)调整尺寸为28×28 后 大大 降低 圣诞老人的尺寸 。 

最优的 卷积神经网络正常接受 输入 图像 大小一般为200-300 像素 ,因此一些 较大 尺寸 的图像将帮助我们建立一个更强大的 图像 分类器。然而,使用更大的分辨率的图像 会加深网络模型的深度和复杂度, 这将意味着需要收集更多的训练数据, 以及 昂贵的计算训练过程。

因此,如果 各位读者想 提高 本文模型的精度话,有以下四点建议:

  • 收集更多的训练数据( 超过5000 幅“ 圣诞老人” 图像 ) ;
  • 利用高分辨率的图像在训练。 64×64 、128×128 像素 的图像可能效果会更 理想 ;
  • 在 训练 过程中使用一个更深层次的网络体系结构 ;
  • 阅读Deep Learning for Computer Vision with Python , 里面有更多关于 自定义数据集 等内容 的细节 ;

总结

  • 本文教你学 会 利用Keras 和 Pyhton 训练LeNet模型,并用来完成 是否含有圣诞老人形象的图像分类 ,最终目标 可以 是建立一个应用程序类似于Not Hotdog
  • “ 圣诞老人” 图像 数据集(460 幅) 是 按照 之前的教程——通过谷歌图片采集深度学习的图像 获得,而“ 没有圣诞老人 ” 的 图像 数据集是由 从UKBench数据集 中挑选得到;
  • 在 一系列的测试图像 上 评估 本文搭建的网络模型 ,在每一种情况下, 本文模型都能对输入图像 分类 正确 。

作者信息

 03539ed1f7341cc0bfddc238a9d505bf21bb3799

Adrain Rosebrock , 企业家 、 博士,专注于图像搜索引擎 。

Linkedin: www.linkedin.com/in/adrian-r…

本文由北邮@爱可可-爱生活 老师推荐,阿里云云栖社区 组织翻译。

文章原标题《Image classification with Keras and deep learning 》,作者: Adrain Rosebrock ,译者:海棠,审阅:。

文章为简译,更为详细的内容,请查看原文