深度学习实战基础案例——卷积神经网络(CNN)基于Xception的猫狗识别|第2例

文章目录

  • 一、环境准备
  • 二、数据预处理
  • 三、构建模型
  • 四、实例化模型
  • 五、训练模型
      • 5.1 构建训练函数
      • 5.2 构建测试函数
      • 5.3 开始正式训练
  • 六、可视化精度和损失
  • 七、个体预测
  • 总结

今天使用轻量级的一个网络Xception做一个简单的猫狗识别案例,我的环境具体如下:

  • pytorch:2.0
  • python:3.8
  • jupyter notebook

一、环境准备

import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision
from torchvision import transforms, datasets
import os,PIL,pathlib,warningswarnings.filterwarnings("ignore")             #忽略警告信息device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device# 输出
device(type='cuda')

二、数据预处理

读取数据:

import os,PIL,random,pathlibdata_dir = 'dataset/'
data_dir = pathlib.Path(data_dir)data_paths  = list(data_dir.glob('*'))
classeNames = [str(path).split("\\")[1] for path in data_paths]
classeNames# 输出
['cat', 'dog']

数据处理

# 关于transforms.Compose的更多介绍可以参考:https://blog.csdn.net/qq_38251616/article/details/124878863
train_transforms = transforms.Compose([transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸# transforms.RandomHorizontalFlip(), # 随机水平翻转transforms.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间transforms.Normalize(           # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
])test_transform = transforms.Compose([transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸transforms.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间transforms.Normalize(           # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
])total_data = datasets.ImageFolder(data_dir,transform=train_transforms)
total_data

在这里插入图片描述
将数据集进行分类

total_data.class_to_idx# 输出
{'cat': 0, 'dog': 1}

划分数据集

train_size = int(0.8 * len(total_data))
test_size  = len(total_data) - train_size
train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])
train_dataset, test_dataset

数据集加载

batch_size = 4train_dl = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size,shuffle=True)
test_dl = torch.utils.data.DataLoader(test_dataset,batch_size=batch_size,shuffle=True)

查看数据集形状

for X, y in test_dl:print("Shape of X [N, C, H, W]: ", X.shape)print("Shape of y: ", y.shape, y.dtype)break

在这里插入图片描述

三、构建模型

Xception的具体网络结构如下所示:
在这里插入图片描述

