基于迁移学习的狗狗分类器

2023-10-14 16:30
文章标签 学习 迁移 分类器 狗狗

本文主要是介绍基于迁移学习的狗狗分类器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达

你以前听说过深度学习这个词吗? 或者你刚刚开始学习它?

在本文中,我将引导您构建自己的狗狗分类器。在这个项目的最后:

  • 您的代码将接受任何用户提供的图像作为输入

  • 如果一只狗在图像中被检测到,它将提供对该狗狗品种的预测

我会让它尽可能的简单~

实现步骤如下:

  • 步骤0:导入数据集

  • 步骤1:图像预处理

  • 步骤2:选择迁移学习的模式

  • 步骤3:更改预训练模型的分类器

  • 步骤4:编写训练算法

  • 步骤5:训练模型

  • 步骤6:测试模型

  • 步骤7:测试你自己的图片

步骤0:导入数据集

你可以从下列网址下载你自己的数据集:https://www.kaggle.com/c/dog-breed-identification

然后解压缩文件!

由于图像处理在本地机器上需要大量的时间和资源,因此我将使用 colab 的 GPU 来训练我的模型。所以,如果你没有自己的 GPU,也可以切换到 colab 来跟进。

导入必要的库始终是一个良好的开始,下面代码展示了我们训练所需要的库。

#Importing Libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image
from PIL import ImageFile
import cv2 # importing Pytorch model libraries
import torch
import torchvision.models as models
import torchvision.transforms as transforms
from torchvision import datasets
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

在下列代码的圆括号的双引号中输入 dog_images 的路径。

dog_files = np.array(glob("/data/dog_images/*/*/*"))
# print number of images in each dataset
print('There are %d total dog images.' % len(dog_files))
Output : There are 8351 total dog images.

步骤1:图像预处理

首先,您需要将训练、验证和测试集数据的目录加载到一些变量中。

#Loading images data into the memory and storing them into the variables
data_dir = '/content/dogImages'
train_dir = data_dir + '/train'
valid_dir = data_dir + '/valid'
test_dir = data_dir + '/test'

然后需要对加载的图像进行一些变换,这就是所谓的数据预处理。

为什么有这个必要?

  • 您的图像必须与网络的输入大小匹配。如果您需要调整图像的大小以匹配网络,那么您可以将数据重新缩放或裁剪到所需的大小

  • 数据增强也使您能够训练网络不受图像数据扭曲的影响。为此,我会随机裁剪和调整图像的大小

  • 数据归一化也是一个重要步骤,确保每个输入参数(本例中为像素)具有类似属性的数据,这使得训练网络时的收敛速度更快

#Applying Data Augmentation and Normalization on images
train_transforms = transforms.Compose([transforms.RandomRotation(30),transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])valid_transforms = transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])test_transforms = transforms.Compose([transforms.Resize(255),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])

将图像存储到数据加载器中

现在我们需要将训练、验证和测试目录加载到数据加载器中。这将使我们能够将数据分成小批量。

我们将数据以key-value的格式进行存储,这将有助于以后调用它们。

# TODO: Load the datasets with ImageFolder
train_data = datasets.ImageFolder(train_dir, transform=train_transforms)
valid_data = datasets.ImageFolder(valid_dir,transform=valid_transforms)
test_data = datasets.ImageFolder(test_dir, transform=test_transforms)# TODO: Using the image datasets and the trainforms, define the dataloaders
trainloader = torch.utils.data.DataLoader(train_data, batch_size=20, shuffle=True)
testloader = torch.utils.data.DataLoader(test_data, batch_size=20,shuffle=False)
validloader = torch.utils.data.DataLoader(valid_data, batch_size=20,shuffle=False)
loaders_transfer = {'train':trainloader,'valid':validloader,'test':testloader}
data_transfer = {'train':trainloader
}

步骤2:选择迁移学习的模式

什么是预训练模型,我们为什么要使用它?

预训练模型是别人为解决类似问题而创建的模型。

  • 与其从零开始构建模型来解决类似的问题,不如使用经过其他问题训练的模型作为起点

  • 一个预训练模型在应用程序中可能不是100% 准确,但是它节省了重新发明轮子所需的巨大努力

  • 迁移学习可以利用在一个问题上学到的特性,并在一个新的、类似的问题上利用它们。例如,一个已经学会识别小浣熊的模型的特征可能有助于开始训练一个用于识别猫咪的模型

你可以选择几个事先训练过的模特进行模特训练。例如 Densenet,Resnet,VGG 模型。我将使用 VGG-16进行模型训练。

