使用深度学习进行图像分类

解决任何真实问题的重要一步是获取数据。Kaggle提供了大量不同数据科学问题的竞赛。我们将挑选一个2014年提出的问题,然后使用这个问题测试本章的深度学习算法,并在第5章中进行改进,我们将基于卷积神经网络(CNN)和一些可以使用的高级技术来改善图像识别模型的性能。大家可以从https://www.kaggle.com/c/dogs-vs-cats/data下载数据。数据集包含25,000张猫和狗的图片。在实现算法前,预处理数据,并对训练、验证和测试数据集进行划分是需要执行的重要步骤。数据下载完成后,可以看到对应数据文件夹包含了如图3.6所示的图片。

图3.6

当以图3.7所示的格式提供数据时,大多数框架能够更容易地读取图片并为它们设置标签的附注。也就是说每个类别应该有其所包含图片的独立文件夹。这里,所有猫的图片都应位于cat文件夹,所有狗的图片都应位于dog文件夹。

图3.7

Python可以很容易地将数据调整成需要的格式。请先快速浏览一下代码,然后,我们将讲述重要的部分。

上述代码所做的处理,就是获取所有图片文件,并挑选出2,000张用于创建验证数据集。它把图片划分到了cats和dogs这两个类别目录中。创建独立的验证集是通用的重要实践,因为在相同的用于训练的数据集上测试算法并不合理。为了创建validation数据集,我们创建了一个图片数量长度范围内的数字列表,并把图像无序排列。在创建validation数据集时,我们可使用无序排列的数据来挑选一组图像。让我们详细解释一下每段代码。

下面的代码用于创建文件:

glob方法返回特定路径的所有文件。当图片数量巨大时,也可以使用iglob,它返回一个迭代器,而不是将文件名载入到内存中。在我们的例子中,只有25,000个文件名,可以很容易加载到内存里。

可以使用下面的代码混合排列文件:

上述代码返回25,000个0~25,000范围内的无序排列的数字,可以把其作为选择图片子集的索引,用于创建validation数据集。

可以创建验证代码,如下所示:

上述代码创建了validation文件夹,并在train和valid目录里创建了对应的类别文件夹(cats和dogs)。

可以用下面的代码对索引进行无序排列:

在上面的代码中,我们使用无序排列后的索引随机抽出2000张不同的图片作为验证集。同样地,我们把训练数据用到的图片划分到train目录。

现在已经得到了需要格式的数据,我们来快速看一下如何把图片加载成PyTorch张量。

1.把数据加载到PyTorch张量

PyTorch的torchvision.datasets包提供了一个名为ImageFolder的工具类,当数据以前面提到的格式呈现时,它可以用于加载图片以及相应的标签。通常需要进行下面的预处理步骤。

1.把所有图片转换成同等大小。大多数深度学习架构都期望图片具有相同的尺寸。

2.用数据集的均值和标准差把数据集归一化。

3.把图片数据集转换成PyTorch张量。

PyTorch在transforms模块中提供了很多工具函数,从而简化了这些预处理步骤。例如,进行如下3种变换:

· 调整成256 ×256大小的图片;

· 转换成PyTorch张量;

· 归一化数据(第5章将探讨如何获得均值和标准差)。

下面的代码演示了如何使用ImageFolder类进行变换和加载图片:

train对象为数据集保留了所有的图片和相应的标签。它包含两个重要属性:一个给出了类别和相应数据集索引的映射;另一个给出了类别列表。

把加载到张量中的数据可视化往往是一个最佳实践。为了可视化张量,必须对张量再次变形并将值反归一化。下面的函数实现了这样的功能:

现在,可以把张量传入前面的imshow函数,将张量转换成图片:

上述代码生成的输出如图3.8所示。

图3.8

2.按批加载PyTorch张量

