@sambodhi
2018-11-15T19:37:18.000000Z
字数 10382
阅读 6710
作者 | Rising Odegua
译者 | Sambodhi
编辑 | Tina
AI 前线导读:这是一篇实战类的文章,旨在向读者介绍计算机视觉的外围应用:图像分类问题。现在我们翻译了 Rising Odegua 撰写基于 keras 进行图像分类的文章。在本文,作者介绍了如何在数据集较小的情况下,如何使用 keras 进行图像分类。
上个周末,我经历了一场思想狂潮。
如果我有一个图像数据集,它非常非常小,我想自己捕获、并希望教会计算机能够识别或区分一些指定的类别,我应该怎么办呢?
假设我有几千张图像,我想训练一个模型,能够从一个类别自动检测出另一个类别。但是,我只有这么少的数据,那我能不能够训练出一个深度神经网络来成功地对这些图进行像分类呢?
经过研究,我发现,人们在计算机视觉领域中遇到的常见情况是:用很少的数据来训练深度神经网络。
让我们面对这一现实:并非每个人都可以访问 Google 或 Facebook 这样的大数据,而且有些数据很难获得。
但我也发现,这种问题的解决方案其实非常简单。今天,我将带领你们学习如何使用那些较小的图像数据集来训练卷积神经网络( Convolutional Neural Network ),前提是你需要有一个很好的分类器,它的分类正确率大约为 81%。
在下一篇文章中,我将展示一种非常强大的技术,称为迁移学习( transfer learning ),它能够将分类正确率提高到 95% 左右。
你现在就可以开始收集数据了。
我将使用 Kaggle 平台上现有的狗和猫的数据集。是的,我是挺懒的。我无法得到自己的数据。
Dogs vs. Cats Redux: Kernels Edition:
https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data
Kaggle 是全球数据科学和机器学习从业者的大本营。他们主办了一些最大的数据科学竞赛,这是一个获取开源数据以及向获奖专家学习的宝地。
我觉得我应该这样说:如果你来自非洲,我们有一个新平台,叫 Zindi( http://zindi.africa/ ),和 Kaggle 很像,但非常适合非洲社会。它包含了从非洲企业和组织收集来的数据集。这是防止人工智能出现偏见的一大步,而 Zindi 就是一个很好的平台。
让我们回到获取数据这个话题。在 Kaggle 的这一页上:
https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data
这里我们有两个选择,我们可以下载数据到我们自己的电脑上来训练模型,或者我们可以使用 Kaggle 内核,它为我们提供更多的算力,让我们可以使用 GPU,以及几乎所有预先安装的用于机器学习和深度学习的库。
我不知道你怎么想的,但我宁愿选择 Kaggle 内核,除非我有 GPU。
如果你能负担得起 GPU 的费用,或者你是一名玩家,已经拥有 GPU,并且你想在自己的电脑上训练模型,只是因为你太喜欢鼓捣电脑了,那么就你可以按照这些教程来设置属于你自己的深度学习工作站:
如果你想偷懒,或者买不起 GPU,那么就去 Kaggle 启动这个引擎吧。
点击这个连接:https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/kernels ,我们打开这个页面。
Kaggle 上的 cats vs dogs 内核
注意:当你浏览 Kaggle 竞赛页面时,你最好阅读一下数据描述。
接下来,单击 Kernels(内核),然后单击右上角的蓝色按钮 New Kernel,系统会问你选择内核的类型( Select Kernel Type )。选择 Notebook,这样我们就可以做一些互动编程。
如果你不知道什么是 notebook,或者需要提高 notebooking 技能,你可以参阅有关 Jupyter Notebook 的网站,这两个都很棒:
单击 Notebook,系统会创建一个新的私有内核,并自动将猫狗数据集添加到你的文件路径中,当然是在云端。
给你这个内核起个名字,然后给它施加超能力( GPU ),这样计算时间就会更短。
你的 Notebook 打开后就像这样子的。
现在,我们的内核已经准备就绪,让我们导入一些将要使用的库。键入以下代码,然后按下 shift Enter 来运行单元格。
导入以下库
cv2,也称为 OpenCV,是一种可用于 Python 和许多其他高级编程语言的图像和视频处理库。它用于各种图像和视频分析,如面部识别和检测、车牌识别、照片编辑、高级机器人视觉、光学字符识别等等。在本教程中,我们将使用它来读取和调整图像大小。
NumPy 是 Python 中最流行的数学库。有了这个库,大型、多维数组和矩阵的工作和计算变得简单快捷。它有大量的高级数学函数来操作这些数组。
Pandas 是一个为 Python 编程语言编写的软件库,用于数据处理和分析。值得一提的是,Panda 提供了用于操作数值表和时间序列的数据结构和操作。
Matplotlib 是 Python 的绘图库。可用于绘制线条、条形图、图形、直方图甚至显示图像。
%matplotlib inline 是一种命令,作用是使 Notebook 出现我们的图表。
os 是一个内置的 Python 包,用于访问你的计算机和文件系统。它可用于显示目录中的内容,创建新文件夹,甚至还可以删除文件夹。
random 可以帮助我们创建随机数,这些随机数将在我们拆分或者洗牌数据集时使用。
gc 是垃圾收集器的简称,是手动清理和删除不必要变量的重要工具。我们将在 Kaggle 内核上积极使用它,因为我们正在处理图像数据集,因此分配给我们的可用内存可能已经满了。
在导入必要的库之后,我们将图像读入到内存中。数据作为 Zip 文件的形式存储在内核中。
我们的数据
我们可以看到以下三个文件:
sample submission.csv
这是一个 csv(comma seperated value,逗号分隔值)文件,用于在训练模型并在给定的测试文件上对其进行测试之后进行提交。由于这次比赛已结束,我们无法提交,因此,我们将忽略这个文件。
test.zip
这个文件包含了我们将在训练后要测试模型的图像,以了解模型是否已经学会区分猫和狗。
train.zip
这个文件是我们模型的 “原材料”。它包含了我们要用来教会模型掌握狗或猫长什么样的数据。
现在,要访问我们的训练图像,我们将使用之前导入的 os 包。
注意:Kaggle 上的所有数据文件路径都以根目录../input 开头。例如,这个内核中训练数据的文件路径为../input/train。
导入我们的图像。
这里,我们创建了两个变量:train_dogs 和 train_cats。一个是所有的狗图像,另一个是所有的猫图像。我们编写了一个列表理解(list comprehension),它使用 os.listdir() 命令来获取训练数据 zip 文件中的所有图像,并在其名称中检索带有 dog 的所有图像。
我们对猫的图像也是如此操作。
我们也得到了测试图像。
训练数据集共包含 25000 张图像,但由于我们正在试验使用一个小型数据集,而且显然我们只能使用很少的算力,从这两个类中,我们只提取 2000 个图像。
非常重要! 我们随机洗牌 train_imgs。
在这里我们做一些清洗。你可能已经注意到,现在我们有了 train_imgs,就意味着train_dogs 和 train_cats 变量是无用的,占用了不必要的空间。如果不删除它们的话,当我们开始训练模型时,内存可能很快就耗尽了。
让我们在 train_imgs 查看一些图像。
让我们看看一些可爱的狗。
记住它的随机列表,但幸运的是,当我运行代码时,前三个图像是由两只狗和一只猫组成的,并注意到它们有不同的维度。
绘制的最后两个图像
在下一个代码块中,我们将使用 cv2 模块调整图像的大小。
首先,我们生命要使用的新维度。在本文中,我使用的是 150x150 来表示高度和宽度,还有 3 个通道。
声明一些重要的变量。
彩色图像由 3 个通道组成,即红色、绿色和蓝色像素值三组数组。我们可以使用 1 个通道来读取灰度格式(黑白)的图像。
现在,我们编写一个小函数,来帮助我们读取图像并调整为上述高度和宽度。
辅助函数
现在,让我们调用函数并处理图像。
X, y = read_and_process_image(train_imgs)
X 现在是图像像素值数组的列表,y 是标签列表。让我们预览 X 中的第一张图片。
是的,这就是你的电脑所说的狗。
我的朋友是一条狗的形象。或者我们可以说我们的电脑叫什么狗。等一下,我怎么知道它是一条狗呢?让我们看一下标签列表 y 中的响应值。
记住1代表狗,0代表猫。
要记得我们说过,1 代表狗,0 代表猫。
还是不相信我,对吧?好,让我们绘制 X 的前 5 个数组。我们不能用上面提到的 matplotlib.image 的 mpimg 模块在 X 中绘制图像,因为这些现在是像素数组,不是原始的 jpg 文件。因此,我们应该使用 imshow() 命令。
绘制前5个图像
现在,我们确信训练集已包含适当的狗和猫的图像,来看一下标签。要记住我们前面说过,总共有 4000 个图像(2000 条狗和 2000 只猫),因此我们的标签列表 y 应该包含 2000 个 1 和 2000 个 0。让我们绘制出来并确认一下。
标签的数量柱状图
棒极了!现在我们有了 2000 个猫和狗的类数。让我们继续。
接下来,检查数据的形状。记得要经常检查并确认数据的形状,这点非常重要。
数据的形状。
我们可以看到,我们的图像是 4 阶张量,或者可以说是一个大小为 400x150x150x3 的 4 维数组,分别对应于批大小、高度、宽度和通道。
图像数组的形状对于我们要构建的 keras 模型很重要。该模型将一个数组(高度、宽度、通道)作为输入。
现在,我们的数据(X,y)已准备就绪,可以开始训练。但首先,我们必须做一些非常重要的事,那就是将我们的数据拆分成训练集和验证集。在开始训练模型之前,这是最重要的事情之一。
对于数据的拆分,我们将使用 python 中的一个名为 sklearn 的流行机器学习包中的一个函数,这个函数非常方便。
接下来,我们将声明一些重要的变量,这些变量将在训练模型时使用。
现在是时候创建我们的模型了。
我们将使用卷积神经网络(convnet)来训练模型。卷积神经网络是目前计算机视觉问题的标准。在任何图像问题中,它们总是优于其他类型的神经网络。
你还不熟悉卷积神经网络吗?在文末中有一些不错的网址,你可以从中了解关于卷积神经网络的信息。
我们将使用 KERAS(https://keras.io/)来创建模型。
据 Wikipedia:
Keras 是一个用 Pythono 编写的开源神经网络库。它能够运行在 TensorFlow、Microsoft Cognitive Toolkit 或 Theano 之上,旨在实现深度神经网络的快速实验,注重用户友好、模块化和可扩展性。
首先,我们导入将要使用的必要 keras 模块:
这里,我们导入 keras layers 模块,它包含了用于深度学习的不同类型的层,例如:
这里我们导入 keras 模型,它包含两种类型:
这里我们导入 keras optimizer(优化器),这是一个包含不同类型的反向传播算法的模块,用于训练模型。其中一些优化器是:
现在,让我们创建网络架构,我们将遵循一种流行、有效和简单的架构,名为 VGGnet。
VGGnet:参见 Very Deep Convolutional Networks For Large-Scale Image Recognition
https://arxiv.org/pdf/1409.1556
网络架构就是我们排列卷积层的方式。
我们将使用一个小型的 vggnet,但是你可以看到,我们的过滤器的大小会随着向下层而增加。
32 → 64 →128 →512 — 最后一层是 1。
在这里,通过调用我们创建的模型上的 .add() 函数来创建第一层,并传递我们想要的层类型:Conv2D 层。第一层称为 input player(输入层),有一些重要的参数需要设置。
我们没有传递 4000 的第一个维度,因为这是批维度。
这里,我们添加 MaxPool2D 层。 它的作用是减小输入特征和空间尺寸,有助于减少网络中参数的数量和计算量,从而减少过拟合。
当模型记忆训练数据时,就会发生过拟合( Overfitting )。该模型在训练时表现出色,但在测试时会失败。
这里我们添加一个值为 0.5 的 Dropout 层。在神经网络中,随机丢弃一些层,然后用减少的网络来学习。通过这种方式,网络在单个层上学会了独立和不可靠。更重要的是,它有助于过拟合。
0.5 的意思是随机丢弃一半的层。
随后一层的输出大小为 1,另一个不同的激活函数称为 sigmoid。这是因为我们试图检测图像是狗还是猫。即我们希望模型输出图像是狗而非猫的概率,这意味着我们需要概率分数,其中较高的值意味着分类器认为图像是狗,较低的值则认为它是猫。
sigmoid 非常适合这种任务,因为它接受一组数字,并返回 0 到 1 范围内的概率分布。
我们可以通过调用模型对象上的 keras 函数 .summary() 来预览卷积神经网络的布局和参数大小。
我们可以看到我们想要训练的参数的数量(300 万以上)和不同层的总布局。
下一步是编译模型。
我们将三个参数传递给 model.compile() 命令。
因为我们做的是分类问题,因此正确率指标 (acc) 是一个不错的选择。
注意:用于测量模型性能的度量指标取决于你正在处理的问题类型。。
最后,在开始训练模型之前,我们需要执行一些归一化。也就是将我们的图像像素值进行缩放,使其具有单位标准偏差且均值为 0。
我们将在 keras 使用一个名为 ImageDataGenerator 的重要模块,当我们在训练期间将图像输入模型时,这个模块会执行一些重要的功能。
但请告诉我什么是 ImageDataGenerator?
据 keras 作者 Francois Chollet 的说法,Keras ImageDataGenerator() 可以让我们快速设置 python 生成器,自动将图像文件转换为预处理的张量,可在训练期间直接输入到模型中。它可以轻松地执行以下功能:
让我们创建 ImageDataGenerator 对象。我们将创建两个生成器,一个用于训练集,另一个用于验证集。
现在我们有了 ImageDataGenerator 对象,让我们通过传递训练集和验证集来创建 python 生成器。
仅仅经过 64 个轮数之后,正确率就到达了约 80%。
模型训练的截图。
对于我们的模型来说是很不错了,因为我们是从零开始训练的,而且数据非常少。
增加轮数并使用批大小和优化器等一些超参数进行训练模型,也许有助于提高表现。
我把这个问题留给你们去探究。
接下来,保存我们的模型,使用如下所示的简单 Keras 函数,这样我们就可以在任何时候重用它,而不必在重新运行 notebook 时再次进行训练。
#Save the model
model.save_weights('model_wieghts.h5')
model.save('model_keras.h5')
我们将绘制一些图表,显示训练集和验证集的正确率和损失,看看是否能得到一些见解。
根据轮数绘制正确率。
那么,我们能够从这幅图得到什么样的信息呢?
根据轮数绘制损失
我们仍然没有发生过拟合,因为训练和验证损失都在接近下降的趋势,就像上面的正确率曲线的那副图一样。如果我们增加轮数的大小,损失可能会更低。
如此一来,你就有了一些直觉。现在试着增加轮数的大小并使用一些超参数看看会发生什么。
在结束本教程之前,我们将在测试集中的一些图像上测试模型。
用于预处理测试图像的代码
我们执行与训练集和验证集相同的预处理。
现在,我们将创建一个简单的 for 循环,它迭代生成器中的图像以进行预测。然后我们将结果绘制出来。
让我们看看模型在之前未见过的图像上是如何执行的。
嗯,模型从五张图片中,出了一个错误。但我并没有说过这模型是最好的…… 至少现在还没有说过。
本文确实篇幅很长,但我认为写出来还是值得的。在下一个教程中,我们将通过使用与训练的网络来改进模型,使其正确率达到 96% 左右。
敬请期待,祝你好运!
这是是我的 notebook 上关于 Kaggle 教程的链接:http://kks.me/aU7ea
下面是 CNN 和 keras 的精彩文章和书籍:
原文连接:
https://towardsdatascience.com/image-detection-from-scratch-in-keras-f314872006c9