#Loading vgg11 into the variable model_transfer
model_transfer = models.vgg11(pretrained=True)

步骤3:更改预训练模型的分类器

将采取以下步骤来改变预训练分类器:

  1. 从以前训练过的模型中取出网络层

  2. 冻结它们,以避免在以后的训练回合中破坏它们所包含的任何信息

  3. 在冻结层上添加一些新的、可训练的图层。他们将学习在新的数据集上将旧的特性转化为预测

  4. 在你的数据集上训练新的网络层

由于特征已经学会了预训练的模型,所以将冻结他们在训练期间对狗狗的形象。我们只会改变分类器的尺寸,只会训练它。

原来的分类器层有25088个维度,但是为了匹配我们的预处理图像大小,我们需要更改为4096。

要在 GPU 上训练模型,我们需要使用以下命令将其移动到 GPU-RAM 上。

#Freezing the parameters
for param in model_transfer.features.parameters():param.requires_grad = False#Changing the classifier layer
model_transfer.classifier[6] = nn.Linear(4096,133,bias=True)#Moving the model to GPU-RAM space
if use_cuda:model_transfer = model_transfer.cuda()
print(model_transfer)

现在我们需要选择一个损失函数和优化器。

利用损失函数计算模型预测值与实际图像的误差。如果你的预测完全错误,你的损失函数将输出更高的数字。如果它们非常好,那么输出的数字就会更低。本文将使用交叉熵损失。

优化器是用来改变神经网络属性的算法或方法,比如权重和学习速度,以减少损失。本文将使用 SGD 优化器。

0.001的学习率对于训练是有好处的,但是你也可以用其他的学习率进行实验。鼓励大家多多尝试不同的参数~

### Loading the Loss-Function
criterion_transfer = nn.CrossEntropyLoss()### Loading the optimizer
optimizer_transfer = optim.SGD(model_transfer.parameters(), lr=0.001, momentum=0.9)

步骤4:编写训练算法

接下来我们将编写训练函数。

我用它编写了验证代码行。所以在训练模型时,我们会同时得到两种损失。

每次Loss减少时,我也会存储这个模型。这样我就不必在以后每次打开一个新实例时都要训练它。

def train(n_epochs, loaders, model, optimizer, criterion, use_cuda, save_path):"""returns trained model"""# initialize tracker for minimum validation lossvalid_loss_min = np.inf   #--->   Max Value (As the loss decreases and becomes less than this value it gets saved)for epoch in range(1, n_epochs+1):#Initializing training variablestrain_loss = 0.0valid_loss = 0.0# Start training the modelmodel.train()for batch_idx, (data, target) in enumerate(loaders['train']):# move to GPU's memory space (if available)if use_cuda:data, target = data.cuda(), target.cuda()model.to('cuda')optimizer.zero_grad()output = model(data)loss = criterion(output,target)loss.backward()optimizer.step()train_loss = train_loss + ((1 / (batch_idx + 1)) * (loss.data - train_loss)) # validate the model #model.eval()for batch_idx, (data, target) in enumerate(loaders['valid']):accuracy=0# move to GPU's memory space (if available)if use_cuda:data, target = data.cuda(), target.cuda()## Update the validation losslogps = model(data)loss = criterion(logps, target)valid_loss += ((1 / (batch_idx + 1)) * (loss.data - valid_loss))# print both training and validation lossesprint('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(epoch, train_loss,valid_loss))if valid_loss <= valid_loss_min:print('Validation loss decreased ({:.6f} --> {:.6f}).  Saving model ...'.format(valid_loss_min,valid_loss))#Saving the modeltorch.save(model.state_dict(), 'model_transfer.pt')valid_loss_min = valid_loss# return the trained modelreturn model

步骤5:训练模型

现在,我将开始通过在函数中提供参数来训练模型。我将训练10个epoch。

