使用YOLOv5-C3模块识别图像天气 - P8

news2024/11/18 11:17:31
  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊 | 接辅导、项目定制
  • 🚀 文章来源:K同学的学习圈子

目录

  • 环境
  • 步骤
    • 环境设置
      • 引用包
      • 全局设备对象
    • 数据准备
      • 数据集信息收集
      • 图像预处理
      • 读取数据集
      • 读取数据集分类
      • 划分出训练集和测试集
      • 将数据划分为批次
    • 模型设计
      • 用于计算same卷积下padding的数值
      • 编写C3模型中基本的卷积块
      • 编写C3模型中基本的bottleneck块
      • 编写C3模块
      • 编写本任务的模型
    • 模型训练
      • 编写训练函数
      • 定义训练参数
      • 开始训练
    • 模型效果展示
      • 打印训练折线图
      • 加载最佳模型进行预测
  • 总结与思考


环境

  • 系统: Linux
  • 语言: Python3.8.10
  • 深度学习框架: Pytorch2.0.0+cu118

步骤

环境设置

引用包

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

from torch.utils.data import DataLoader, random_split
from torchvision import datasets, transforms

import random, pathlib, copy
from PIL import Image

import matplotlib.pyplot as plt
from torchinfo import summary
import numpy as np

全局设备对象

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

数据准备

数据集信息收集

data_path = 'weather_photos'

image_list = list(pathlib.Path(data_path).glob('*/*'))

# 打印一下图像的大小
for _ in range(5):
	path = random.choice(image_list)
	print(np.array(Image.open(str(path))).shape)

# 打印一下图像的内容
plt.figure(figsize=(20, 4))
for i in range(20):
	plt.subplot(2, 10, i+1)
	image = random.choice(image_list)
	label = image.parts[-2]
	path = str(image)
	
	plt.imshow(Image.open(path))
	plt.axis('off')
	plt.title(label)
plt.show()

图像大小
预览数据集中的图像

图像预处理

通过上面对图像初步的观察,图像的尺寸不一致,需要做一下缩放操作,弄成相同的尺寸

transform = transforms.Compose([
	transforms.Resize([224, 224]), # 缩放到224x224
	transforms.ToTensor(),
	transforms.Normalize(
		mean=[0.485, 0.456, 0.406],
		std=[0.229, 0.224, 0.225]
	)
])

读取数据集

dataset = datasets.ImageFolder(data_path, transform=transform)

读取数据集分类

class_names = [k for k in dataset.class_to_idx]
print(class_names)

图像的类型

划分出训练集和测试集

train_size = int(len(dataset) * 0.8)
test_size = len(dataset) - train_size

train_dataset, test_dataset = random_split(dataset, [train_size, test_size])

将数据划分为批次

batch_size = 32
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)
test_loader = DataLoader(test_dataset, batch_size=batch_size)

模型设计

用于计算same卷积下padding的数值

# 个人理解padding只和kernel_size有关,可是pytorch传入了stride就不能直接将padding设置为'same'了,因此需要一个方法计算padding的值
def same_padding(k, p=None):
	if p is None:
		p = k//2 if isinstance(k, int) else [ x//2 for x in k]
	return p

编写C3模型中基本的卷积块

class Conv(nn.Module):
	def __init__(self, in_size, out_size, kernel_size, stride=1, padding=None, groups=1, act=True):
		super().__init__()

		self.conv = nn.Conv2d(in_size, out_size, kernel_size, stride, padding=same_padding(kernel_size, padding), bias=False)
		self.bn = nn.BatchNorm2d(out_size)
		self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
	
	def forward(self, x):
		x = self.act(self.bn(self.conv(x)))
		return x

编写C3模型中基本的bottleneck块

class Bottleneck(nn.Module):
	def __init__(self, in_size, out_size, shortcut=True, groups=1, expansion=0.5):
		super().__int__()

		hidden_size = int(out_size * expansion)
		self.conv1 = Conv(in_size, hidden_size, 1)
		self.conv2 = Conv(hidden_size, out_size, 3, groups=groups)
		self.add = shortcut and in_size == out_size

	def forward(self, x):
		x = x + self.conv2(self.conv1(x)) if self.add else self.conv2(self.conv1(x))
		return x

编写C3模块

