卷积神经网络实现天气图像分类 - P3

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍦 参考文章:Pytorch实战 | 第P3周:彩色图片识别:天气识别
  • 🍖 原作者:K同学啊 | 接辅导、项目定制
  • 🚀 文章来源:K同学的学习圈子

目录

  • 环境
  • 步骤
    • 环境设置
    • 数据准备
    • 模型设计
    • 模型训练
    • 结果展示
  • 总结与心得体会


环境

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

步骤

环境设置

首先是包引用

import torch # pytorch主包
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 matplotlib.pyplot as plt # 图表库
from torchinfo import summary # 打印模型结构

查询当前环境的GPU是否可用

print(torch.cuda.is_available())

GPU可用情况
创建一个全局的设备对象,用于使各类数据处于相同的设备中

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 当GPU不可用时,使用CPU

# 如果是Mac系统可以多增加一个if条件,启用mps
if torch.backends.mps.is_available():
	device = torch.device('mps')

数据准备

这次的天气图像是由K同学提供的,我提前下载下来放在了当前目录下的data文件夹中
加载文件夹中的图像数据集,要求文件夹按照不同的分类并列存储,一个简要的文件树为

data
	cloudy
	rain
	shine
	sunrise

使用torchvisio.datasets中的方法加载自定义图像数据集,可以免除一些文章中推荐的自己创建Dataset,个人感觉十分方便,而且这种文件的存储结构也兼容keras框架。

首先我们使用原生的PythonAPI来遍历一下文件夹,收集一下分类信息

import pathlib

data_lib = pathlib.Path('data')
class_names = [f.parts[-1] for f in data_lib.glob('*')] # 将data下级文件夹作为分类名
print(class_names)

打印分类信息
在所有的图片中随机选择几个文件打印一下信息。

import numpy as np
from PIL import Image
import random

image_list = list(data_lib.glob('*/*'))
for _ in range(10):
	print(np.array(Image.open(random.choice(image_list))).shape)

打印图像信息
通过打印图像信息,发现图像的大小并不一致,需要在创建数据集时对图像进行缩放到统一的大小。

transform = transforms.Compose([
	transforms.Resize([224, 224]), # 将图像都缩放到224x224
	transforms.ToTensor(), # 将图像转换成pytorch tensor对象
]) # 定义一个全局的transform, 用于对齐训练验证以及测试数据

接下来就可以正式从文件夹中加载数据集了

dataset = datasets.ImageFolder('data', transform=tranform)

现在把整文件夹下的所有文件加载为了一个数据集,需要根据一定的比例划分为训练和验证集,方便模型的评估

train_size = int(len(dataset) *0.8) # 80% 训练集 20% 验证集
eval_size = len(dataset) - train_size

train_dataset, eval_dataset = random_split(dataset, [train_size, eval_size])

创建完数据集,打印一下数据集中的图像

plt.figure(figsize=(20, 4))
for i in range(20):
	image, label = train_dataset[i]
	plt.subplot(2, 10, i+1)
	plt.imshow(image.permute(1,2,0)) # pytorch的tensor格式为N,C,H,W,在imshow展示需要将格式变成H,W,C格式,使用permute切换一下
	plt.axis('off')
	plt.title(class_names[label])

预览数据集
最后用DataLoader包装一下数据集,方便遍历

batch_size = 32
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
eval_loader = DataLoader(eval_loader, batch_size=batch_size)

模型设计

使用一个带有BatchNorm的卷积神经网络来处理分类问题

class Network(nn.Module):
	def __init__(self, num_classes):
		super().__init__()
		self.conv1 = nn.Conv2d(3, 12, kernel_size=5, strides=1)
		self.conv2 = nn.Conv2d(12, 12, kernel_size=5, strides=1)
		self.conv3 = nn.Conv2d(12, 24, kernel_size=5, strides=1)
		self.conv4 = nn.Conv2d(24, 24, kernel_size=5, strides=1)

		self.maxpool = nn.MaxPool2d(2)

		self.bn1 = nn.BatchNorm2d(12)
		self.bn2 = nn.BatchNorm2d(12)
		self.bn3 = nn.BatchNorm2d(24)
		self.bn4 = nn.BatchNorm2d(24)

		# 224 [-> 220 -> 216 -> 108] [-> 104 -> 100 -> 50]
		self.fc1 = nn.Linear(50*50*24, num_classes)
	
	def forward(self, x):
		x = F.relu(self.bn1(self.conv1(x)))
		x = F.relu(self.bn2(self.conv2(x)))
		x = self.maxpool(x)
		x = F.relu(self.bn3(self.conv3(x)))
		x = F.relu(self.bn4(self.conv4(x)))
		x = self.maxpool(x)
	
		x = x.view(x.size(0), -1)
		
		x = self.fc1(x)

		return x