# train the model
model_transfer = train(10, loaders_transfer, model_transfer, optimizer_transfer, criterion_transfer, use_cuda, 'model_transfer.pt')# load the model that got the best validation accuracy
model_transfer.load_state_dict(torch.load('model_transfer.pt'))
OUTPUT:Epoch: 1   Training Loss: 2.443815   Validation Loss: 0.801671
Validation loss decreased (inf --> 0.801671).  Saving model ...
Epoch: 2   Training Loss: 1.440627   Validation Loss: 0.591050
Validation loss decreased (0.801671 --> 0.591050).  Saving model ...
Epoch: 3   Training Loss: 1.310158   Validation Loss: 0.560950
Validation loss decreased (0.591050 --> 0.560950).  Saving model ...
Epoch: 4   Training Loss: 1.200572   Validation Loss: 0.566340
Epoch: 5   Training Loss: 1.160727   Validation Loss: 0.530196
Validation loss decreased (0.560950 --> 0.530196).  Saving model ...
Epoch: 6   Training Loss: 1.088659   Validation Loss: 0.560774
Epoch: 7   Training Loss: 1.060936   Validation Loss: 0.503829
Validation loss decreased (0.530196 --> 0.503829).  Saving model ...
Epoch: 8   Training Loss: 1.010044   Validation Loss: 0.500608
Validation loss decreased (0.503829 --> 0.500608).  Saving model ...
Epoch: 9   Training Loss: 1.054875   Validation Loss: 0.497319
Validation loss decreased (0.500608 --> 0.497319).  Saving model ...
Epoch: 10   Training Loss: 1.000547   Validation Loss: 0.545735<All keys matched successfully>

步骤6:测试模型

现在我将在模型以前从未见过的新图像上测试模型,并计算预测的准确性。

def test(loaders, model, criterion, use_cuda):# Initializing the variablestest_loss = 0.correct = 0.total = 0.model.eval()  #So that it doesn't change the model parameters during testingfor batch_idx, (data, target) in enumerate(loaders['test']):# move to GPU's memory spave if availableif use_cuda:data, target = data.cuda(), target.cuda()# Passing the data to the model (Forward Pass)output = model(data)loss = criterion(output, target)   #Test Losstest_loss = test_loss + ((1 / (batch_idx + 1)) * (loss.data - test_loss))# Output probabilities to the predicted classpred = output.data.max(1, keepdim=True)[1]# Comparing the predicted class to outputcorrect += np.sum(np.squeeze(pred.eq(target.data.view_as(pred))).cpu().numpy())total += data.size(0)print('Test Loss: {:.6f}\n'.format(test_loss))print('\nTest Accuracy: %2d%% (%2d/%2d)' % (100. * correct / total, correct, total))
test(loaders_transfer, model_transfer, criterion_transfer, use_cuda)

我已经训练了它10个 epoch,得到了83% 的准确率。并且,得到以下输出!

Output:
Test Loss: 0.542430 Test Accuracy: 83% (700/836)

如何提高这个模型的准确性?

  • 通过训练更多的 epoch(比较训练和验证损失)

  • 通过改变学习率(比如0.01,0.05,0.1)

  • 通过改变预训练模型(像稠密网络,但需要更多的训练时间)

  • 通过对图像的进一步预处理

步骤7:测试你自己的图片

现在你已经训练和测试了你的模型。现在,这是最令人兴奋的部分。你能走到这一步真是太好了。

1.将要测试和保存的新图像加载到内存中

#Loading the new image directory
dog_files_short = np.array(glob("/content/my_dogs/*"))
#Loading the model
model_transfer.load_state_dict(torch.load('model_transfer.pt'))

2. 现在我们必须对图像进行预处理,并通过测试我们训练好的模型来预测类

def predict_breed_transfer(img_path):#Preprocessing the input imagetransform = transforms.Compose([transforms.Resize(255),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])img = Image.open(img_path)img = transform(img)[:3,:,:].unsqueeze(0)if use_cuda:img = img.cuda()model_transfer.to('cuda')# Passing throught the modelmodel_transfer.eval()# Checking the name of class by passing the indexclass_names = [item[4:].replace("_", " ") for item in data_transfer['train'].dataset.classes]idx = torch.argmax(model_transfer(img))return class_names[idx]output = model_transfer(img)# Probabilities to classpred = output.data.max(1, keepdim=True)[1]return pred

3. 现在,通过将图像路径作为参数传递给这个函数,我们可以预测狗狗的品种。

我已经传递了下面的图像,并得到了下列输出。

Output:
Norwegian buhund

总结

这只是一个开始,你可以用这个模型做更多的事情。你可以通过部署它来创建一个应用程序。我尝试从零开始创建自己的模型,没有使用迁移学习,但测试的准确率不超过13% 。你也可以尝试一下,因为这有助于理解概念。

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目31讲

在「小白学视觉」公众号后台回复:Python视觉实战项目31讲即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲

在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

下载4:leetcode算法开源书

在「小白学视觉」公众号后台回复:leetcode即可下载。每题都 runtime beats 100% 的开源好书,你值得拥有!


交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

这篇关于基于迁移学习的狗狗分类器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/qq_42722197/article/details/112914822
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/211723

相关文章

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert