【PyTorch 卷积】实战自定义的图片归类

前言

        卷积神经网络是一类包含卷积计算且具有深度结构的前馈神经网络,是深度学习的代表算法之一,它通过卷积层、池化层、全连接层等结构,可以有效地处理如时间序列和图片数据等。关于卷积的概念网络上也比较多,这里就不一一描述了。实战为主当然要从实际问题出发,用代码的方式加深印象。在写代码前,我先说一下为什么我要写这篇文章?

        之前我也用 Tensorflow.js 跟着别人试过图片分类,虽然结果是有了,但是对代码的理解和印象并不深刻。后来由于工作业务原因才接触 PyTorch,发现这个框架更好上手,整一圈后就想用这个把之前用得图片也实现一下分类。开始也是看文章实现,但是网上大部分都是用 MNIST 数据集实现的手写字识别,而业务中有时就是一些指定的不规则小众图片识别,所以下面就简单实现一个自定义的图片集归类。

流程

  • 根据自己的定义,收集图片并归类
  • 读取图片数据和归类标签,保存数据集
  • 固定图片大小 (会变形),归一化转张量
  • 定义超参数,损失函数和优化器等
  • 炼丹,重复查看损失值准确率等指标
  • 保存模型参数,加载测试图片分类效果

环境

  • Python 3.8
  • Torch 1.9.0
  • Pillow 10.0
  • Torchvision
  • Numpy
  • Pandas
  • Matplotlib

编码

        写代码前已经把需要的图片做好了分类,上面的依赖包也已经安装完毕。由于只是演示这里没有用预训练模型(ResNet、VGG),因为训练时要用的是 Tensor,所以需要先读取文件夹内的图片先转化为 PIL 的对象数据或 Numpy 数据,然后可以对图片进行调整,最后全都转成 Tensor(也可以跳过 PIL 直接转张量)。这里需要注意的是对灰彩图片通道,不同尺寸图的统一处理,就是灰色图的单通道要通过复制的方式创建三个通道,所以图片设置一样的像素大小。因为在卷积网络中,输入的通道数和输入大小要一致,不然可能在训练中报错。

图片数据生成

        这里就是遍历各个分类文件夹的图片转换为对象信息数据,和提取所有分类,分别保存到指定位置,当然也可以在这里划分训练数据,校验数据,测试数据,需要的可以扩展这里就跳过了。

# -*- coding: utf-8 -*-
import os
import pickle as pkl
import pandas as pd
from PIL import Imageall_cate = []
data_set = []
directory = "./data/train"
for index, data in enumerate(os.walk(directory)):root, dirs, files = dataif index == 0:all_cate += dirselse:sorted(all_cate)root_names = root.split("\\")dir_name = root_names[-1]for img in files:img_path = root + "\\" + imgimg_np = Image.open(img_path)dict = {}dict['img_np'] = img_npdict['label'] = all_cate.index(dir_name) + 1data_set.append(dict)# 字典转DataFrame
df = pd.DataFrame(data_set)
pkl.dump(df, open('data/train_dataset.p', 'wb'))
open("data/all_cate.txt", encoding="utf-8", mode="w+").write("\n".join(all_cate))print("存档数据成功~")
批量数据集标准化

        这里是读取序列化的图片信息,对所有图片统一像素 (一般配置电脑最好在 100px 以内,不然会很卡) 并标准归一化后,转换为 Tensor。然后判断图片通道数,如果是灰色图,可以复制张量三次以创建三个通道,最后通过 torch 的 DataLoader 在训练前完成数据集的加载。