model = Network(len(class_names)).to(device) # 别忘了把定义的模型拉入共享中
summary(model, input_size=(32, 3, 224, 224))

模型结构

模型训练

首先定义一下每个epoch内训练和评估的逻辑

def train(train_loader, model, loss_fn, optimizer):
	train_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)
		
		preds = model(x)
		loss = loss_fn(preds, y)

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

		train_loss += loss.item()
		train_acc += (preds.argmax(1) == y).type(torch.float).sum().item()
	train_loss /= num_batches
	train_acc /= train_size
	return train_loss, train_acc
	
def eval(eval_loader, model, loss_fn):
	eval_size = len(eval_loader.dataset)
	num_batches = len(eval_loader)
	eval_loss, eval_acc = 0, 0
	for x, y in eval_loader:
		x, y = x.to(device), y.to(device)

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

		eval_loss += loss.item()
		eval_acc += (preds.argmax(1) == y).type(torch.float).sum().item()
	eval_loss /= num_batches
	eval_acc /= eval_size

	return eval_loss, eval_acc

然后编写代码进行训练

loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)
epochs = 10

train_loss, train_acc = [], []
eval_loss, eval_acc =[], []
for epoch in range(epochs):
	model.train()
	epoch_train_loss, epoch_train_acc = train(train_loader, model, loss_fn, optimizer)
	model.eval()
	model.no_grad():
		epoch_eval_loss, epoch_eval_acc = test(eval_loader, model, loss_fn)

结果展示

训练结果
基于训练和测试数据展示结果

range_epochs = range(len(train_loss))
plt.figure(figsize=(12, 4))
plt.subplot(1,2,1)
plt.plot(range_epochs, train_loss, label='train loss')
plt.plot(range_epochs, eval_loss, label='validation loss')
plt.legend(loc='upper right')
plt.title('Loss')

plt.subplot(1,2,2)
plt.plot(range_epochs, train_acc, label='train accuracy')
plt.plot(range_epochs, eval_acc, label='validation accuracy')
plt.legend(loc='lower right')
plt.title('Accuracy')

训练历史图表

总结与心得体会

通过对训练过程的观察,训练过程中的数据波动很大,并且验证集上的最好正确率只有82%。
目前行业都流行小卷积核,于是我把卷积核调整为了3x3,并且每次卷积后我都进行池化操作,直到通道数为64,由于天气识别时,背景信息也比较重要,高层的卷积操作后我使用平均池化代替低层使用的最大池化,加大了全连接层的Dropout惩罚比重,用来抑制过拟合问题。最后的模型如下:

class Network(nn.Module):
    def __init__(self, num_classes):
        super().__init__()
        
        self.conv1 = nn.Conv2d(3, 16, kernel_size=3)
        self.conv2 = nn.Conv2d(16, 32, kernel_size=3)
        self.conv3 = nn.Conv2d(32, 64, kernel_size=3)
        self.conv4 = nn.Conv2d(64, 64, kernel_size=3)
        
        self.bn1 = nn.BatchNorm2d(16)
        self.bn2 = nn.BatchNorm2d(32)
        self.bn3 = nn.BatchNorm2d(64)
        self.bn4 = nn.BatchNorm2d(64)
        
        self.maxpool = nn.MaxPool2d(2)
        self.avgpool = nn.AvgPool2d(2)
        self.dropout = nn.Dropout(0.5)
        
        # 224 -> 222-> 111 -> 109 -> 54 -> 52 -> 50 -> 25
        self.fc1 = nn.Linear(25*25*64, 128)
        self.fc2 = nn.Linear(128, num_classes)
        
    def forward(self, x):
        x = F.relu(self.bn1(self.conv1(x)))
        x = self.maxpool(x)
        x = F.relu(self.bn2(self.conv2(x)))
        x = self.avgpool(x)
        x = F.relu(self.bn3(self.conv3(x)))
        x = F.relu(self.bn4(self.conv4(x)))
        x = self.avgpool(x)
        
        
        x = x.view(x.size(0), -1)
        x = self.dropout(x)
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x