在深度学习或机器学习中把图片进行批取样是一个通用实践,因为当今的图形处理器(GPU)和CPU都为批量图片的操作进行了优化。批尺寸根据我们使用的GPU种类而不同。每个GPU都有自己的内存,可能从2GB到12GB不等,有时商业GPU内存会更大。PyTorch提供了DataLoader类,它输入数据集将返回批图片。它抽象出了批处理的很多复杂度,如应用变换时的多worker的使用。下面的代码把前面的train和valid数据集转换到数据加载器(data loader)中:

DataLoader类提供了很多选项,其中最常使用的选项如下。

· shuffle:为true时,每次调用数据加载器时都混合排列图片。

· num_workers:负责并发。使用少于机器内核数量的worker是一个通用的实践。

3.构建网络架构

对于大多的真实用例,特别是在计算机视觉中,我们很少构建自己的架构。可以使用已有的不同架构快速解决我们的真实问题。在我们的例子中,使用了流行的名为ResNet的深度学习算法,它在2015年赢得了不同竞赛的冠军,如与计算机视觉相关的ImageNet。为了更容易理解,我们假设算法是一些仔细连接在一起的不同的PyTorch层,并不关注算法的内部。在第5章学习卷积神经网络(CNN)时,我们将看到一些关键的ResNet算法的构造块。PyTorch通过torchvision.models模块提供的现成应用使得用户更容易使用这样的流行算法。因而,对于本例,我们快速看一下如何使用算法,然后再详解每行代码:

models.resnet18(pertrained = True)对象创建了算法的实例,实例是PyTorch层的集合。我们打印出model_ft,快速地看一看哪些东西构成了ResNet算法。算法的一小部分看起来如图3.9所示。这里没有包含整个算法,因为这很可能会占用几页内容。


图3.9

可以看出,ResNet架构是一个层的集合,包含的层为Conv2d、BatchNorm2d和 MaxPool2d,这些层以一种特有的方式组合在一起。所有这些算法都将接受一个名为pretrained的参数。当pretrained为True时,算法的权重已为特定的ImageNet分类问题微调好。ImageNet预测的类别有1000种,包括汽车、船、鱼、猫和狗等。训练该算法,使其预测1000种ImageNet类别,权重调整到某一点,让算法得到最高的准确率。我们为用例使用这些保存好并与模型共享的权重。与以随机权重开始的情况相比,算法以微调好的权重开始时会趋向于工作得更好。因而,我们的用例将从预训练好的权重开始。

ResNet算法不能直接使用,因为它是用来预测1,000种类别,而对于我们的用例,仅需预测猫和狗这两种类别。为此,我们拿到ResNet模型的最后一层——linear层,并把输出特征改成2,如下面的代码所示:

files = glob(os.path.join(path,'*/*.jpg')) no_of_images = len(files) shuffle = np.random.permutation(no_of_images) train = files[shuffle[:int(no_of_images*0.8)]] valid = files[shuffle[int(no_of_images*0.8):]]class Architecturel(nn.Module): def init (self, input_size, hidden_size, num_classes): super(Architecturel, self). init () self.fcl = nn.Linear(input_size, hidden_size) self.relu nn.ReLU() self.fc2 = nn.Linear(hidden_size, num_classes) self.relu = nn.ReLU() self.fc3 = nn.Linear(hidden_size, num_classes) def forward(self, x): out = self.fcl(x) out = self.relu(out) out = self.fc2(out) out = self.relu(out) out = self.fc3(out) return outclass Architecture2(nn.Module): def init (self, input_size, hidden_size, num_classes): super(Architecture2, self). init () self.fcl = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU() self.fc2 = nn.Linear(hidden_size, num_classes) def forward(self, x): out = self.fcl(x) out = self.relu(out) out = self.fc2(out) return outmodel =Architecturel(l〇,2〇,2) optimizer = torch.optim.Adam(model.parameters(), lr=le-4, weight_decay=le-5)nn.dropout(x, training=True) scheduler = StepLR(optimizer, step_size=30, gamma=0.1) for epoch in range(100): scheduler.step() train(...) validate(...) scheduler = MultiStepLR(optimizer, milestones=[30,80], gamma=0.1) for epoch in range(100): scheduler.step() train(...) validate(...) optimizer = torch.optim.SGD(model.parameters(), lr=〇.l, momentum=0.9) scheduler = ReduceLR〇nPlateau(optimizer, 'min') for epoch in range(lO): train(...) val_loss = validate(...) # Note that step should be called after validate() scheduler.step(val_loss)