class C3(nn.Module):
    def __init__(self, in_size, out_size, neck_size=1, groups=1, expansion=0.5):
        super().__init__()
        
        hidden_size = int(expansion * out_size)
        
        self.conv1 = Conv(in_size, hidden_size, kernel_size=1)
        self.conv2 = Conv(in_size, hidden_size, kernel_size=1)
        self.conv3 = Conv(2*hidden_size, out_size, kernel_size=1)
        
        self.bottleneck = nn.Sequential(*(BottleNeck(hidden_size, hidden_size) for _ in range(neck_size)))
        
    def forward(self, x):
        x = self.conv3(torch.cat((self.conv2(x), self.bottleneck(self.conv1(x))), dim=1))
        return x

编写本任务的模型

class Network(nn.Module):
	def __init__(self, num_classes):
		super().__init__()

		# channel:3 -> channel:32,kernel_size = 3, 
		self.conv1 = Conv(3, 32, 3, 2)
		self.c3_1 = C3(32, 64, 3)
		self.classifier = nn.Sequential(
			nn.Linear(802816, 100),
			nn.ReLU(),
			nn.Linear(100, num_classes)
		)

	def forward(self, x):
		x = self.conv1(x)
		x = self.c3_1(x)
		x = x.view(x.size(0), -1)
		x = slef.classifier(x)
		return x
model = Network(len(class_names)).to(device)
summary(model, input_size=(32, 3, 224, 224))
print(model)

打印模型参数
打开模型结构

模型训练

编写训练函数

def train(train_loader, model, loss_fn, optimizer):
	size = len(train_loader.dataset)
	num_batches = len(train_loader)
	
	train_loss, train_acc = 0, 0
	for x, y in train_loader:
		x, y = x.to(device), y.to(device)
		
		pred = model(x)
		loss = loss_fn(pred, y)

		optimizer.zero_grad()
		loss.backward()
		optimizer.step()

		train_loss += loss.item()
		train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()

	train_loss /= num_batches
	train_acc /= size
	
	return train_loss, train_acc

def test(test_loader, model, loss_fn):
	size = len(test_loader.dataset)
	num_batches = len(test_loader)
	
	test_loss, test_acc = 0, 0
	for x, y in test_loader:
		x, y = x.to(device), y.to(device)

		pred = model(x)
		loss = loss_fn(pred, y)

		test_loss += loss.item()
		test_acc += (pred.argmax(1) == y).type(torch.float).sum().item()

	test_loss /= num_batches
	test_acc /= size

	return test_loss, test_acc

定义训练参数

epochs = 30
optimizer = optim.Adam(model.parameters(), lr=1e-4)
loss_fn = nn.CrossEntropyLoss()
best_model_path = 'best_weather_c3.pth'
best_acc = 0

开始训练

train_loss, train_acc = [], []
test_loss, test_acc = [], []
for epoch in range(epochs):
    model.train()
    epoch_train_loss, epoch_train_acc = train(train_loader, model, loss_fn, optimizer)
    model.eval()
    with torch.no_grad():
        epoch_test_loss, epoch_test_acc = test(test_loader, model, loss_fn)
    
    train_loss.append(epoch_train_loss)
    train_acc.append(epoch_train_acc)
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    
    if best_acc < epoch_test_acc:
        best_acc = epoch_test_acc
        best_model = copy.deepcopy(model)
    
    print(f'Epoch: {epoch+1}, TrainAcc: {epoch_train_acc*100:.1f}, TrainLoss: {epoch_train_loss:.3f}, TestAcc: {epoch_test_acc*100:.1f}, TestLoss: {epoch_test_loss:.3f}')
    
print(f'training done. best_acc: {best_acc*100:.1f}. saving...')
torch.save(best_model.state_dict(), best_model_path)
print('saved')

训练过程

模型效果展示

通过30轮次的训练可以得到一个正确率有91.6%的模型,感觉是模型被训练的不充分。因为我前面的文章中,仅用了不到30万的参数就达到了95%以上的正确率。

打印训练折线图

epochs_range = range(epochs)
plt.figure(figsize=(10,5))
plt.subplot(121)
plt.plot(epochs_range, train_loss, label='train loss')
plt.plot(epochs_range, test_loss, label='validation loss')
plt.legend(loc='upper right')
plt.title('Loss')

