卷积神经网络实现运动鞋识别 - P5

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

目录

  • 环境
  • 步骤
    • 环境设置
      • 包引用
      • 训练设备
    • 数据准备
      • 图像解压后的路径
      • 打印图像的参数
      • 展示图像
      • 图像的预处理
      • 创建数据集
      • 获取数据集的分类
      • 打乱数据的顺序,生成批次
    • 模型设计
    • 模型训练
      • 训练函数
      • 评估函数
      • 循环迭代部分
    • 模型效果展示
      • 训练过程图表展示
      • 载入最佳模式,随机选择图像进行预测
  • 总结与心得体会


环境

  • 系统: 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 torchvision import datasets, transforms # 数据集创建、数据预处理方法
from torch.utils.data import DataLoader # DataLoader可以将数据集封装成批次数据

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image # 加载图片预览使用的库
from torchinfo import summary # 可以打印模型实际运行时的图
import copy # 深拷贝使用的库
import pathlib, random # 文件夹遍历和随机数

训练设备

# 声明一个全局设备对象,方便后面将数据和模型拷贝到设备中
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

数据准备

图像解压后的路径

train_path = 'train'
test_path = 'test'

打印图像的参数

train_pathlib = pathlib.Path(train_path)
train_image_list = list(train_pathlib.glob('*/*'))
for _ in range(5):
	print(np.array(Image.open(str(random.choice(train_image_list)))).shape)

图片的参数
重复执行了多次,返回结果都是(240, 240, 3),可以确定图像的大小统一为240,240,在数据加载的过程中可以不对图像做缩放处理。

展示图像

plt.figure(figsize=(20, 4))
for i in range(20):
	image = random.choice(train_image_list)
	plt.subplot(2, 10, i+1)
	plt.axis('off')
	plt.imshow(Image.open(str(image)))
	plt.title(image.parts[-2])

数据集预览
至此我们对数据集中的图像有了一个初步的了解。接下来就是准备训练数据。

图像的预处理

定义一些图像的预处理方法,例如将图像读取并转为pytorch的tensor对象,然后对图像的数值做归一化处理

transform = transforms.Compose([
	transforms.ToTensor(),
	transforms.Normalize(
		mean=[0.485, 0.456, 0.406], 
        std=[0.229, 0.224, 0.225]
    )
])

创建数据集

train_dataset = datasets.ImageFolder(train_path, transform=transform)
test_dataset = datasets.ImageFolder(test_path, transform=transform)

获取数据集的分类

class_names = [key for key in train_dataset.class_to_idx]
print(class_names)

数据分类

打乱数据的顺序,生成批次

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

模型设计

使用3x3的卷积核,最大的通道数到256,每次卷积操作后,就紧跟一个池化层,一共使用了4个卷积层和4个池化层。最后使用了三层全连接网络来做分类器。
模型结构图

class Network(nn.Module):
    def __init__(self, num_classes):
        super().__init__()
        
        self.conv1 = nn.Conv2d(3, 64, 3)
        self.bn1  = nn.BatchNorm2d(64)
        
        self.conv2 = nn.Conv2d(64, 128, 3)
        self.bn2 = nn.BatchNorm2d(128)
        
        self.conv3 = nn.Conv2d(128, 256, 3)
        self.bn3 = nn.BatchNorm2d(256)
        
        self.conv4 = nn.Conv2d(256, 256, 3)
        self.bn4 = nn.BatchNorm2d(256)
        
        self.maxpool = nn.MaxPool2d(2)
        
        self.fc1 = nn.Linear(13*13*256, 128)
        self.fc2 = nn.Linear(128, 128)
        self.fc3 = nn.Linear(128, num_classes)
        
        self.dropout = nn.Dropout(0.5)
        
    def forward(self, x):
        # 240 -> 238
        x = F.relu(self.bn1(self.conv1(x)))
        # 238 -> 119
        x = self.maxpool(x)
        
        # 119 -> 117
        x = F.relu(self.bn2(self.conv2(x)))
        # 117 -> 58
        x = self.maxpool(x)
        
        # 58 -> 56
        x = F.relu(self.bn3(self.conv3(x)))
        # 56 -> 28
        x = self.maxpool(x)
        
        # 28 -> 26
        x = F.relu(self.bn4(self.conv4(x)))
        # 26 -> 13
        x = self.maxpool(x)
        
        x = x.view(x.size(0), -1)
        x = self.dropout(x)
        x = F.relu(self.dropout(self.fc1(x)))
        x = F.relu(self.dropout(self.fc2(x)))
        x = self.fc3(x)
        
        return x
model = Network(len(class_names)).to(device)

summary(model, input_size=(32, 3, 240, 240))

模型结构图

模型训练

模型训练过程中,每个epoch都会对全部的训练集进行一次完整的遍历,所以可以封装一些训练和评估方法,将业务逻辑和循环分开

训练函数

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

循环迭代部分

loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-4)
scheduler = optim.lr_scheduler.LambdaLR(optimizer=optimizer, lr_lambda=lambda epoch:0.92**(epoch //2)) 
# 创建学习率的衰减
epochs = 50

train_loss, train_acc = [], []
test_loss, test_acc = [], []
best_acc = 0
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)
        
    scheduler.step() # 每次迭代调用一次,自动做学习率衰减
    
    # 如果当前评估的学习率更好,就保存当前模型
    if best_acc < epoch_test_acc:
        best_acc = epoch_test_acc
        best_model = copy.deepcopy(model)
    
    # 记录历史记录
    train_loss.append(epoch_train_loss)
    train_acc.append(epoch_train_acc)
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    
    # 打印每个迭代的数据
    print(f"Epoch:{epoch+1}, TrainLoss: {epoch_train_loss:.3f}, TrainAcc: {epoch_train_acc*100:.1f}, TestLoss: {epoch_test_loss:.3f}, TestAcc: {epoch_test_acc*100:.1f}")

# 打印本次训练的最佳正确率
print(f'training finished, best_acc is {best_acc*100:.1f}')

# 将最佳模型保存到文件中
torch.save(model.state_dict(), 'best_model.pth')

模型训练过程

模型效果展示

训练过程图表展示

画一个拆线图,观察训练过程中损失函数和正确率的变化趋势

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

epoch_range = range(epochs)

plt.subplot(1,2, 1)
plt.plot(epoch_range, train_loss, label='train loss')
plt.plot(epoch_range, test_loss, label='validation loss')
plt.legend(loc='upper right')
plt.title('Loss')

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

训练过程图示
可以看出模型在最后基本已经收敛,最佳准确率是88.2%,满足了挑战任务。

载入最佳模式,随机选择图像进行预测

model.load_state_dict(torch.load('best_model.pth'))
model = model.to(device)

test_pathlib = pathlib.Path(test_path)

image_list = list(test_pathlib.glob('*/*'))

image_path = random.choice(image_list)
image = transform(Image.open(str(image_path)))
image = image.unsqueeze(0)
image = image.to(device)

pred = model(image)

plt.figure(figsize=(5,5))
plt.axis('off')
plt.imshow(Image.open(str(image_path)))
plt.title(f'real: {image_path.parts[-2]}, predict: {class_names[pred.argmax(1).item()]}')

预测结果
上次运行上面的预测任务,发现正确率还不错。

总结与心得体会

  1. 整个模型设计的思路其实是模仿了vgg16模型,在卷积层的数量和通道上做了简化。轻量级的任务可以首先试着减少池化层间的卷积次数,减少模型中最大的特征图的通道数
  2. 对图像的归一化操作很重要。在没有归一化前,模型的最佳正确率只能达到80%,推测可能是因为未做归一化的图像值域范围太大,不方便收敛,归一化后,原始图像中的输入特征值范围变成0~1,模型的权重变化更易作用到特征上。

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

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

相关文章

Python程序化交易接口批量获取数据源码

小编举例下面是一个简单的示例代码&#xff0c;展示如何使用Python的程序化交易接口批量获取数据&#xff0c;例如开发文档参考&#xff1a;MetaTradeAPI (metatradeapi) - Gitee.com 签名 int Init(); 功能 API 初始化 参数 无 返回值 授权成功的交易账户数量 返回值 &…

UE5打完包后,启动程序不能全屏

最近看到ue5的打包程序后不能默认自动全屏&#xff0c;效果如下&#xff0c;发现并不是全屏的&#xff0c;而且就算点击放大也不是全屏 解决办法&#xff1a;设置如下之后在打包就可以了 但是会一直打印错误的日志&#xff0c;不过这个不影响使用

成都瀚网科技:抖店怎么上精选联盟?

在抖音电商平台上&#xff0c;选定的联盟是一个非常重要的入口。对于商家来说&#xff0c;能够进入选定的联盟意味着更多的曝光度和流量&#xff0c;从而获得更好的销售机会。那么&#xff0c;抖店是如何进入精选联盟的呢&#xff1f; 1、抖店如何加入特色联盟&#xff1f; 提供…

HummerRisk V1.4.0发布

大家好&#xff0c;HummerRisk 1.4.0和大家见面了&#xff0c;在这个版本中我们变更了多云检测的底层逻辑&#xff0c;增加了每次检测的project概念&#xff0c;更好的去支持检测历史和检索需要&#xff0c;增加阿里云最佳实践中资源监控检测规则&#xff0c;增加资源态势中的细…

【unity插件】使用BehaviorDesigner插件制作BOSS的AI行为树

文章目录 前言素材插件一、基础使用二、敌人物理攻击三、敌人面向玩家四、敌人法术攻击五、随机进行攻击六、敌人不同的阶段推荐学习视频源码完结 前言 Behavior Designer是一个行为树插件&#xff0c;是一款为了让策划&#xff0c;程序员&#xff0c;美术人员方便使用的可视化…

cobbler自动化安装CentOS、windows和ubuntu

环境介绍 同时玩cobbler3.3和cobbler2.8.5 cobbler3.3 系统CentOS8.3 VMware虚拟机 桥接到物理网络 IP: 192.168.1.33 cobbler2.8.5 系统CentOS7.9 VMWare虚拟机 桥接到物理网络 IP&#xff1a;192.168.1.33 安装cobbler3.3 yum源修改 cat /etc/yum.repo.d/Cento…

【Docker】用Dockerfile制作个人的镜像文件

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

更健康舒适更科技的照明体验!SUKER书客护眼台灯 L1上手体验

低价又好用的护眼台灯是多数人的需求&#xff0c;很多人只追求功能性护眼台灯&#xff0c;显色高、无频闪、无蓝光等基础需求。但是在较低价格中很难面面俱到&#xff0c;然而刚发布的SUKER书客L1护眼台灯却是一款不可多得的性价比护眼台灯&#xff0c;拥有高品质光源&#xff…

财报解读:首次全口径盈利,快手深耕电商找准了发展门道?

快手成功闯过了盈利大关。 近日快手发布的Q2财报显示&#xff0c;其借助于电商“内循环”取得超预期成效&#xff0c;不仅用户数相比一季度环比净增1900万&#xff0c;再创新高&#xff0c;而且迎来了成立以来首次单季度全口径盈利。 对于快手盈利能力的大幅提升&#xff0c;…

Spring Cloud 2022.x版本使用gateway和nacos实现动态路由和负载均衡

文章目录 1、nacos下载安装1.1、启动服务器1.2、关闭服务器1.3、服务注册&发现和配置管理接口 2、代码示例2.1、app1工程代码2.2、app2工程代码2.3、gateway网关工程代码 3、动态配置网关路由3.1、配置动态路由3.2、配置为负载模式 4、gateway配置规则4.1、请求转发&#x…

【Kali Linux】高级渗透测试实战篇

这里写目录标题 前言内容简介读者对象随书资源目录 前言 对于企业网络安全建设工作的质量保障&#xff0c;业界普遍遵循PDCA&#xff08;计划&#xff08;Plan&#xff09;、实施&#xff08;Do&#xff09;、检查&#xff08;Check&#xff09;、处理&#xff08;Act&#xff…

实现无公网IP环境下远程访问本地Jupyter Notebook服务的方法及端口映射

文章目录 前言1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 前言 Jupyter Notebook&#xff0c;它是一个交互式的数据科学和计算环境&#xff0c;支持多种编程语言&#xff0c;如…

哈希表与有序表

哈希表与有序表 Set结构 key Map结构 key-value 哈希表 哈希表的时间复杂度都是常数项级别的&#xff0c;但常数较大 增删改查的时间都是常数级别的&#xff0c;与数据量无关 当哈希表存储的值是基础数据类型&#xff08;Integer - int&#xff09;&#xff0c;哈希表中内…

Sharding-JDBC分库分表四种分片算法

1. 精确分片算法 精确分片算法&#xff08;PreciseShardingAlgorithm&#xff09;精确分片算法&#xff08;与IN语句&#xff09;&#xff0c;用于处理使用单一键作为分片键的与IN进行分片的场景。需要配合StandardShardingStrategy使用 2. 范围分片算法 范围分片算法&#…

达梦8 在CentOS 系统下静默安装

确认系统参数 [rootlocalhost ~]# ulimit -a core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited【1048576(即 1GB)以上或 unlimited】 scheduling priority (-e) 0 file size (blocks, -f) unlimite…

面试十分钟不到就被赶出来了,问的实在是太变态了...

干了两年外包&#xff0c;本来想出来正儿八经找个互联网公司上班&#xff0c;没想到算法死在另一家厂子。 自从加入这家外包公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到11月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资…

ubuntu18.04.6的安装教程

目录 一、下载并安装virtualbox virtualbox7.0.8版本的安装 二、Ubuntu的下载与安装 ubuntu18.04.6操作系统 下载 安装 一、下载并安装virtualbox VirtualBox是功能强大的x86和AMD64/Intel64虚拟化企业和家庭使用的产品。VirtualBox不仅是面向企业客户的功能极其丰富的高…

解读bl616的startup.S文件

startup.S是bl616的启动文件&#xff0c;以汇编格式存在。这就导致对需要看懂此文件的人要level高一些了&#xff0c;再加上汇编竟然是risc-v的&#xff0c;而不是arm的&#xff0c;导致本人还要恶补一下risc-v的汇编指令和risc-v的寄存器。 这里推荐一下比较的介绍risc-v架构…

神经网络与卷积神经网络

全连接神经网络 概念及应用场景 全连接神经网络是一种深度学习模型&#xff0c;也被称为多层感知机&#xff08;MLP&#xff09;。它由多个神经元组成的层级结构&#xff0c;每个神经元都与前一层的所有神经元相连&#xff0c;它们之间的连接权重是可训练的。每个神经元都计算…

终端登录github两种方式

第一种方式 添加token&#xff0c;Setting->Developer Setting 第二种方式SSH 用下面命令查看远程仓库格式 git remote -v 用下面命令更改远程仓库格式 git remote set-url origin gitgithub.com:用户名/仓库名.git 然后用下面命令生成新的SSH秘钥 ssh-keygen -t ed2…