weka分类器怎么设置类别_手把手教你用PyTorch实现图像分类器

(关注AI新视野公众号,发送‘资料’二字,免费获取50G人工智能视频教程!)

8dc5ab8f1169f0f25542560be11646bc.png

经过几个月富有挑战性但是受益良多的学习,我最近从Udacity的Python Nanodegree program AI编程专业毕业。最后一个项目是用PyTorch创建一个102种不同类型的花的图像分类器。

在做这个final project的时候,很多同学都遇到了类似的问题和挑战。当我接近完成的时候,我决定与大家分享一些在未来对他人有益的建议和见解。

本文介绍如何实现图像分类器的概念基础------这是一种能够理解图像内容的算法。

本文的目标不是提供手把手的指导,而是帮助理解整个过程。如果你正在考虑学习机器学习或人工智能,你将不得不做类似的项目,并理解本系列文章中介绍的概念。

文章主要进行概念上的解释,不需要知道如何编写代码。此外,下面所包含的PyTorch细节是次要的,主要以PyTorch作为示例。

这个过程的第一步是加载一个pre-trained神经网络。在讨论这一步时,我将解释为什么要"reuse"网络(即使用"pre-trained"网络),阐明哪些部分可以重用,哪些部分不能重用,并提供如何根据需要定制pre-trained网络的指导。

加载预训练的网络

reuse是一种十分合理的策略,尤其是众所周知并且得到广泛认可的标准。在示例中,出发点是torchvision提供的一种模型结构。

本文的目标是加载其中的一个pre-trained网络,并且将其中的分类器替换为自己的分类器,从而可以训练自己的分类器。

虽然这个想法是合理的,但我发现它也会产生一些问题,因为加载一个预先训练的网络并不能节省训练分类器的时间。

"所以你可能会想,使用预训练网络有什么意义?"

当我们人类看到图像时,可以识别线条和形状。正因为如此,我们才能将图像内容与之前看到过的内容联系起来。我们希望我们的分类器能够做一些类似的事情,但是图像不是一段微不足道的数据。图像通常由数千个独立的像素组成,每个像素都有一种颜色,这种颜色由三个不同的值组合定义 : Red,Green, Blue。

94c25b61b00676eb990ec8c939662564.png

从左到右:原始,红色,绿色,蓝色

如果我们希望我们的分类器能够处理该数据量,我们将需要处理每个图像中包含的所有信息,并以其可以理解的格式将其提供给分类器。这就是预训练网络发挥作用的地方。

这些预先训练的网络主要由一组特征检测器和分类器组成,其中特征检测器被训练以从每个图像中提取信息,并且训练分类器以理解特征层提供的输入。

我们已经在已在ImageNet上培训过功能检测器,并且证明它可以有很好的表现。因此,我们希望保持原样。为了防止在我们训练分类器时,要素图层被修改,我们需要"冻结"它们。这个小代码片段可以帮助解决这个问题:

for param in model.parameters(): param.requires_grad = False

如果使用分类器会怎么样? 为什么我们不能重复使用它? 要回答这个问题,让我们以架构VGG16为例,来看看它的默认分类器:

(classifier): Sequential( (0): Linear(in_features=25088, out_features=4096, bias=True) (1): ReLU(inplace) (3): Linear(in_features=4096, out_features=4096, bias=True) (4): ReLU(inplace) (5): Dropout(p=0.5) (6): Linear(in_features=4096, out_features=1000, bias=True))

首先,我们无法保证这一定是有效的。并且令人怀疑的是,这些默认层和元素,激活函数和丢失值对于我们的特定情况而言恰好是最佳的。

当我们看到它的最后一层有1000个元素的输出时,情况就变得很明显了。在我们的例子中,我们处理102种不同类型的花,因此我们的分类器的输出必须是102 。

从上面VGG16中的默认分类器,我们还可以注意到它的输入层有25088个元素,因为这是此特定预训练模型中特征检测器的输出大小。我们的分类器的输入大小也必须与要素图层的输出相匹配。