plt.subplot(122)
plt.plot(epochs_range, train_acc, label='train accuracy')
plt.plot(epochs_range, test_acc, label='validation accuracy')
plt.legend(loc='lower right')
plt.title('Accuracy')
plt.show()

训练过程

加载最佳模型进行预测

model.load_state_dict(torch.load(best_model_path))
model.to(device)


image = random.choice(image_list)

true_label = image.parts[-2]

image = Image.open(str(image))

inputs = transform(image)
inputs = inputs.unsqueeze(0).to(device)


model.eval()
pred = model(inputs)

predict_label = class_names[pred.argmax(1).item()]

plt.figure(figsize=(5,5))

plt.imshow(image)
plt.title(f"real:{true_label}, predict:{predict_label}")
plt.axis('off')
plt.show()

执行效果

总结与思考

  • 1x1卷积用来操作通道数,此时特征图的大小不变
  • bottleneck先将特征图通道数做压缩然后再还原到输入的通道数
  • 深层的卷积神经网络保留多尺度特征的方式有两个:1. 高层特征,低层特征直接相加 2. 高层特征,低层特征堆叠在一起
  • 使用的网络有8000万参数量,效果还不如前面的30万参数量的模型,不知道是否有一种粗略的标准,来拟合相同能力的模型参数量和数据量的对应关系。还有一种原因可能是C3模型被YOLO用来做目标检测,多尺度特征捕捉的能力在天气识别任务中可以说是毫无用处。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vue】模块基本语法

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Vue快速入门》。&#x1f…

什么是WhatsApp群发,WhatsApp协议,WhatsApp云控

那么WhatsApp群控云控可以做什么呢&#xff1f; 1、获客 自动化引流&#xff0c;强大的可控性&#xff0c;产品快速拓客 2、导流 一键式傻瓜化自动加好友&#xff0c;群发&#xff0c;朋友圈营销 3、群控 一键式拉群好友&#xff0c;建群&#xff0c;进群 …

精通git,没用过git cherry-pick?

前言 git cherry-pick是git中比较有用的命令&#xff0c;cherry是樱桃&#xff0c;cherry-pick就是挑樱桃&#xff0c;从一堆樱桃中挑选自己喜欢的樱桃&#xff0c;在git中就是多次commit中挑选一个或者几个commit出来&#xff0c;也可以理解为把特定的commit复制到一个新分支…

大模型应用发展的方向|代理 Agent 的兴起及其未来(上)

“ 介绍了人工智能代理的历史渊源与演进&#xff0c;接着探讨了大型语言模型&#xff08;LLMs&#xff09;的发展&#xff0c;以及它们在知识获取、指令理解、泛化、规划和推理等方面所展现出的强大潜力。在此基础上&#xff0c;提出了一个以大型语言模型为核心的智能代理概念框…

[论文笔记]P-tuning v2

引言 今天带来第五篇大模型微调论文笔记P-tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Across Scales and Tasks。 作者首先指出了prompt tuning的一些不足,比如在中等规模的模型上NLU任务表现不好,还不能处理困难的序列标记任务,缺乏统一应用的能力。 然…

【学习草稿】背包问题

一、01背包问题 图解详细解析 &#xff08;转载&#xff09; https://blog.csdn.net/qq_37767455/article/details/99086678 &#xff1a;Vi表示第 i 个物品的价值&#xff0c;Wi表示第 i 个物品的体积&#xff0c;定义V(i,j)&#xff1a;当前背包容量 j&#xff0c;前 i 个物…

Vue中的自定义指令详解

文章目录 自定义指令自定义指令-指令的值&#xff08;给自定义指令传参数&#xff09; 自定义指令 自定义指令&#xff1a;自己定义的指令&#xff0c;可以封装一些dom 操作&#xff0c;扩展额外功能&#xff08;自动聚焦&#xff0c;自动加载&#xff0c;懒加载等复杂的指令封…

2006-2022年上市公司彭博ESG数据

2006-2022年彭博ESG数据 1、时间&#xff1a;2006-2022年 2、指标&#xff1a; Stkcd、Year、BloombergS、BloombergESG、BloombergE、BloombergG 3、指标解释&#xff1a; 彭博企业社会责任披露指数(Bloomberg ESG Disclo-sure Scores)&#xff0c;包括ESG综合得分以及环境、社…

Mac使用CMakeList编译ImGUi项目