然后增大训练的epochs为30,学习率降低为1e-4

optimizer = optim.Adam(model.parameters(), lr=1e-4)
epochs = 30

训练结果如下
训练过程
可以看到,验证集上的正确率最高达到了95%以上
训练过程图示

在数据集中随机选取一个图像进行预测展示

image_path = random.choice(image_list)
image_input = transform(Image.open(image_path))
image_input = image_input.unsqueeze(0).to(device)
model.eval()
pred = model(image_input)

plt.figure(figsize=(5, 5))
plt.imshow(image_input.cpu().squeeze(0).permute(1,2,0))
plt.axis('off')
plt.title(class_names[pred.argmax(1)])

结果如下
预测结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++的对象与类的含义

C是一门面向对象的编程语言,理解C需要掌握类(class)和对象(object)这两个概念。 C 中的类(Class)可以看做C语言中结构体(Struct)的升级版。结构体是一种构造类型&#x…

【后端速成 Vue】第一个 Vue 程序

1、为什么要学习 Vue? 为什么使用 Vue? 回想之前,前后端交互的时候,前端收到后端响应的数据,接着将数据渲染到页面上,之前使用的是 JavaScript 或者 基于 JavaScript 的 Jquery,但是这两个用起来还是不太…

回归预测 | MATLAB实现CSO-BP布谷鸟优化算法优化BP神经网络多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现CSO-BP布谷鸟优化算法优化BP神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现CSO-BP布谷鸟优化算法优化BP神经网络多输入单输出回归预测(多指标,多图)效果一览…

Alibaba-Easyexcel 使用总结

简介 简介 EasyExcel 是一个基于 Java 的简单、省内存的读写 Excel 的开源项目,在尽可能节约内存的情况下支持读写百 M 的 Excel。 但注意,其不支持: 单个文件的并发写入、读取读取图片宏 常见问题 Excel 术语 Sheet,工作薄…

C# WPF ListBox 动态显示图片

前言 最近在和其他软件联合做一个本地图片选择传输功能,为此希望图片能够有序的呈现在客户端,简单的实现了一下功能,通过Mvvm模式进行呈现,过程简单通俗,话不多说直接上图。 处理过程 前台代码 你只需要粘贴到你的前台…

SQL - 开窗(窗口)函数

什么是开窗函数&#xff1f; 开窗函数对一组值进行操作&#xff0c;它不像普通聚合函数那样需要使用GROUP BY子句对数据进行分组&#xff0c;能够在同一行中同时返回基础行的列和聚合列 开窗函数的语法形式为&#xff1a;函数 over(partition by <分组用列> order by …

数据结构与算法:计算机科学的基石

文章目录 数据结构&#xff1a;构建数据的框架算法&#xff1a;问题的解决方案编程语言&#xff1a;实现数据结构的工具结论 &#x1f389;欢迎来到数据结构学习专栏~数据结构与算法&#xff1a;计算机科学的基石 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&…

Linux的基础指令

目录 1、ls指令 .和..意义 2、pwd指令 3、cd指令 ①cd ~ ②cd - 关于cd ..的用法 绝对路径和相对路径 4、touch指令 5、mkdir指令 tree指令 6、rmdir指令 7、rm指令 * 8、man指令 9、cp指令 nano&#xff1a; 10、mv指令 11、cat指令 12、more指令 13、less…

PCL 三维点云边界提取(C++详细过程版)

边界提取 一、概述二、代码实现三、结果展示本文由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 点云边界提取在PCL里有现成的调用函数,具体算法原理和实现代码见:PCL 点云边界提取。为充分了解pcl::BoundaryEsti…