小结由上文我们可以得知,预先训练好的网络非常有益,因为它们使我们能够专注于我们的用例细节,同时重复使用众所周知的泛型来进行示例中的图像预处理。

我们还了解到,分类器输出的大小必须与我们希望能够识别的不同类型的数量相同。

最后,我们已经看到要素图层的输出和自定义分类器的输入也必须匹配大小。

训练分类器

首先我们要做的是将训练用的图片喂给我们的分类器,我们可以使用PyTorch中的ImageFolder接口载入图片。预训练网络要求我们输入的都是某种特定格式的图片,因此,在将图片喂给神经网络前,我们需要对图片进行某些变换以达到对图片的裁剪和归一化。

具体来说,我们会将输入图片裁剪至224x224尺寸并且使用[0.485, 0.456, 0.406]和[0.229, 0.224, 0.225]两个参数作为均值和标准差进行归一化。归一化使得图片颜色通道数值中心化于0同时使得标准差为1。

接着我们可以使用PyTorch中的DataLoader接口将所有图片分成不同的批次。因为我们需要三种图片数据集------训练集,验证集和测试集,所以我们需要为每个数据集分别创建一个读取器。好了,万事俱备,我们可以开始训练我们的分类器了。

进行到此处我们将碰到最重要的挑战:模型准确度让我们的模型去识别一张我们事先已经标注好类别的图片并不难,然而我们需要我们的模型拥有泛化能力,即让模型可以识别我们从未标注过的花卉图片中的花卉种类。我们可以通过防止模型的过拟合达到模型泛化的目的。过拟合的意思为:我们的模型参数太过于满足我们自己的训练图片的准确度,从而可能导致无法对除了训练集之外的其他图片进行准确识别。即模型在训练集上表现优越,但是在测试集和验证集上误差很大。

063b1c72f9aeab85bc385b2ebfa8544d.png

不同的参数可以帮助模型达到最佳拟合

隐藏层我们总是很容易陷入更多或更大的隐藏层能够提高分类器准确性这样的思维误区,然而这个说法不总是对的。

增加隐藏层的数量和尺寸会使得我们的分类器考虑更多除了那些至关重要的参数以外的参数。例如,将噪音也视为花卉的一部分。这将导致过拟合以及模型准确度的下降。不仅如此,增加隐藏层的数量和尺寸也将花费我们更多时间去训练分类器和利用分类器去预测结果。

正因如此,我们建议开始训练网络时采用较少数量和较小尺寸的隐藏层,同时隐藏层的数量和尺寸根据训练进展按需增加,而不是一开始便在网络中加入大量和大尺寸的隐藏层。

在Udacity的利用python进行AI编程纳米学位项目中的花卉分类器项目中(我在本系列文章的第一篇推文中介绍了该项目),利用训练集进行第一次全训练轮次时,我仅仅利用包含一层小规模隐藏层的网络便获得了超过70%的准确度

数据增强我们有一批图片用来训练我们的模型,这是极好的事情,但是如果我们有更多的图片,这将会变得更好。此时数据增强便派上了用场。在训练模型的每一回合中,每张图片会被喂入网络一次。但是在每次喂给网络之前,我们可以对图片进行任意的变换,例如旋转,平移,缩放。通过这种方式,在不同的训练回合中,同一张图片将会以不同的形式喂给神经网络。增加训练数据的多样性可以减少过拟合的出现概率,相应地也提高了模型的泛化能力,从而提高了模型总体的准确性。

打乱数据集当训练神经网络时,为了防止模型出现任何偏向性,我们需要以任意顺序将图片喂给神经网络。

例如,一开始如果我们只将矮牵牛花图片喂给分类器,那么该分类器的张量很容易倾向于矮牵牛花。事实上,此时此刻,我们的分类器将会只知道矮牵牛花这一种花。即使接下来我们使用其他种类花卉图片来继续训练模型,这种最初的对于某种花卉的倾向性将会随着时间继续存在。

为了防止这种现象的发生,我们需要在数据载入器中打乱图片顺序,只需要简单的一步------在创建载入器时添加shuffle=True语句即可。

trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