文章目录 创建项目1.下载ImGui2.下载GLAD3.下载GLFW4.编译项目5.运行截图 创建项目 我这里创建一个demo&#xff0c;opengl这个是可以跨平台的&#xff0c;所以在mac上使用ImGui的opengl3示例 1.下载ImGui 我使用的是docking版本的&#xff0c;这个版本支持停靠功能&#xff…

Python学习 day01(注意事项)

注释 变量 数据类型的转换 运算符 / 的结果为浮点数。若// 的两边有一个为浮点数&#xff0c;则结果为浮点数&#xff0c;否则为整数。 字符串

JavaScript - canvas - 将图片保存到本地

效果 示例 项目结构&#xff1a; 源码&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>将图片保存到本地</title></head><body><canvas id"canvas"></canvas><b…

第一百五十一回 自定义组件综合实例:游戏摇杆二

文章目录 内容回顾实现方法位置细节示例代码我们在上一章回中介绍了如何实现 游戏摇杆相关的内容,本章回中将继续介绍这方面的知识.闲话休提,让我们一起Talk Flutter吧。 内容回顾 我们在上一章回中介绍了游戏摇杆的概念以及实现方法,并且通过示例代码演示了实现游戏摇杆的…

《计算机视觉中的多视图几何》笔记(9)

现在进入本书的part 2了&#xff0c;标题是Two-View Geometry。第9-14章都隶属于part 2&#xff0c;这一部分涵盖了两个透视图的几何形状知识&#xff0c;这些视图可以像在立体设备中同时获取&#xff0c;或者例如通过相对于场景移动的相机顺序获取。这两种情况在几何上是等价的…

Java基于SpringBoot的校园博客系统

第一章&#xff1a;简介 本系统主要根据博主的需求做出分析&#xff0c;让博主更好的在线查看校园博客系统信息等&#xff0c;管理员后台管理系统数据等功能。从这个系统的操作来说&#xff0c;能够有效的进行信息的添加、修改、查询、删除一些校园博客系统信息&#xff0c;在…

【深度学习实验】前馈神经网络(七):批量加载数据(直接加载数据→定义类封装数据)

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 直接加载鸢尾花数据集 a. 加载数据集 b. 数据归一化 c. 洗牌操作 d. 打印数据 2. 定义类封装数据 a. __init__(构造函数&#xff1a;用于初始化数据集对象) b.…

基础课-排列组合

1.排列 2.组合 定义 从n个不同元素中&#xff0c;任意取出m(m<n)元素并为一组&#xff0c;叫做从n个不同元素中取出m个元素的一个组合 注意:1.不同元素 2.只取不排 3.相同组合:元素相同 3.把位置当成特殊元素 这个元素不一定入选的时候&#xff0c;把位置当特殊元素 4.插空…

【AI视野·今日Sound 声学论文速览 第九期】Thu, 21 Sep 2023

AI视野今日CS.Sound 声学论文速览 Thu, 21 Sep 2023 Totally 1 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;Auto-ACD,大规模文本-音频数据集自动生成方法。 基于现有的大模型和api构建了一套大规模高质量的音频文本数据收集方法&#xff0c…

HTTP参数类型中的Query和Body参数

在接口中常见到query参数和body参数&#xff0c;那么它对应的传参方式是&#xff1f; ★ query查询参数 ---> params ---> route.params.参数 ★ body请求体参数 ---> data ---> route.query.参数 总结&#xff1a; GET请求只能传Query参数&#xff0c; POST请…

无聊的一篇博客(如何通过路由器登陆页对固定机器进行网速干扰,如何帮熊孩子戒网瘾)

1. 路由器登陆页面&#xff0c;按钮解析&#xff0c;获取按钮。 2. JavaScript与上传的脚本。 // 获取要点击的按钮A和按钮B元素var isRunning true; // 初始状态为false// 定义一个函数来模拟点击按钮A和按钮B function clickButtons() {if (isRunning) {// 随机生成一个延时…

【AI视野·今日Robot 机器人论文速览 第三十五期】Mon, 18 Sep 2023

AI视野今日CS.Robotics 机器人学论文速览 Mon, 18 Sep 2023 Totally 44 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;GelSplitter, 基于近红外与可见光融合实现高精度surfaceNormal重建的触觉传感器。(from 华中科技大学) 基于分光镜的紧凑型…