机器学习花朵图像分类_在PyTorch中使用转移学习进行图像分类
想了解更多好玩的人工智能应用,请关注公众号“机器AI学习 数据AI挖掘”,”智能应用"菜单中包括:颜值检测、植物花卉识别、文字识别、人脸美妆等有趣的智能应用。。
在此文章中,我们讨论了PyTorch中的图像分类。我们将使用CalTech256数据集的一个子集对10只动物的图像进行分类。我们将介绍数据集准备,数据扩充和构建分类器的步骤。我们使用转移学习来使用低级图像特征(例如边缘,纹理等)。这些是通过预先训练的模型ResNet50来学习的,然后训练我们的分类器来学习数据集图像(例如眼睛,腿等)中的高级细节。已经在ImageNet上接受了数百万张图像的培训。
不用担心功能和代码。该博客提供了一些代码段,以使其易于学习和理解。此外,完整的代码已通过python笔记本提供(关注公众号,回复”图像分类“获取源代码)。
尽管我们试图使博客自给自足,但我们仍鼓励读者在继续之前先熟悉Pytorch的基础知识。
数据集准备
该 CalTech256数据集有分为256个不同的标记类与其他“混乱”类沿30607倍的图像。
训练整个数据集将花费数小时。因此,我们将处理包含10种动物的数据集的子集-熊,黑猩猩,长颈鹿,大猩猩,美洲驼,鸵鸟,豪猪,臭鼬,三角龙 和 斑马。这样我们可以更快地进行实验。然后,该代码也可以用于训练整个数据集。
这些文件夹中的图像数量从81(臭鼬)到212(大猩猩)不等。我们将每个类别中的前60张图像用于训练。接下来的10张图片用于验证,其余的图片在下面的实验中进行测试。
因此,最终我们有了600张训练图像,100张验证图像,409张测试图像和10类动物。
如果您想复制实验,请按照以下步骤操作
下载 CalTech256 数据集
创建三个目录,名称分别为 train,valid 和 test。
在火车和测试目录中分别创建10个子目录。子目录应命名为 熊,黑猩猩,长颈鹿,大猩猩,美洲驼,鸵鸟,豪猪,臭鼬,三角龙 和 斑马。
将Caltech256数据集中的熊的前60个图像移动到目录train / bear。对每只动物重复此步骤。
将Caltech256数据集中的后10张熊图像移到有效/熊目录。对每只动物重复此步骤。
将熊的其余图像(即火车或有效文件夹中未包含的图像)复制到test / bear目录。对每只动物重复此步骤。
数据扩充
可用多种方式修改可用训练集中的图像,以在训练过程中加入更多变化。这样,训练后的模型将得到更广泛的推广,并在不同种类的测试数据上表现良好。同样,输入数据可以有各种大小。在将一批数据一起用于训练之前,需要将它们标准化为固定的大小和格式。
首先,每个输入图像都要经过许多转换。我们尝试通过在转换中引入一些随机性来插入一些变化。在每个时期,将一组变换应用于每个图像。当我们训练多个时期时,模型可以看到输入图像的更多变化,并且每个时期都有新的随机变化的变换。这将导致数据扩充,然后该模型将尝试进一步推广。
在下面,我们看到了三角恐龙图像转换版本的示例。
三角恐龙图像的变形版本
让我们来看一下我们用于数据扩充的转换。
转换RandomResizedCrop以随机大小(在原始大小的0.8到1.0的缩放范围内以及默认范围0.75到1.33的随机纵横比内)裁剪输入图像。然后将裁剪后的图像调整为256×256。
RandomRotation将图像旋转-15至15度范围内的随机角度。
RandomHorizontalFlip以50%的默认概率随机水平翻转图像。
CenterCrop从中心裁剪出224×224的图像。
ToTensor将值在0-255之间的PIL图像转换为浮点Tensor,并将其除以255,将其规格化为0-1范围。
归一化采用3通道张量,并通过该通道的输入平均值和标准差对每个通道进行归一化。均值和标准差向量作为3个元素向量输入。张量中的每个通道均归一化为T =(T –均值)/(标准差)
上述所有转换都使用Compose链接在一起。
# Applying Transforms to the Dataimage_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)), transforms.RandomRotation(degrees=15), transforms.RandomHorizontalFlip(), transforms.CenterCrop(size=224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'valid': transforms.Compose([ transforms.Resize(size=256), transforms.CenterCrop(size=224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'test': transforms.Compose([ transforms.Resize(size=256), transforms.CenterCrop(size=224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ])}
请注意,对于验证和测试数据,我们不执行RandomResizedCrop,RandomRotation和RandomHorizontalFlip转换。相反,我们只是将验证图像的大小调整为256×256,并裁剪出中心224×224,以便能够将它们与预训练模型一起使用。最后,将图像转换为张量,并通过ImageNet中所有图像的均值和标准差对其进行归一化。
数据载入
接下来,让我们看看如何使用上面定义的转换并加载用于训练的数据。
# Load the Data# Set train and valid directory pathstrain_directory = 'train'valid_directory = 'test'# Batch sizebs = 32# Number of classesnum_classes = 10# Load Data from foldersdata = { 'train': datasets.ImageFolder(root=train_directory, transform=image_transforms['train']), 'valid': datasets.ImageFolder(root=valid_directory, transform=image_transforms['valid']), 'test': datasets.ImageFolder(root=test_directory, transform=image_transforms['test'])}# Size of Data, to be used for calculating Average Loss and Accuracytrain_data_size = len(data['train'])valid_data_size = len(data['valid'])test_data_size = len(data['test'])# Create iterators for the Data loaded using DataLoader moduletrain_data = DataLoader(data['train'], batch_size=bs, shuffle=True)valid_data = DataLoader(data['valid'], batch_size=bs, shuffle=True)test_data = DataLoader(data['test'], batch_size=bs, shuffle=True)# Print the train, validation and test set data sizestrain_data_size, valid_data_size, test_data_size
我们首先设置训练和验证数据目录以及批处理大小。然后我们使用DataLoader加载它们。请注意,我们先前讨论的图像转换是在使用DataLoader加载数据时应用于数据的。数据的顺序也被重新排序。torchvision.transforms包和DataLoader是非常重要的PyTorch功能,这些功能使数据扩充和加载过程非常容易。
迁移学习
收集属于感兴趣域的图像并从头开始训练分类器非常困难且耗时。因此,我们使用预先训练的模型作为基础,并更改最后几层,以便我们可以根据需要的类别对图像进行分类。即使在数据集较小的情况下,这也有助于我们获得良好的结果,因为已经在预训练模型中从较大的数据集(如ImageNet)中学习了基本图像特征。
如上图所示,内层保持与预训练模型相同,仅更改最后层以适合我们的课程数量。在这项工作中,我们使用预先训练的ResNet50模型。
# Load pretrained ResNet50 Modelresnet50 = models.resnet50(pretrained=True)
# Freeze model parametersfor param in resnet50.parameters(): param.requires_grad = False
接下来,我们用一小组顺序层替换ResNet50模型的最后一层。ResNet50的最后一个完全连接层的输入被馈送到线性层。它具有256个输出,然后输出到ReLU和Dropout层。然后是一个256×10线性层,该层具有10个输出,对应于我们的CalTech子集中的10个类别。
# Change the final layer of ResNet50 Model for Transfer Learningfc_inputs = resnet50.fc.in_featuresresnet50.fc = nn.Sequential( nn.Linear(fc_inputs, 256), nn.ReLU(), nn.Dropout(0.4), nn.Linear(256, 10), nn.LogSoftmax(dim=1) # For using NLLLoss())
由于我们将在GPU上进行训练,因此我们可以为GPU准备好模型。
# Convert model to be used on GPUresnet50 = resnet50.to('cuda:0')
接下来,我们定义损失函数和用于训练的优化器。PyTorch提供了多种丢失功能。我们使用负损失可能性函数,因为该函数可用于对多个类别进行分类。PyTorch还支持多个优化器。我们使用亚当优化器。Adam是最受欢迎的优化器之一,因为它可以针对每个参数分别调整学习率。
# Define Optimizer and Loss Functionloss_func = nn.NLLLoss()optimizer = optim.Adam(resnet50.parameters())
训练
完整的培训代码在python笔记本中,但是我们将在此处讨论主要概念。训练针对一组固定的时间段,在单个时间段中处理每个图像一次。训练数据加载器分批加载数据。在我们的示例中,我们给的批次大小为32。这意味着每个批次最多可以包含32张图像。
对于每一批,输入图像都通过模型(也称为正向传递)传递,以获取输出。然后,使用提供的loss_criterion或cost函数使用基本事实和计算出的输出来计算损失。相对于可训练参数的损耗梯度是使用向后函数计算的。请注意,在进行转移学习时,我们只需要为属于模型末尾的几个新添加层的一小部分参数计算梯度。对模型的摘要函数调用可以显示参数的实际数量和可训练参数的数量。此方法的优势在于,现在只需要训练模型参数总数的十分之一即可。
梯度计算使用进行autograd和反向传播,使用链式法则在图形区分。PyTorch会在向后传递中累积所有渐变。因此,必须在训练循环开始时将它们归零。这是使用优化器的zero_grad函数实现的。最后,在向后通过计算梯度之后,使用优化程序的阶跃函数更新参数。
计算整个批次的总损失和准确性,然后对所有批次进行平均,以获取整个时期的损失和准确性值。
for epoch in range(epochs): epoch_start = time.time() print("Epoch: {}/{}".format(epoch+1, epochs)) # Set to training mode model.train() # Loss and Accuracy within the epoch train_loss = 0.0 train_acc = 0.0 valid_loss = 0.0 valid_acc = 0.0 for i, (inputs, labels) in enumerate(train_data_loader): inputs = inputs.to(device) labels = labels.to(device) # Clean existing gradients optimizer.zero_grad() # Forward pass - compute outputs on input data using the model outputs = model(inputs) # Compute loss loss = loss_criterion(outputs, labels) # Backpropagate the gradients loss.backward() # Update the parameters optimizer.step() # Compute the total loss for the batch and add it to train_loss train_loss += loss.item() * inputs.size(0) # Compute the accuracy ret, predictions = torch.max(outputs.data, 1) correct_counts = predictions.eq(labels.data.view_as(predictions)) # Convert correct_counts to float and then compute the mean acc = torch.mean(correct_counts.type(torch.FloatTensor)) # Compute total accuracy in the whole batch and add to train_acc train_acc += acc.item() * inputs.size(0) print("Batch number: {:03d}, Training: Loss: {:.4f}, Accuracy: {:.4f}".format(i, loss.item(), acc.item()))
验证方式
随着训练针对更多时期的进行,该模型倾向于过度拟合数据,从而导致其在新测试数据上的性能较差。维护单独的验证集很重要,因此我们可以在适当的时候停止训练并防止过度拟合。在训练循环后的每个纪元内立即进行验证。由于我们在验证过程中不需要任何梯度计算,因此可以在torch.no_grad()块内完成。
对于每个验证批次,将输入和标签传输到GPU(如果cuda可用,则将它们传输到CPU)。输入经过前向传递,然后是整个时期的批处理和循环结束时的损失和准确性计算。
# Validation - No gradient tracking needed with torch.no_grad(): # Set to evaluation mode model.eval() # Validation loop for j, (inputs, labels) in enumerate(valid_data_loader): inputs = inputs.to(device) labels = labels.to(device) # Forward pass - compute outputs on input data using the model outputs = model(inputs) # Compute loss loss = loss_criterion(outputs, labels) # Compute the total loss for the batch and add it to valid_loss valid_loss += loss.item() * inputs.size(0) # Calculate validation accuracy ret, predictions = torch.max(outputs.data, 1) correct_counts = predictions.eq(labels.data.view_as(predictions)) # Convert correct_counts to float and then compute the mean acc = torch.mean(correct_counts.type(torch.FloatTensor)) # Compute total accuracy in the whole batch and add to valid_acc valid_acc += acc.item() * inputs.size(0) print("Validation Batch number: {:03d}, Validation: Loss: {:.4f}, Accuracy: {:.4f}".format(j, loss.item(), acc.item())) # Find average training loss and training accuracy avg_train_loss = train_loss/train_data_size avg_train_acc = train_acc/float(train_data_size) # Find average training loss and training accuracy avg_valid_loss = valid_loss/valid_data_size avg_valid_acc = valid_acc/float(valid_data_size) history.append([avg_train_loss, avg_valid_loss, avg_train_acc, avg_valid_acc]) epoch_end = time.time() print("Epoch : {:03d}, Training: Loss: {:.4f}, Accuracy: {:.4f}%, \n\t\tValidation : Loss : {:.4f}, Accuracy: {:.4f}%, Time: {:.4f}s".format(epoch, avg_train_loss, avg_train_acc*100, avg_valid_loss, avg_valid_acc*100, epoch_end-epoch_start))
如上图所示,该数据集的验证损失和训练损失都很快下降。精度也非常快地提高到0.9的范围。随着历元数的增加,训练损失会进一步减少,从而导致拟合过度,但是验证结果并不能改善很多。因此,我们从纪元中选择了具有较高准确性和较低损失的模型。最好是我们早点停止,以防止训练数据过度拟合。在我们的案例中,我们选择了epoch#8,其验证准确性为96%。
本月初停止过程也可以自动完成。一旦损失低于给定的阈值,并且对于给定的时期,验证准确性没有提高,我们就可以停止。
推理
一旦有了模型,我们就可以对单个测试图像或整个测试数据集进行推断,以获得测试准确性。测试集准确性计算类似于验证代码,不同之处在于它是在测试数据集上执行的。同样,我们在Python笔记本中包含了函数computeTestSetAccuracy。下面让我们讨论如何查找给定测试图像的输出类。
输入图像首先经过用于验证/测试数据的所有转换。然后将所得张量转换为4维张量,并通过该模型,该模型输出不同类别的对数概率。模型输出的指数为我们提供了类概率。然后选择概率最高的类别作为输出类别。
选择可能性最高的类别作为我们的输出类别。
def predict(model, test_image_name): transform = image_transforms['test'] test_image = Image.open(test_image_name) plt.imshow(test_image) test_image_tensor = transform(test_image) if torch.cuda.is_available(): test_image_tensor = test_image_tensor.view(1, 3, 224, 224).cuda() else: test_image_tensor = test_image_tensor.view(1, 3, 224, 224) with torch.no_grad(): model.eval() # Model outputs log probabilities out = model(test_image_tensor) ps = torch.exp(out) topk, topclass = ps.topk(1, dim=1) print("Output class : ", idx_to_class[topclass.cpu().numpy()[0][0]])
在具有409张图像的测试仪上,达到了92.4%的精度。
以下是一些未在训练或验证中使用的新测试数据的分类结果。图像的最高预测类别及其概率得分覆盖在右上方。如下所示,以最高概率预测的类别通常是正确的类别。还要注意,在所有其余的9个类别中,从外观上看,与实际类别最接近的动物通常是第二位。
我们刚刚看到了如何使用针对1000类ImageNet训练的预训练模型。它非常有效地对属于我们感兴趣的10个不同类别的图像进行了分类。
我们在一个小的数据集上显示了分类结果。在以后的文章中,我们将在较困难的数据集上应用相同的迁移学习方法,以解决较难的现实问题。敬请关注!
机器学习花朵图像分类_在PyTorch中使用转移学习进行图像分类相关推荐
- Pytorch:利用迁移学习做图像分类
**Pytorch:利用迁移学习做图像分类** 数据准备 数据扩充 数据加载 迁移学习 训练 验证 推理/分类 在这一篇文章中,我们描述了如何在 pytorch中进行图像分类.我们将使用Caltech ...
- pytorch图像分类_使用PyTorch和Streamlit创建图像分类Web应用
pytorch图像分类 You just developed a cool ML model. 您刚刚开发了一个很酷的ML模型. You are proud of it. You want to sh ...
- 使用PyTorch中的预训练模型进行图像分类
PyTorch的TorchVision模块中包含多个用于图像分类的预训练模型,TorchVision包由流行的数据集.模型结构和用于计算机视觉的通用图像转换函数组成.一般来讲,如果你进入计算机视觉和使 ...
- 在PyTorch中使用卷积神经网络建立图像分类模型
概述 在PyTorch中构建自己的卷积神经网络(CNN)的实践教程 我们将研究一个图像分类问题--CNN的一个经典和广泛使用的应用 我们将以实用的格式介绍深度学习概念 介绍 我被神经网络的力量和能力所 ...
- gpu处理信号_在PyTorch中使用DistributedDataParallel进行多GPU分布式模型训练
先进的深度学习模型参数正以指数级速度增长:去年的GPT-2有大约7.5亿个参数,今年的GPT-3有1750亿个参数.虽然GPT是一个比较极端的例子但是各种SOTA模型正在推动越来越大的模型进入生产应用 ...
- pytorch深度学习_在本完整课程中学习在PyTorch中应用深度学习
pytorch深度学习 In this complete course from Fawaz Sammani you will learn the key concepts behind deep l ...
- 数据可视化机器学习工具在线_为什么您不能跳过学习数据可视化
数据可视化机器学习工具在线 重点 (Top highlight) There's no scarcity of posts online about 'fancy' data topics like ...
- lstm 输入数据维度_理解Pytorch中LSTM的输入输出参数含义
本文不会介绍LSTM的原理,具体可看如下两篇文章 Understanding LSTM Networks DeepLearning.ai学习笔记(五)序列模型 -- week1 循环序列模型 1.举个 ...
- 机器学习 物理引擎_在太阳物理学中使用机器学习
机器学习 物理引擎 我们如何预测冠状物质抛射? (How Can We Predict Coronal Mass Ejections?) Coronal Mass Ejection (CME) is ...
最新文章
- 文件加解密,文件操作
- 629. K个逆序对数组
- SQL Server数学函数
- digest 用户认证 response生成算法
- 蓝桥杯scratch_又是福州第一!信息学编程竞赛“蓝桥杯”公布福建省赛榜单
- 计算机栏和用户栏有啥区别,任务栏与桌面的区别是
- awk编程基本使用示例
- 苹果Mac矢量图形设计工具:Affinity Designer Beta
- HDU - 2047
- Delphi SWF SDK v1.4 Crack Notes
- 论文句子转换软件v.1.2.3
- hosts文件修改,文件类型修改
- c/c++ utf-8与gbk的互相转化
- java会议室预约系统源码_基于jsp的会议室预订预约-JavaEE实现会议室预订预约 - java项目源码...
- 野火STM32F429学习笔记
- 虚拟存储器的基本概念
- tplink怎么进去_想设置路由器,如何进入tplink
- 入市炒股 不如入淘创业 盘点淘宝十大新职业
- Hadoop-HDFS的数据读写过程(详细过程与图解)
- 如何制作数据可视化网页