随机失活有时,分类器内的神经网络节点会产生过多的影响,从而使得其他节点不能进行正常的训练。同时,节点之间会产生相互依存关系从而导致过拟合。

随机失活是在每一次训练中通过使一些节点随机失活来防止上述现象发生的一种训练技巧。因而,每一次训练中分别训练了所有节点中的不同子集,从而减少了过拟合现象的发生。

e285e7d9ab0c75688893d08766982026.png

暂且先不谈论过拟合,我们需要时刻记住的是学习率可能是最重要的超参数。如果学习率太大,我们可能永远得不到误差的最小值,如果学习率太小,分类器的训练过程会变得非常漫长。典型的学习率数值分别是:0.01,0.001,0.0001等等。

最后但也仍然非常重要的是,对位于分类器最后一层的激活函数的正确选择也会大幅改善模型准确度。例如,如果在神经网络中我们使用了负对数似然损失函数,按照文档所述,那么建议在最后一层使用LogSoftmax激活函数。

小结为了训练一个拥有泛化能力,同时在预测新图片中的花卉种类有着高准确度的模型,理解模型训练过程是非常有用的。

在文章中我们讨论了过拟合是如何影响模型的泛化能力以及如何防止过拟合的发生。同时我们也提及了学习率的重要性以及常用的学习率。最后,我们可以看出在最后一层中选择正确的激活函数也是至关重要的。

既然我们知道了如何训练模型,我们便可以使用模型去识别模型从未见过的图片中的花卉种类。

预测花的品种

一旦我们的分类器训练完成,我们希望每次我们需要分析一张图像时都不必再次训练它。所以我们想保存分类器,这样我们就可以在需要的时候再次加载它。

使用torch.save[1]方法,我们可以轻松地存储包含我们需要保留的值的字典。类似地,当我们需要使用分类器时,我们可以使用torch.load[2]来检索字典。

专业提醒:您可以保存结构类型。这将允许您了解应加载哪个初始模型结构。此外,您可以轻松找到分类器的输入大小,具体取决于所选的初始架构:

ResNet, Inception: input_size = model.fc.in_featuresVGG: input_size = model.classifier[0].in_featuresDenseNet: input_size = model.classifier.in_featuresSqueezeNet: input_size = model.classifier[1].in_channelsAlexNet: alexnet.classifier[1].in_features
16dd7388ab6ff1ec92bb67f379e843c0.png

水晶球

要预测花的类型,我们需要先加载图像。为此,我们可以使用PIL[3]。调整图像大小和裁剪以匹配神经元网络所需的输入大小 224x224 后,我们需要将其转换为 numpy[4] 数组。

RGB 颜色通常编码为整数从 0 到 255。由于我们的模型需要在 0 和 1 之间的浮点型数字,我们需要将RGB颜色除以 255。然后,我们再减去平均值,除以标准差来规范化[5]数据。

如上文所示,为了规范化我们的数据,我们将使用 [0.485、 0.456、 0.406] 表示平均值,将 [0.229、0.224、0.225] 设置成标准差。

最后一点,我们需要解决 numpy 数组在其第三个维度中具有颜色,而 PyTorch 中位于第一个维度中。为了使数据与输入格式匹配,我们需要使用转置来对其尺寸重新排序。

最后,我们可以使用 tototo.from_numpy[6]为该 numpy 数组创建张量,并将它们传递给模型。传递结果中函数totorch.topk[7]将给我们提供具有相应概率的预测概率最高的类别。

请注意,使用 Softmax 作为最终激活函数时,所有类的概率应为总和 1。在使用 LogSoftmax 的情况下,我们将获取概率的对数。多亏了 matplotlib,我们可以像这样表示预测结果:

760449c19c00fc96b04d4269b2c087b9.png

预测结果

小结在这最后一篇文章中,我们学习了如何保存和加载分类器。我们还讨论了如何预测新图像中的类型,主要收获是我们需要预先处理图像,以匹配神经网络期望的格式。

完成后,我们可以创建张量,并使用 topk 方法查找概率最高的类,并绘制结果以简化可视化。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值