# -*- coding: utf-8 -*-
import torch
from torchvision import transforms
import pickle as pkl
from torch.utils.data import Datasetclass DataSet(Dataset):def __init__(self, pkl_file):df = pkl.load(open(pkl_file, 'rb'))self.dataFrame = dfdef __len__(self):return len(self.dataFrame)def __getitem__(self, item):img_np = self.dataFrame.iloc[item, 0]label = self.dataFrame.iloc[item, 1]transform = transforms.Compose([transforms.Resize((100, 100)),  # 根据需要调整图像大小transforms.ToTensor(),transforms.Normalize([0.5], [0.5])    # 标准归一化, p1.均值  p2.方差])image_tensor = transform(img_np)if image_tensor.shape[0] == 1:  image_tensor = image_tensor.repeat(3, 1, 1)  res = {'img_tensor': image_tensor,'label': torch.LongTensor([label-1])    # 需要实际的索引值}return res
神经网络模型

        这里创建的是卷积神经网络,接收 3 通道,第一层卷积层卷积核 3x3,输出 25 维张量,通过批标准化(BatchNorm2d)进行归一化处理,最后通过 ReLU 激活函数进行非线性变换。第一层池化使用 2x2 的最大池化操作对卷积后的特征图进行下采样。第二层也是卷积和对应的池化,最后是全连接层。将经过池化的特征图展平,然后通过一个有 1024 个神经元的全连接层,再通过 ReLU 激活函数进行非线性变换。之后是一个有 128 个神经元的全连接层,最后再通过 ReLU 激活函数进行非线性变换,输出 5 个神经元代表分类的概率分布。

# -*- coding: utf-8 -*-
import torch.nn as nn
import torch
import math
import torch.functional as Fclass CNN(nn.Module):def __init__(self):super(CNN, self).__init__()self.layer1 = nn.Sequential(nn.Conv2d(3, 25, kernel_size=3),nn.BatchNorm2d(25),nn.ReLU(inplace=True))self.layer2 = nn.Sequential(nn.MaxPool2d(kernel_size=2, stride=2))self.layer3 = nn.Sequential(nn.Conv2d(25, 50, kernel_size=3),nn.BatchNorm2d(50),nn.ReLU(inplace=True))self.layer4 = nn.Sequential(nn.MaxPool2d(kernel_size=2, stride=2))self.fc = nn.Sequential(nn.Linear(50 * 23 * 23, 1024),nn.ReLU(inplace=True),nn.Linear(1024, 128),nn.ReLU(inplace=True),nn.Linear(128, 5))def forward(self, x):x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = x.view(x.size(0), -1)x = self.fc(x)return x
开始训练
# -*- coding:utf-8 -*-
import torch
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
from data_set import DataSet
from torch.autograd import Variable
from utils import *
import cnn
import torch.nn as nn
import numpy as np
import torch.optim as optim# 定义超参数
batch_size = 1
learning_rate = 0.02
num_epoches = 1# 加载图片tensor训练集
tain_dataset = DataSet("data/train_dataset.p")
train_loader = DataLoader(tain_dataset, batch_size=batch_size, shuffle=True)model = cnn.CNN()# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate)# 训练模型
train_loses = []
records = []
for i in range(num_epoches):for ii, data in enumerate(train_loader):img = data['img_tensor']label = data['label'].view(-1)optimizer.zero_grad()out = model(img)loss = criterion(out, label)train_loses.append(loss.data.item())loss.backward()optimizer.step()if ii % 50 == 0:print('epoch: {}, loop: {}, loss: {:.4}'.format(i, ii, np.mean(train_loses)))records.append([np.mean(train_loses)])# 绘制模型的损失,准确率走势图
train_loss = [data[0] for data in records]
plt.plot(train_loss, label = 'Train Loss')
plt.xlabel('Steps')
plt.ylabel('Loss')
plt.legend()
plt.show()# 模型评估(略)
# model.eval()# 模型保存
torch.save(model, 'params/cnn_imgs_02.pkl')
模型检测

        训练完成保存参数到本地,下面就是将加载进的参数来测试其他图片的分类效果,同样的也是将指定图片和训练时一样的转换操作,最后将预测结果取出最大分布索引值,根据索引就可以匹配出分类名称了。另一个是工具函数,将 tensor 格式的图片在预测结果后显示在 pyplot 中。

# -*- coding:utf-8 -*-
import torch
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
from data_set import DataSet
from utils import *
import torchvision
from PIL import Image
from torchvision import transforms
import cnndef imshow(img):img = img / 2 + 0.5npimg = img.numpy()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()model = torch.load("params/cnn_imgs_02.pkl")img_path= "imgs/05.jpg"
img_np = Image.open(img_path)
transform = transforms.Compose([transforms.Resize((100, 100)),  transforms.ToTensor(),transforms.Normalize([0.5], [0.5])  
])
image_tensor = transform(img_np)# 如果是灰度图片
if image_tensor.shape[0] == 1:  image_tensor = image_tensor.repeat(3, 1, 1)  image_tensor = image_tensor.view(-1, 3, 100, 100)predict = model(image_tensor)
indices = torch.max(predict, 1)[1].item()all_cate = []
for line in open("data/all_cate.txt", encoding="utf-8", mode="r"):all_cate.append(line.strip())cate_name = ""
try:cate_name = all_cate[indices]
except ValueError:cate_name = "未知"print("识别结果是:", cate_name)
# imshow(torchvision.utils.make_grid(image_tensor))
# 原图显示
img_np.show()
exit()

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

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

相关文章

c++之类和对象

首先我们要理解cin,cout只能自动识别内置类型,原因就是因为cin,cout里面的函数重载。 那么如果我想输入非内置类型,就要进行运算符重载。 但是会发生如下的情况。 友元函数可以访问对象的私有。 运算符重载的总结 成员初始化既可以用函数体内初始化也可…

docker部署minio并使用springboot连接

需求:工作中,在微信小程序播放时,返回文件流并不能有效的使用,前端需要一个可以访问的地址,springboot默认是有资源拦截器的,但是不适合生产环境的使用 可以提供使用的有例如fastdfs或者minio,这…

【Linux】安装配置解决CentosMobaXterm的使用及Linux常用命令以及命令模式

目录 Centos的介绍 centos安装配置&MobaXterm 创建 安装 ​编辑 配置 ​编辑 MobaXterm使用 Linux常用命令&模式 常用命令 vi或vim编辑器 三种模式 命令模式 编辑模式 末行模式 拍照备份 Centos的介绍 CentOS(Community Enterprise Op…

软件测试面试,一定要准备的7个高频面试题(附答案,建议收藏)

问题1:请自我介绍下? 核⼼要素:个⼈技能优势⼯作背景经验亮点参考回答: 第一种:基本信息离职理由 ⾯试官您好,我叫张三,来⾃番茄市,在软件测试⾏业有 3 年的⼯作经验。做过 Web/APP…

无需编程技术,快速搭建个人网站

如果你想拥有一个属于自己的个人网站,但又没有任何编程经验,别担心,我们今天将为你介绍一个简单的方法,让你轻松搭建网站,无需任何编程知识。让我们一起来看看吧! 在乔拓云建站工具中,自带了许多…

图纸管理制度《八》设计图纸管理制度

第一章 总则 第1条 目的。为做好设计图纸的管理工作,使其收发及时、手续齐全、废图绝迹、不遗失、无差错,特制定本办法。 第2条 适用范围。本办法适用于企业所有工程项目的图纸管理工作。 第3条 相关部门及人员职责 (1) 工程技术部负责图纸管理的监督…

0基础学习PyFlink——个数滑动窗口(Sliding Count Windows)

大纲 滑动(Sliding)和滚动(Tumbling)的区别样例窗口为2,滑动距离为1窗口为3,滑动距离为1窗口为3,滑动距离为2窗口为3,滑动距离为3 完整代码参考资料 在 《0基础学习PyFlink——个数…

Explaining and harnessing adversarial examples

Explaining and harnessing adversarial examples----《解释和利用对抗样本》 背景: 早期的研究工作认为神经网络容易受到对抗样本误导是由于其非线性特征和过拟合。 创新点: 该论文作者认为神经网络易受对抗性扰动影响的主要原因是它的线性本质&#xf…

stm32 模拟I2C

目录 简介 I2C 物理层 协议层 ①②:起始信号和结束信号 ③ 应答和非应答信号 ④数据有效性 ⑤数据传输 ⑥空闲状态 简介 I2C 物理层 一个 I2C 总线两条线组成,一个双向串行数据线SDA用来表示数据,一个串行时钟线SCL用于数据收发同步…

5个最流行的文本生成纹理AI工具

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 3D场景编辑器 拥抱文本生成纹理AI模型改变游戏规则的力量,人工智能驱动的创新彻底改变了游戏开发中的资产创建。 这些出色的工具可将书面描述转换…

《Generic Dynamic Graph Convolutional Network for traffic flow forecasting》阅读笔记

论文标题 《Generic Dynamic Graph Convolutional Network for traffic flow forecasting》 干什么活:交通流预测(traffic flow forecasting )方法:动态图卷积网络(Dynamic Graph Convolutional Network)…

Ubuntu 使用 nginx 搭建 https 文件服务器

Ubuntu 使用 nginx 搭建 https 文件服务器 搭建步骤安装 nginx生成证书修改 config重启 nginx 搭建步骤 安装 nginx生成证书修改 config重启 nginx 安装 nginx apt 安装: sudo apt-get install nginx生成证书 使用 openssl 生成证书: 到对应的路径…

【Mybatis-Plus】常见的@table类注解

目录 引入Mybatis-Plus依赖 TableName 当实体类的类名在转成小写后和数据库表名相同时 当实体类的类名在转成小写后和数据库表名不相同时 Tableld TableField 当数据库字段名与实体类成员不一致 成员变量名以is开头,且是布尔值 ​编辑 成员变量名与数据库关…

IDEA中application.properties文件中文乱码

现象: 原因: 项目编码格式与IDEA编码格式不一致导致的 解决办法: 在File->Settings->Editor->File Encodings选项中,将Global Encoding,Project Encoding,Default encoding for properties files这三个选项置为一致&a…

使用 Curl 和 DomCrawler 下载抖音视频链接并存储到指定文件夹

项目需求 假设我们需要从抖音平台上下载一些特定的视频,以便进行分析、编辑或其他用途。为了实现这个目标,我们需要编写一个爬虫程序来获取抖音视频的链接,并将其保存到本地文件夹中。 目标分析 在开始编写爬虫之前,我们需要了…

QQ文件怎么恢复?3个方法解决文件丢失问题!

无论是在学习还是工作中,我们都有可能需要接触到QQ这款软件。QQ传输文件十分方便,因此仍然有许多小伙伴喜欢用QQ来发送各种类型的文件。对于大家来说,最害怕的莫过于重要的文件出现丢失的情况。 当我们发现QQ文件意外删除或者过期时该怎么办…

k8s之集群调度

目录 调度 工作机制 调度过程 调度算法 优先级 指定调度节点 调度 Kubernetes 是通过 List-Watch 的机制进行每个组件的协作,保持数据同步的,每个组件之间的设计实现了解耦。 用户是通过 kubectl 根据配置文件,向 APIServer 发送命令…

【java学习—十】操作集合的工具类Collections(8)

文章目录 1. 操作集合的工具类: Collections2. 应用3. 查找、替换3.1. max 与 min3.2. 根据Comparator返回max(min) 3.3. frequency 与 replaceAll4. 同步控制 1. 操作集合的工具类: Collections Collections 是一个操作 Set 、List 和 Map 等集合的工具…

嵌入式Linux系统的闪存设备和文件系统学习纪要

嵌入式Linux系统的闪存设备和文件系统学习纪要 Linux下的文件系统结构如下: NAND Flash 是一种非易失性存储器(Non-Volatile Memory),常用于闪存设备和固态硬盘(SSD)中。以下是几种常见的 NAND Flash 种类&…

PTA 函数题(C语言)-- 阶乘计算升级版

题目title: 阶乘计算升级版 题目作者: 陈越 浙江大学 本题要求实现一个打印非负整数阶乘的函数。 函数接口定义: void Print_Factorial ( const int N ); 其中N是用户传入的参数,其值不超过1000。如果N是非负整数&#…