图像分类的五种技术,算法和应用方法的总结和总结,并进行实验验证
介绍图像分类的五种技术,算法和应用方法的总结和总结,并进行实验验证。
图像分类问题在于为指定类别中的输入图像分配标签的任务。这是计算机视觉的基本问题之一,虽然看起来很简单,但在现实生活中有多种应用。
传统方式:功能描述和识别。
![]()
也许对于某些示例任务使用此方法更容易,但实际情况要复杂得多。
![]()
因此,我们没有尝试直接在代码中执行此操作,而是使用机器学习为每个类别提供大量示例,然后开发学习算法来查看这些示例并了解每个类别的内容就像视觉上一样。指定每个兴趣类别的外观。然而,
图像分类问题是一项非常复杂的任务,总是通过深度学习模型来解决,例如卷积神经网络(CNN)。但我们也知道,我们平时在课堂上学习的很多算法,比如KNN(最近邻算法)和SVM(支持向量机),都非常擅长解决数据挖掘问题,但似乎有时并不适合图像分类。该问题的最佳选择。
所以我们想将课堂上学习的算法与 CNN 的性能进行比较,并迁移学习算法。
目标
我们的目标是:
将 KNN、SVM 和 BP 神经网络与业界常用的解决图像分类问题的算法(例如 CNN 和迁移学习)进行比较。
获得深度学习的经验。
使用 Google 的 TensorFlow 探索机器学习框架。
算法和工具
在这个项目中我们使用了5种方法:KNN、SVM、BP神经网络、CNN和迁移学习。
整个项目主要分为三种方法。
第一种方法:KNN、SVM、BP神经网络,都是课堂上学到的算法,功能强大且易于实现。我们主要使用sklearn来实现这些算法。
另一种方法:虽然传统的多层感知器(MLP)模型已成功应用于图像识别,但它的扩展性不佳,因为节点之间的完全连接受到维数灾难的影响。分辨率图像。所以在这一部分,我们将使用Google的TensorFlow深度学习框架来构建CNN。
第三种方法:重新训练预训练深度神经网络的最后一层(称为Inception V3),这也是由TensorFlow实现的。Inception V3 接受了 ImageNet 大规模视觉识别挑战的训练,数据自 2012 年以来收集。这是一个标准的计算机视觉任务,模型尝试将整个图像分为 1000 个类别,例如“斑马”、“斑点狗”和“洗碗机”。要重新训练这个预训练网络,我们需要
如何应用
第一种方法:
预处理数据集并使用sklearn运行KNN,SVM和BP神经网络
首先,我们定义了两个不同的使用 OpenCV 包的预处理函数:第一个称为图像特征向量,它调整图像大小,然后将图像展平为线像素列表。第二个称为提取颜色直方图,从图像中提取 3D 颜色直方图。 HSV 颜色空间,然后将结果展平。
然后我们创建几个需要解析的参数,因为我们想要测试这部分的准确性,不仅针对整个数据集,还针对子数据集具有不同数量的标签,我们构建数据集作为程序解析的参数。同时,我们还构建k-NN方法中使用的邻居数作为分析参数。
之后,我们开始提取数据集中的每个图像特征并将其放入数组中。我们使用 读取每个图像,通过从图像名称中提取字符串 将标签分成多个部分。在我们的数据集中,我们使用相同的名称格式:“类标签”.“图像编号”.jpg,以便我们可以轻松提取每个图像的类标签。然后,我们使用之前定义的 2 函数来提取两个特征并将它们添加到数组 rawImages 和 features 中,而之前提取的标签则添加到 labels 数组中。
下一步是使用从 sklearn 包导入的函数 train_test_split 来分割数据集。后缀为RI、RL的集合是rawImages和标签对的分割结果,另一个是特征和标签对的分割结果。我们使用 85% 的数据集作为训练集,15% 作为测试集。
最后,我们使用KNN、SVM和BP神经网络函数对数据进行评估。对于 KNN,我们使用 KNeighbors 分类器;对于SVM,我们使用SVC;对于BP神经网络,我们使用MLPC分类器。
第二种方法:
使用 TensorFlow 构建 CNN。TensorFlow 的目的是允许您构建计算图(使用任何语言,例如Python),然后在 graph 上执行操作,这比在 C++ 中执行相同操作要快直接在Python中操作。计算效率更高。
TensorFlow 还可以自动计算优化图变量所需的梯度,使模型更好地工作。这是因为图是简单数学表达式的组合,因此可以使用链式法则计算整个图的梯度。
TensorFlow 图包含:
用于将数据插入到图中的占位符变量。
要优化的变量以获得更好的卷积网络性能。
卷积网络数学公式。
可用于优化变量的成本指标。
更新变量的优化方法。
CNN 架构是通过堆叠不同的层而形成的,这些层通过可微函数将输入量转换为输出量(例如类别分数)。
因此,在我们的实现中,第一层是图像存储,然后我们构建 3 个具有 2 × 2 最大池化和修正线性单元 (ReLU) 的卷积层。
输入是一个四维张量,具有以下维度:
图像编号。每个图像的
Y 轴。
每个图像的 X 轴。
每个图像的通道。
输出是另一个四维张量,其维度如下:
图像编号,与输入相同。每个图像的
Y 轴。如果使用 2×2 连接,输入图像的高度和宽度将除以 2。
每个图像的 X 轴。与上面相同。
由卷积的滤波器产生的通道。
然后我们在网格的末端构建 2 个完全连接的层。输入是 [number_of_images, number_of_inputs] 形式的 2D 张量。输出是 [number_of_images, number_of_outputs] 形式的 2D 张量。
然而,为了将卷积层和全连接层结合起来,我们需要一个平滑层,将 4 维张量降低为 2 维,以便可以用作全连接层的输入。
CNN的最后一端始终是softmax层,它对全连接层的输出进行归一化,使得每个元素都在0到1之间,并且所有元素的总和为1。
为了优化训练结果,我们需要成本衡量并最小化每次迭代。这里使用的成本函数是交叉熵(从()调用)并取所有图像分类的交叉熵的平均值。优化方法为 tf.train.AdamOptimizer(),它是梯度下降的改进形式。这是调整参数的学习率。
第三种方法:
重新训练 Inception V3 对象识别模型具有数百万个参数,可能需要数周时间才能完全训练。迁移学习是一种可以快速完成此任务的技术,方法是采用针对一组类别(例如 ImageNet)训练的模型,并根据现有权重针对新类别对其进行训练。虽然它的性能不如完整的锻炼,但它对于许多应用程序来说非常高效,并且可以在笔记本电脑上使用三十分钟,而无需GPU。对于这部分应用程序,我们可以按照以下说明进行操作:
首先,我们需要获得一个预训练的模型,删除旧的顶层并基于现有数据集训练一个新模型。完整的网络在原始 ImageNet 类上进行训练,没有猫的品种。迁移学习的神奇之处在于,经过训练以区分某些对象的较低层可以在不进行修改的情况下重复用于许多识别任务。然后,我们分析磁盘上的所有图像并计算每个图像的瓶颈值。单击此处 ( ) 了解瓶颈详细信息。每个图像在训练过程中都会被多次使用,因此计算每个瓶颈值需要花费大量时间,因此可以加速它们以缓存这些瓶颈值,这样就不必重新计算。
此脚本运行 4000 个训练步骤。每个步骤从训练集中随机选择十张图像,在缓存中找到它们的瓶颈,并将它们输入到最后一层进行预测。然后将这些预测与实际标签进行比较,从而通过反向传播过程更新最终层的权重。
开始实验
数据集
牛津IIIT宠物数据集()
有25个狗品种和12个猫品种。每个品种有200张图片。
我们的项目中只使用了 10 个品种的猫。
![]()
这里我们使用以下类型:['Sphinx'(加拿大无毛猫,又称斯芬克斯猫)、'Siamese'(暹罗猫)、'Ragdoll'(布偶猫)、'Persian'(波斯猫)、 'Maine-Coon'(缅因猫)、'British Shorthair'(英国短毛猫)、'Bombay'(孟买猫)、'Birman'(缅甸猫)、'Bengal'(孟加拉猫)]。
因此,数据集中共有 2000 张图像,大小各异。但我可以将它们调整为固定大小,例如 64x64 或 128x128。
预处理
在这个项目中,我们主要使用OpenCV来处理图像数据,例如将图像读入数组并根据需要进行更改。
改善图像训练结果的常见方法是以随机方式扭曲、裁剪或增亮训练输入,其优点是由于训练数据的所有可能的变化和偏斜而增加了训练数据的有效大小图像。帮助网络学习应对现实生活中使用分类器时出现的所有扭曲。
详情请参阅链接:https://
评估
第一种方法:
1。部分:数据集预处理和KNN、SVM和BP神经网络的实现。
程序有很多参数可以调整:在image_to_feature_vector函数中,我们设置的大小是128x128。我们过去也尝试过 8x8、64x64 和 256x256 等尺寸。所以我们发现图像尺寸越大,准确率越高。然而,大图像尺寸也会增加执行时间和内存消耗。所以我们最终选择了128x128的图像尺寸,因为它不太大但仍然保证了准确性。
在函数 extract_color_histogram 中,我们将每个通道的涂片数量设置为 32,32,32。与之前的函数类似,我们也尝试了 8、8、8 和 64、64、64,数字越大,结果越高,但执行时间也越长。所以我们认为32、32、32是最合适的。
在数据集方面,我们尝试了三种类型的数据集。第一个是包含 400 张图像和 2 个标签的子数据集。第二个是包含 1000 张图像和 5 个标签的子数据集。后者是包含 1997 张图像和 10 个标签的整个数据集。并且我们将不同的数据集解析为程序中的参数。在
KNeighborsClassifier中,我们仅更改了邻居的数量,并将结果保存为每个数据集的最佳K。然后将我们设置的所有其他参数重置为默认值。在
MLPClassifier 中,我们设置了一个包含 50 个神经元的隐藏层。我们测试了几个隐藏层,但最终结果似乎没有发生显着变化。最大迭代次数为1000次,容差为1e-4以保证其收敛。并将 L2 惩罚参数 α 设置为默认值,随机状态设置为 1,求解器设置为“sgd”,学习率设置为 。在
SVC中,最大迭代次数为1000次,类别权重值是“平衡的”。
我们程序的运行时间不是很长,从2个标记数据集到10个标记数据集,大约需要3-5分钟。
第二种方法:
使用 TensorFlow 构建 CNN。
由于模型使用了整个大数据集,计算模型的梯度需要很长时间。因此,我们在优化器的每次迭代中仅使用少量图像。批量大小通常为 32 或 64。数据集分为包含 1600 个图像的训练集、包含 400 个图像的验证集和包含 300 个图像的测试集。
有很多参数可以调整。
首先是学习速度。只要它足够小以能够收敛并且足够大而不会使程序太慢,找到一个好的学习率就很容易。我们选择1×10^-4。
第二个是我们传输到网络的图像的大小。我们尝试了64*64和128*128。事实证明,图像越大,我们获得的准确度就越高,但代价是工作时间相应增加。
然后是层及其形状。但实际上可调整的参数太多,因此找到这些参数的最佳值是一项非常困难的工作。
根据许多互联网资源,我们了解到网络建设参数的选择几乎总是依赖于经验。
最初我们尝试构建一个相对复杂的网络,其参数如下:
![]()
我们使用了3个卷积层和2个全连接层,它们相对复杂。
但结果就是——过度贴合。只有经过一千次迭代后,我们的程序才能达到 100% 的训练准确率,而测试准确率只有 30%。起初我很困惑为什么会得到过拟合的结果,并尝试任意调整参数,但结果却始终没有改善。几天后,我偶然看到一篇关于中国研究人员进行的深度学习项目的文章()。他们指出他们进行的研究是有问题的。 “技术问题是,如果你想训练和测试像 AlexNet 这样的 CNN,而又不过度拟合结果,仅使用少于 2000 个示例是不够的。”当时我就意识到,第一,我们的数据集其实很小,第二,我们的网络太复杂了。
请记住,我们的数据集恰好包含 2000 张图像。
然后我尝试减少内核层的数量和大小。我尝试了很多参数,下图是我们使用的最终结构。
![]()
我们只使用2个小形状的扭曲层和2个全连接层。但结果并不完全理想。经过 4000 次迭代后,结果仍然太拟合,但测试结果比之前好 10%。
我们仍在寻找解决此问题的方法,但明显的原因是我们的数据集不足,我们没有足够的时间进行更好的改进。
最终的结果是,经过 5000 次迭代,我们达到了约 43% 的准确率,而运行时间超过了半个小时。
PS:对于这个结果,我们其实有点不高兴。于是我们找到了另一个标准数据集——CIFAR-10()。
![]()
CIFAR-10 数据集由 10 个类别的 60,000 张 32x32 彩色图像组成,每个类别有 6,000 张图像。它包含 50,000 个训练图像和 10,000 个测试图像。
我们使用了上面构建的相同网络,经过 10 小时的训练,我们在测试集上获得了 78% 的准确率。
第三种方法:
重新训练Inception V3,与此相同,我们随机选择一些图像进行训练,并选择另一批图像进行确认。
有很多参数可以调整。
首先是训练步骤,默认值是4000,如果我们更早得到合理的结果,我们会尝试更多或尝试更少。
学习率控制着训练过程中最后一层的更新大小。直观上,如果它更小,学习时间会更长,但最终可能有助于提高整体准确性。 **训练批次**的大小控制着训练阶段学习的图像数量,并且由于学习率应用于每个批次,如果想要制作更大的批次来达到相同的结果,我们需要减少总体效果的数字。
由于深度学习是一项艰巨的任务,并且通常运行时间相对较长,因此我们不想在经过数小时的训练后发现我们的模型实际上很糟糕。因此,我们经常检查确认的准确性。这样我们也可以避免过度位移。分割允许您在主训练集中包含 80% 的图像,在训练期间留下 10% 用于验证,经常运行,然后使用最后 10% 作为测试集来预测分类器在现实世界中的表现。 。
结果
第一种方法:预处理数据集并使用sklearn运行KNN、SVM和BP神经网络。
结果如下图所示。由于SVM的结果非常差,甚至低于随机猜测,因此我们不提供其性能。
![]()
根据结果,我们可以看到:
对于K-NN,原始像素精度和直方图精度相对相同。在具有5个标签的子数据集中,直方图精度略高于原始像素,但在所有原始像素中,原始像素表现出更好的结果。
在神经网络MLP分类器中,原始像素精度远低于直方图精度。对于整个数据集(包含 10 个标签),原始像素精度甚至低于随机猜测。
这两种sklearn方法都没有给出很好的结果,在整个数据集(有10个标签的数据集)中正确类别检测的准确率只有24%左右。这些结果表明使用sklearn方法进行图像识别还不够好。它们在对具有多个类别的复杂图像进行分类时表现不佳。然而,与随机猜测相比,他们确实做了一些改进,但这还不够。
基于这个结果,我们发现需要引入一些深度学习方法来提高准确性。
第二种方法:如上使用TensorFlow构建CNN,由于过拟合,我们没有得到好的结果。
![]()
通常需要半个小时来运行训练,但由于结果的夸大,我们并不认为这个运行时间重要。与方法1相比,我们可以看到,虽然CNN的结果被夸大了,但我们仍然得到了比方法1更好的结果。
第三种方法:Retrain Inception V3。
![]()
整个训练的进度不超过10分钟。我们可以取得非常好的结果。基于此,我们实际上可以看到深度学习和迁移的巨大威力。
演示:
![]()
目标
根据以上比较,我们可以得出结论:
KNN、SVM和BP神经网络不能很好地执行图像分类等特定任务。 。
虽然CNN部分得到的结果太合适了,但仍然比课堂上学到的其他解决图像分类问题的方法要好得多。
迁移学习对于图像分类问题非常有效。无需GPU即可在短时间内准确快速地完成训练。即使您的数据集很小,它也能很好地防止过度拟合。
我们学到了一些关于图像分类任务的非常重要的经验教训。这样的作业与课堂上完成的其他作业完全不同。数据集比较大而且不稀疏,而且网络复杂,所以在不使用GPU的情况下运行时间相当长。
裁剪图像或调整图像大小以使其变小。
为每次训练迭代随机选择一个小批量。
从验证集中随机选择一小批进行验证,并在训练过程中经常报告验证分数。
尝试使用图像校正将输入图像集更改为新的、更大的、稍作修改的图像集。
对于图像分类任务,我们需要一个大于200 x 10的数据集。CIFAR10数据集包含60,000张图像。
更复杂的网络需要更大的数据集进行训练。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网