获取更多专业知识请关注公众号:“人工智能技术与咨询”

文章内容转自《PyTorch深度学习》,针对转载原作者有任何疑问,请第一时间联系我们,我们会进行调整或删除。


全部评论
有点难,看不太懂
点赞 回复 分享
发布于 2022-08-12 16:19

相关推荐

哞客37422655...:这就是真实社会,没有花里胡哨的安慰,让你感受到阶级分明,不浪费彼此时间。虽然露骨但是唉
点赞 评论 收藏
分享
2025-12-25 10:16
已编辑
合肥工业大学 后端工程师
如题,在历经了长达多月的焦急等待,楼主也算是如愿以偿收到了梦中情司的意向了,秋招也终于是落下了帷幕,虽然手中的offer不够打牌,但已经满足了。华为时间线:9.3 笔试环节,惊险通过10.15 线下面试,前两轮技术面手撕都比较轻松,面试官态度也很好,最后一轮主管面,向主管表达了强烈的意愿,主管很和蔼,面试体验非常棒,1125定律后入池成功11.19 收到接口人的保温电话12.9 接到部门hr的保温电话,介绍了一下部门负责的工作12.23 收到华为的意向书,成为华孝子一枚~期间收到了之前实习过的公司的offer,害怕华子泡不出来就先签三方了,这下不得不毁约了,在此向前司道个歉,也感谢前司对我的认可和托举,祝业务蒸蒸日上~感谢从今年三月开始找暑期实习以来,所有朋友和家人的鼓励,我们宿舍的就业氛围相当好,大家会分享各种有用的信息以及面试中遇到刁钻的面试题,在有人收到offer的时候我们都会发自内心的高兴和祝福,在我去线下面的时候也借我穿过西服.....能在大学四年分入这么好的宿舍拥有这么这么好的舍友除了幸运我找不出其他的形容词。还要感谢我的父母,在我每一次面试前都给予鼓励,也在失败的时候安慰我,他们的托底是我前进的基石,以后有工资了要给父母买很多东西最感谢的是我的女朋友,我们从大一相识,一直坚持到大四,她是一个非常优秀也异常坚定的女生,也正是因为她的实力出众早再年初就定好了要去上海的一家外企。我为了也去上海,从暑期实习开始投了不少上海的岗位但无一例外的都被拒之门外,但这期间她从来没有嫌弃过我,反而一直鼓励我相信我,如果说父母的托底是我前进的基石,那女朋友的鼓励和信任则是我前进的动力和方向。在如今这个充满戾气和对立的社会,能找到一个一心一意彼此喜欢的人实在是很难得,我深知这种珍贵所以更会加倍珍惜也感谢自己吧,在经历了无数个失眠的夜晚和面试失败的打击下,最终还是迎来了最好的结果,记得在华为线下面的前几周我几乎回到了高三时期的作息,那真是一段充实美好的时光,好在最后的结果也没有辜负这份努力也想跟所有的牛友说:不要因为一时的失败而自怨自艾,妄自菲薄,只要坚持下去,总会有柳暗花明又一村的惊喜在等待着你,机会总是垂青于有准备的人,要相信否极泰来,相信自己。朋友,坚定地相信未来吧,相信不屈不挠的努力,相信战胜死亡的年轻,相信未来、热爱生命。
小肥罗:有这样的女朋友真是幸福
秋招白月光
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务