import math
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.model_zoo as model_zoo
from torch.nn import init
import torchclass SeparableConv2d(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False):super(SeparableConv2d, self).__init__()self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size, stride, padding, dilation, groups=in_channels,bias=bias)self.pointwise = nn.Conv2d(in_channels, out_channels, 1, 1, 0, 1, 1, bias=bias)def forward(self, x):x = self.conv1(x)x = self.pointwise(x)return xclass Block(nn.Module):def __init__(self, in_filters, out_filters, reps, strides=1, start_with_relu=True, grow_first=True):# :parm reps:块重复次数super(Block, self).__init__()# Middle flow无需做这一步,而其余块需要,以做跳连# 1)Middle flow输入输出特征图个数始终一致,且Stride恒为1# 1)其余快stride=2,这样可以将特征图尺寸减半,获得与最大池化减半特征图尺寸同样的效果if out_filters != in_filters or strides != 1:self.skip = nn.Conv2d(in_filters, out_filters, 1, stride=strides, bias=False)self.skipbn = nn.BatchNorm2d(out_filters)else:self.skip = Noneself.relu = nn.ReLU(inplace=True)rep = []filters = in_filtersif grow_first:rep.append(self.relu)# 这里的卷积不改变特征图尺寸rep.append(SeparableConv2d(in_filters, out_filters, 3, stride=1, padding=1, bias=False))rep.append(nn.BatchNorm2d(out_filters))filters = out_filtersfor i in range(reps - 1):rep.append(self.relu)rep.append(SeparableConv2d(filters, filters, 3, stride=1, padding=1, bias=False))rep.append(nn.BatchNorm2d(filters))if not grow_first:rep.append(self.relu)rep.append(SeparableConv2d(in_filters, out_filters, 3, stride=1, padding=1, bias=False))rep.append(nn.BatchNorm2d(out_filters))if not start_with_relu:rep = rep[1:]else:rep[0] = nn.ReLU(inplace=False)# Middle flow 的stride恒为1,因此无需做池化,而其余块需要# 其余块的stride=2,因此这里的最大池化可以将特征图尺寸减半if strides != 1:rep.append(nn.MaxPool2d(3, strides, 1))self.rep = nn.Sequential(*rep)def forward(self, inp):x = self.rep(inp)if self.skip is not None:skip = self.skip(inp)skip = self.skipbn(skip)else:skip = inpx += skipreturn xclass Xception(nn.Module):def __init__(self, num_classes):super(Xception, self).__init__()self.num_classes = num_classes # 总分类数###############################定义 Entry flow#################################self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=0, bias=False)self.bn1 = nn.BatchNorm2d(32)self.relu = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=0, bias=False)self.bn2 = nn.BatchNorm2d(64)# do relu here# Block中的参数顺序:in_filters,out_filters,reps,stride,start_with_relu,grow_firstself.block1 = Block(64, 128, 2, 2, start_with_relu=False, grow_first=True)self.block2 = Block(128, 256, 2, 2, start_with_relu=True, grow_first=True)self.block3 = Block(256, 728, 2, 2, start_with_relu=True, grow_first=True)##############################定义 Middle flow################################self.block4 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)self.block5 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)self.block6 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)self.block7 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)self.block8 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)self.block9 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)self.block10 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)self.block11 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)#############################定义 Exit flow###################################self.block12 = Block(728, 1024, 2, 2, start_with_relu=True, grow_first=False)self.conv3 = SeparableConv2d(1024, 1536, 3, 1, 1)self.bn3 = nn.BatchNorm2d(1536)# do relu hereself.conv4 = SeparableConv2d(1536, 2048, 3, 1, 1)self.bn4 = nn.BatchNorm2d(2048)self.fc = nn.Linear(2048, num_classes)################################################################################--------------------init weights---------------------#for m in self.modules():if isinstance(m, nn.Conv2d):n = m.kernel_size[0] * m.kernel_size[1] * m.out_channelsm.weight.data.normal_(0, math.sqrt(2. / n))elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()#----------------------------------------------------------------def forward(self, x):###########################定义 Entry flow ######################################x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.conv2(x)x = self.bn2(x)x = self.relu(x)x = self.block1(x)x = self.block2(x)x = self.block3(x)######################## 定义 Middle flow#######################################x = self.block4(x)x = self.block5(x)x = self.block6(x)x = self.block7(x)x = self.block8(x)x = self.block9(x)x = self.block10(x)x = self.block11(x)######################### 定义 Exit flow #######################################x = self.block12(x)x = self.conv3(x)x = self.bn3(x)x = self.relu(x)x = self.conv4(x)x = self.bn4(x)x = self.relu(x)x = F.adaptive_avg_pool2d(x, (1,1))x = x.view(x.size(0), -1)x = self.fc(x)return x

四、实例化模型

device = "cuda:0" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))xception = Xception(num_classes = 2)
model = xception.to(device)
model

在这里插入图片描述

五、训练模型

5.1 构建训练函数

# 训练循环
def train(dataloader, model, loss_fn, optimizer):size = len(dataloader.dataset)  # 训练集的大小num_batches = len(dataloader)   # 批次数目, (size/batch_size,向上取整)train_loss, train_acc = 0, 0  # 初始化训练损失和正确率for X, y in dataloader:  # 获取图片及其标签X, y = X.to(device), y.to(device)# 计算预测误差pred = model(X)          # 网络输出loss = loss_fn(pred, y)  # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失# 反向传播optimizer.zero_grad()  # grad属性归零loss.backward()        # 反向传播optimizer.step()       # 每一步自动更新# 记录acc与losstrain_acc  += (pred.argmax(1) == y).type(torch.float).sum().item()train_loss += loss.item()train_acc  /= sizetrain_loss /= num_batchesreturn train_acc, train_loss

5.2 构建测试函数