最新ai系统ChatGPT程序源码+详细搭建教程+mj以图生图+Dall-E2绘画+支持GPT4+AI绘画+H5端+Prompt知识库

目录 一、前言 二、系统演示 三、功能模块 3.1 GPT模型提问 3.2 应用工作台 3.3 Midjourney专业绘画 3.4 mind思维导图 四、源码系统 4.1 前台演示站点 4.2 SparkAi源码下载 4.3 SparkAi系统文档 五、详细搭建教程 5.1 基础env环境配置 5.2 env.env文件配置 六、环境…

欧拉计划45题

Triangular, pentagonal, and hexagonal Triangle, pentagonal, and hexagonal numbers are generated by the following formulae: Triangle 1,3,6,10,15,… Pentagonal 1,5,12,22,35,… Hexagonal 1,6,15,28,45,… It can be verified…

性能比较 - Spring Boot 应用程序中的线程池与虚拟线程 (Project Loom)

本文比较了 Spring Boot 应用程序中的不同请求处理方法&#xff1a;ThreadPool、WebFlux、协程和虚拟线程 (Project Loom)。 在本文中&#xff0c;我们将简要描述并粗略比较可在 Spring Boot 应用程序中使用的各种请求处理方法的性能。 高效的请求处理在开发高性能后端…

镜像底层原理详解和基于Docker file创建镜像

目录 一、镜像底层原理 1.联合文件系统(UnionFS) 2.镜像加载原理 3.为什么Docker里的centos的大小才200M? 二、Dockerfile 1.简介 2.Dockerfile操作常用命令 &#xff08;1&#xff09;FORM 镜像 &#xff08;2&#xff09;MAINTAINER 维护人信息 &#xff08;3&…

电商系统架构设计系列(九):如何规划和设计分库分表?

上篇文章中&#xff0c;我给你留了一个思考题&#xff1a;分库分表该如何设计&#xff1f; 今天这篇文章&#xff0c;我们来聊一下如何规划和设计分库分表&#xff0c;以及要考虑哪些问题。 引言 当要解决海量数据的问题&#xff0c;就必须要用到分布式的存储集群了&#xff…

2023.8 - java - 泛型

泛型问题的引出&#xff1a; jdk 1.5 引出泛型 // package 泛型; public class index {public static void main (String[] args){test t new test();t.setContent("aaa");int a (int) t.getContent();System.out.println(a);} }class test{Object content;publi…

RNN+LSTM正弦sin信号预测 完整代码数据视频教程

视频讲解:RNN+LSTM正弦sin信号预测_哔哩哔哩_bilibili 效果演示: 数据展示: 完整代码: import torch import torch.nn as nn import torch.optim as optim import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.preprocessing import…

1.jvm和java体系结构

jvm简介 JVM&#xff1a;跨语言的平台 Java是目前应用最为广泛的软件开发平台之一。随着Java以及Java社区的不断壮大Java 也早已不再是简简单单的一门计算机语言了&#xff0c;它更是一个平台、一种文化、一个社区。 ● 作为一个平台&#xff0c;Java虚拟机扮演着举足轻重的…

无涯教程-Perl - use函数

描述 此函数将MODULE导出的所有功能(或仅LIST引用的功能)导入当前包的名称空间。有效等效于- BEGIN { require "Module.pm"; Module->import(); }也用于在当前脚本上强加编译器指令(编译指示),尽管从本质上讲它们只是模块。 请注意,use语句在编译时进行判断。在…

SpringBoot 模板模式实现优惠券逻辑

一、计算逻辑的类结构图 在这张图里&#xff0c;顶层接口 RuleTemplate 定义了 calculate 方法&#xff0c;抽象模板类 AbstractRuleTemplate 将通用的模板计算逻辑在 calculate 方法中实现&#xff0c;同时它还定义了一个抽象方法 calculateNewPrice 作为子类的扩展点。各个具…

三子棋游戏

目录 主函数test.c 菜单函数 选择实现 游戏函数 &#xff08;函数调用&#xff09; 打印棋盘数据 打印展示棋盘 玩家下棋 电脑下棋 判断输赢 循环 test.c总代码 头文件&函数声明game.h 头文件的包含 游戏符号声明 游戏函数声明 game.h总代码 游戏函数ga…