def test (dataloader, model, loss_fn):size        = len(dataloader.dataset)  # 测试集的大小num_batches = len(dataloader)          # 批次数目, (size/batch_size,向上取整)test_loss, test_acc = 0, 0# 当不进行训练时,停止梯度更新,节省计算内存消耗with torch.no_grad():for imgs, target in dataloader:imgs, target = imgs.to(device), target.to(device)# 计算losstarget_pred = model(imgs)loss        = loss_fn(target_pred, target)test_loss += loss.item()test_acc  += (target_pred.argmax(1) == target).type(torch.float).sum().item()test_acc  /= sizetest_loss /= num_batchesreturn test_acc, test_loss

5.3 开始正式训练

import copyoptimizer  = torch.optim.Adam(model.parameters(), lr= 1e-3)
loss_fn    = nn.CrossEntropyLoss() # 创建损失函数epochs     = 5train_loss = []
train_acc  = []
test_loss  = []
test_acc   = []best_acc = 0    # 设置一个最佳准确率,作为最佳模型的判别指标for epoch in range(epochs):model.train()epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, optimizer)model.eval()epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)# 保存最佳模型到 best_modelif epoch_test_acc > best_acc:best_acc   = epoch_test_accbest_model = copy.deepcopy(model)train_acc.append(epoch_train_acc)train_loss.append(epoch_train_loss)test_acc.append(epoch_test_acc)test_loss.append(epoch_test_loss)# 获取当前的学习率lr = optimizer.state_dict()['param_groups'][0]['lr']template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}')print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss,epoch_test_acc*100, epoch_test_loss, lr))# 保存最佳模型到文件中
PATH = './best_model.pth'  # 保存的参数文件名
torch.save(best_model.state_dict(), PATH)print('Done')

六、可视化精度和损失

import matplotlib.pyplot as plt
#隐藏警告
import warnings
warnings.filterwarnings("ignore")               #忽略警告信息
plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False      # 用来正常显示负号
plt.rcParams['figure.dpi']         = 100        #分辨率epochs_range = range(epochs)plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

在这里插入图片描述

七、个体预测

随便去网上找一张猫狗图片,进行预测。
在这里插入图片描述

# 预测import matplotlib.pyplot as plt
from PIL import Image
from torchvision.transforms import transforms
import torch
import matplotlib.pyplot as pltplt.rcParams['font.sans-serif']=['SimHei']  #解决中文显示乱码问题
plt.rcParams['axes.unicode_minus']=False  #解决坐标轴负数的负号显示问题data_transform = transforms.Compose([transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸transforms.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间transforms.Normalize(           # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
])img = Image.open("cat.jpg")
plt.imshow(img)
img = data_transform(img)
img = torch.unsqueeze(img, dim=0)
name=['狗','猫']
model_weight_path = "best_model.pth"
model = Xception(num_classes = 2)
model.load_state_dict(torch.load(model_weight_path))
model.eval()
with torch.no_grad():output = torch.squeeze(model(img))predict = torch.softmax(output, dim=0)# 获得最大可能性索引predict_cla = torch.argmax(predict).numpy()print('索引为', predict_cla)
print('预测结果为:{},置信度为: {}'.format(name[predict_cla], predict[predict_cla].item()))
plt.show()

在这里插入图片描述

总结

  • Xception(又称为 Extreme Inception)是一种卷积神经网络架构,在 2016 年由 Google 提出,它的名字是由 ‘Extreme’ 和 ‘Inception’ 两个词汇组成的。Xception 基于 Inception V3 模型基础进行改进,使用深度可分离卷积来代替传统的卷积,从而更加有效地减少了模型的参数数量和计算复杂度。
  • 在传统的 Inception 模型中,每个计算单元采用了两个卷积层,一个 1x1 的卷积层用于降低特征图的通道数,紧接着是一个 3x3 的卷积层用于进行特征提取。而 Xception 则将 1x1 和 3x3 卷积逐次分开,使用了深度可分离卷积作为基本的计算单元。深度可分离卷积将标准卷积分解为两部分,首先使用深度卷积来处理每个输入通道,然后再使用 1x1 的逐点卷积来融合通道,从而获得与标准卷积近似的特征提取效果。而深度可分离卷积相较于标准卷积而言,可以明显降低参数量和训练计算量。
  • 而使用深度可分离卷积单元取代了传统的卷积操作之后,Xception模型在计算效率,模型大小上都相比 Inception V3 有大幅的提升。
  • 总之,Xception模型的优势是在极大的减少了网络参数量和计算复杂度的同时,可以保持卓越的性能表现。因此,Xception模型已经被广泛地应用与图像分类、目标检测等任务中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/140223.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记一次STM32F4 HAL IAP开发过程踩坑

第一次在HAL库上做IAP,不太熟悉库结构,被坑了一早上… MCU上做了一个shell,实现了goto命令跳转到APP区执行(只是为了开发时方便)。跳转到APP前和以前一样清理了所有初始化过的外设,也对中断进行了处理&…

MySQL数据库的索引和事务

目录 一、索引 1.1Mysql索引 1.2索引的作用 1.3 创建索引的依据 1.4 普通索引 修改表方式创建索引 删除索引 1.5 唯一索引 修改表方式创建 删除索引 1.6 主键索引 修改表方式创建 1.7 组合索引 1.8 全文索引 1.9查看索引 二、事务 2.1事务概念 2.2事务的ACID特…

rocketmq-spring-boot-starter 2.1.0 事务消息移除参数txProducerGroup

statrer引入 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.2.3</version></dependency> starter 2.0.2对应rocketmq 4.4.0 starter 2.1.0对应rocke…

NSDT 3D孪生场景搭建:阵列摆放详解

阵列摆放概念 阵列摆放是指将物体、设备或元件按照一定的规则和间距排列组合的方式。在工程和科学领域中&#xff0c;阵列式摆放常常用于优化空间利用、提高效率或增强性能。 阵列摆放通常需要考虑间距、角度、方向、对称性等因素&#xff0c;以满足特定的要求和设计目标。不同…

Seata流程源码梳理下篇-TC

我们上篇简单梳理了下TM、RM的一些流程&#xff08;离现在过得挺久的了&#xff0c;这篇我们这篇来梳理下TC的内容。 TC (Transaction Coordinator) - 事务协调者 维护全局和分支事务的状态&#xff0c;驱动全局事务提交或回滚。 TM (Transaction Manager) - 事务管理器 定…

C++ Primer 第5章 语句

C Primer 第5章 语句 5.1 简单语句一、空语句二、别漏写分号&#xff0c;也别多写分号三、复合语句&#xff08;块&#xff09; 5.2 语句作用域5.3 条件语句5.3.1 if语句一、使用if else语句二、嵌套if语句三、注意使用花括号四、悬垂else五、使用花括号控制执行路径 5.3.2 swi…

Oracle分区的使用详解:创建、修改和删除分区,处理分区已满或不存在的插入数据,以及分区历史数据与近期数据的操作指南

一、前言 什么是表分区: Oracle的分区是一种将表或索引数据分割为更小、更易管理的部分的技术。它可以提高查询性能、简化维护操作,并提供更好的数据组织和管理。 表分区和表空间的区别和联系: 在Oracle数据库中,表空间(Tablespace)是用于存储表、索引和其他数据库对…

Baichuan2 技术报告笔记

文章目录 预训练预训练数据模型架构TokenizerPositional EmbeddingsAcitivations and NormalizationsOptimizations 对齐Supervised Fine-TuningRLHF 安全性预训练阶段对齐阶段 参考资料 对Baichuan2技术报告阅读后的笔记 Baichuan2 与其他大模型的对比如下表 预训练 预训练数…

【Java开发】Redis位图实现统计日活周活月活

最近研究了使用 Redis 的位图功能统计日活周活等数据&#xff0c;特来和大家分享下&#xff0c;Redis 位图还可用于记录用户签到情况、判断某个元素是否存在于集合中等。 1 Redis 位图介绍 Redis 位图是一种特殊的数据结构&#xff0c;它由一系列位组成&#xff0c;每个位只能…

洛谷P8815:逻辑表达式 ← CSP-J 2022 复赛第3题

【题目来源】https://www.luogu.com.cn/problem/P8815https://www.acwing.com/problem/content/4733/【题目描述】 逻辑表达式是计算机科学中的重要概念和工具&#xff0c;包含逻辑值、逻辑运算、逻辑运算优先级等内容。 在一个逻辑表达式中&#xff0c;元素的值只有两种可能&a…

Appilot发布:打造面向DevOps场景的开源AI助手

今日&#xff0c;数澈软件Seal &#xff08;以下简称“Seal”&#xff09;宣布推出面向 DevOps 场景的 AI 助手 Appilot&#xff0c;这款产品将充分利用 AI 大语言模型的能力为用户提供变革性的部署和应用管理体验。Seal 此次发布的 Appilot 项目&#xff0c;可以让用户直接输入…

leetcode 22. 括号生成

2023.9.24 看到组合两个字&#xff0c;想到了回溯。 大致思路是将所有可能的组合列出来&#xff0c;通过中止条件筛选掉无效的括号。 第一个中止条件&#xff1a;如果右括号数量大于左括号&#xff0c;那括号肯定无效。 第二个中止条件&#xff1a;当左右括号数量相等&#x…

古代有没有电子元器件?

手机&#xff0c;电脑&#xff0c;电视等等电子产品&#xff0c;无时无刻充斥在我们的生活中&#xff0c;如果有一天突然没有了这些功能多样的电子产品&#xff0c;估计大部分人都会一时之间难以适应。 这就好比正在上网&#xff0c;结果突然被人断了网&#xff0c;导致无网络连…

Go语言入门篇

目录 一、基础数据类型 1.1 变量的定义方式 1.2 用%T输出变量的类型 二、复合数据类型 2.1 数组 2.1.2、数组的遍历 2.1.3 数组传参 2.2. 切片slice 2.2.1. 初始化切片 2.2.2. append向切片中追加元素 2.2.3. 切片的截取 2.3. map 2.3.1. map初始化 2.3.2. 添加和…

操作系统权限提升(三十)之数据库提权-SQL Server sp_oacreate+sp_oamethod(dba权限)提权

SQL Server sp_oacreate+sp_oamethod(dba权限)提权 sp_oacreate+sp_oamethod介绍 在xp_cmdshell被删除或不能利用是可以考虑利用sp_oacreate,利用前提需要sqlserver sysadmin账户服务器权限为system(sqlserver2019默认被降权为mssql)。sp_oacreate 是一个存储过程,可以…

【无标题】mysql 普通用户连接报错: MySql server has gone away

1、mysql 普通用户连接报错&#xff1a; MySql server has gone away 2、进入mysql错误日志位置查看输出日志显示错误为&#xff1a; [Warning] [MY-013130] [Server] Aborted connection 47 to db: unconnected user: tjcx host: 10.195.11.4 (init_connect command failed; …

基于docker进行Grafana + prometheus实现服务监听

基于docker进行Grafana Prometheus实现服务监听 Grafana安装Prometheus安装Jvm监控配置服务器主机监控(基础cpu&#xff0c;内存&#xff0c;磁盘&#xff0c;网络) Grafana安装 docker pull grafana/grafanamkdir /server/grafanachmod 777 /server/grafanadocker run -d -p…

汽车OTA

汽车OTA&#xff08;Over-The-Air&#xff09;技术是指通过无线网络对汽车进行软件升级、数据传输和远程诊断等功能的技术。随着汽车行业的数字化和智能化发展&#xff0c;OTA技术在汽车领域的应用越来越广泛&#xff0c;对于提高汽车性能、降低维修成本和提升用户体验具有重要…

Linux(ubuntu)系统更新后不能进入图形界面

最近需要跑一个深度学习的程序&#xff0c;把许久没用的ubuntu系统调了出来&#xff0c;手欠的我更新了一下系统&#xff0c;结果再启动&#xff0c;系统就只停留在光标闪动那里&#xff0c;不能看到图形界面了。网上查了一下&#xff0c;说是因为更新后&#xff0c;显卡驱动没…

Scrapy+Selenium自动化获取个人CSDN文章质量分

前言 本文将介绍如何使用Scrapy和Selenium这两个强大的Python工具来自动获取个人CSDN文章的质量分数。我们将详细讨论Scrapy爬虫框架的使用&#xff0c;以及如何结合Selenium浏览器自动化工具来实现这一目标。无需手动浏览每篇文章&#xff0c;我们可以轻松地获取并记录文章的…