【跨年博客/轻松向】Pytorch卷积神经网络图像识别

2023-12-27 03:30

本文主要是介绍【跨年博客/轻松向】Pytorch卷积神经网络图像识别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【跨年博客/轻松向】Pytorch卷积神经网络图像识别

  • 导语
  • 注意
  • 程序
    • 需要导入的库
    • 设置数据集
    • 定义网络
    • 训练
    • 预测
  • 一些闲谈

写于2021-12-31 23:04,2021年最后一篇博客了,也是2022年第一篇博客。


今年的格言:有一分热,发一分光,就令萤火一般,也可以在黑暗里发一点光,不必等候炬火,此后如竟没有炬火,我便是唯一的光。


导语

前几天不是发了一个MNIST图像识别的文章吗,但那篇还是有一些东西没讲的很好。MNIST图像是灰度图像,很多小伙伴想看看RGB的写法。这次拿RGB图做一个细胞分类吧~
看右下角时间~

注意

此篇博客是对上篇博客的修正、补充以及拓展。
请先参阅上期博客:【Pytorch】MNIST 图像分类代码 - 超详细解读_CSDN_千鱼干的博客
有地方看不懂没事,看完后看这篇的补充内容。

程序

需要导入的库

import torch
import torch.nn as nn
from torch.nn import Sequential
from matplotlib import pyplot as plt
import torchvision.datasets as datasets
from torch.utils.data import DataLoader
import torchvision.transforms as transforms

torch库就不解释了。
torch.nn库是一个包含了神经网络的Modules和用来继承的包以及一些函数方法,比如nn.functional。因为我们之后定义网络时是从nn.Module继承的,还用了nn里面的卷积、激活函数等等,所以这个库必不可少。
Sequential(中文:序列)是torch.nn里面“整合”层用的。就相当于饼干盒,把饼干“像序列一样”装进去。
matplotlib在这里是一个显示图像的库。我们引入了pyplot,用来显示图像。
torchvision包含一些数据集、模型、图像处理方法。这里用datasets来处理数据集(我们自己的图片)。
torch.utils.data里面的DataLoader是用来将数据集装载用的,以便训练。
torchvision.transforms在这里用于定义数据集处理形式。往下看就知道。

设置数据集

这里假设我们数据集的路径是当前你的python文件所在文件夹下data/CELLS/。这个文件夹下有两个子文件夹,一个叫“linba”,另一个叫“xianxingli”

插播一句,现在是2022-1-1 0:00,这篇博客写了一年(笑)

也就是说,我们的数据集分为淋巴细胞和线性粒细胞两种细胞的图片。
所以我们要设置两个类别:classes = [“linba”, “zhongxingli”]
我们这里设置一下批次大小位64,迭代250次,学习率0.001。
学习率选一个小小的数,这样有助于梯度下降。具体原因见上一篇博客。
这里还要写一个get_variable()函数以获取cuda加速后的自动求导结果。


这里 再次 详细解释一下epochs和batch_szie:
->batch_size表示每轮迭代训练时每次训练的数据量;
->epochs表示训练几轮。

每一次迭代(Iteration)都是一次权重更新,每一次权重更新需要batch_size个数据进行正向传递(Forward)运算得到损失函数,再通过反向传导(Backward)更新参数(注意,在这个过程中需要把梯度(Grad)设置为0,这个后面再讲)。1个迭代等于使用batch_size个样本训练一次。比如有256个样本数据,完整训练完这些样本数据需要:
->batch_size=64;
->迭代4次;
->epochs=1。


而通常会将epochs设为不仅1次,这就跟磨面一样,磨完一轮不够,磨多轮才能得到更加精细的面粉。

这时候因为我们处理的是图片,而我们处理的应该是张量(Pytorch处理的是张量,类似向量,矩阵)。我们怎么让数据集图片变成数据集矩阵呢?
这时就要设置transform(翻译:转换)了。
同时,我们的图片不能太大,否则会让训练很慢。
所以我们首先将图片转化为张量,然后将裁剪为 w ∗ h = 128 ∗ 128 w*h=128*128 wh=128128(w是width,宽;h是height,高;c是channel,通道,就是颜色通道,RGB是红绿蓝三通道)大小的张量。同时我们还要让每个像素数值服从标准为0.5的正态分布。
因为我们需要训练集和测试集两部分,所以将数据集分成两个处理内容,最后将训练集和测试集装载,数据集处理完毕。

最后,我们展示一下某张数据集图片转换为向量并处理之后的样子(可选)。

全部代码如下:

path = "./data/CELLS/"
classes = ["linba", "zhongxingli"]def get_variable(x):x = torch.autograd.Variable(x)return x.cuda() if torch.cuda.is_available() else xbatch_size = 64
epochs = 250
lr = 0.001test_path = "./data/CELLS/"transform = transforms.Compose([transforms.ToTensor(),transforms.Resize((128, 128)),transforms.CenterCrop(128),transforms.Normalize(mean=[0.5, 0.5, 0.5],std=[0.5, 0.5, 0.5])
])data_train = datasets.ImageFolder(root=path, transform=transform)
train_loader = DataLoader(data_train, batch_size=batch_size, shuffle=True)data_test = datasets.ImageFolder(root=test_path, transform=transform)
test_loader = DataLoader(data_test, batch_size=batch_size, shuffle=True)# -----------------------展示数据集---------------------------
images, labels = next(iter(train_loader))
img = images[0].numpy().transpose(1, 2, 0)
plt.imshow(img)
plt.title(labels[0])
plt.show()# -----------------------展示数据集---------------------------

定义网络

网络结构如下图:
结构
注意,输入出的“?x128x128x3”的意思是“?”张图片,“128x128x3”是 w ∗ h ∗ c = 128 ∗ 128 ∗ 3 w*h*c=128*128*3 whc=1281283

怎样定义网络呢?首先我们要从nn.Module继承,然后“装填”入我们的架构,最后在前向计算(forward)函数中进行前向计算。
这里注意一下:forward函数不需要显式调用,因为nn.Module类中有一个函数会自动调用forward。


上一篇博客没写明这里每层的参数是怎么计算的。这一部分相当重要,因为最后传入全连接层时必须要求输入和输出匹配,但这里我上篇没细讲。
这里贴出nn.Conv2d()在Pytorch官方文档里的图:

–>猛戳我 - 原文链接<–

计算的方式
注意这里的符号, H o u t H_{out} Hout是进行的向下取整
定义类的方式和上一篇相似。
代码:

class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()self.conv1 = Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.MaxPool2d(2, 2))self.conv2 = Sequential(nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.MaxPool2d(2, 2))self.conv3 = Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.MaxPool2d(2, 2))self.conv4 = Sequential(nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.MaxPool2d(2, 2))self.dense = Sequential(nn.Linear(8 * 8 * 256, 256),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(256, 128),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(128, 2))def forward(self, x):x1 = self.conv1(x)x2 = self.conv2(x1)x3 = self.conv3(x2)x4 = self.conv4(x3)x5 = x4.view(-1, 8 * 8 * 256)out = self.dense(x5)return out

训练

这一部分我上一篇讲的很详细了。我只贴出代码:

cnn = CNN()
if torch.cuda.is_available():cnn = cnn.cuda()lossF = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(cnn.parameters(), lr=lr)cnn.train()loss_pth = 999999999.99
i_pth = 0for epoch in range(epochs):running_loss = 0.0running_correct = 0.0print("Epochs [{}/{}]".format(epoch, epochs))for data in train_loader:X_train, y_train = dataX_train, y_train = get_variable(X_train), get_variable(y_train)outputs = cnn(X_train)_, predict = torch.max(outputs.data, 1)# ----------------------------------optimizer.zero_grad()loss = lossF(outputs, y_train)loss.backward()optimizer.step()# ----------------------------------running_loss += loss.item()running_correct += torch.sum(predict == y_train.data)testing_correct = 0.0for data in test_loader:X_test, y_test = dataX_test, y_test = get_variable(X_test), get_variable(y_test)outputs = cnn(X_test)_, predict = torch.max(outputs.data, 1)testing_correct += torch.sum(predict == y_test.data)print("Loss: {}    Training Accuracy: {}%    Testing Accuracy:{}%".format(running_loss,100 * running_correct / len(data_train),100 * testing_correct / len(data_test)))if running_loss < loss_pth:loss_pth = running_losstorch.save(cnn, "./models/cell_classify_%d.pth" % i_pth)i_pth = i_pth + 1torch.save(cnn, "cell_classify.pth")
print("训练完成!最小损失为:%f" % loss_pth)

预测

这一部分我在上一篇博客也是讲得比较详细。我只贴出代码。
这里设pics文件夹下还有一个文件夹,里面有待预测图片:

import torch
import torch.nn as nn
from torch.nn import Sequential
from matplotlib import pyplot as plt
import torchvision.datasets as datasets
from torch.utils.data import DataLoader
import torchvision.transforms as transformsmodel_path = "./models/cell_classify.pth"
test_path = "./pics/"classes = ["linbaxibao", "zhongxinglixibao"]transform = transforms.Compose([transforms.ToTensor(),transforms.Resize((128, 128)),transforms.CenterCrop(128),transforms.Normalize(mean=[0.5, 0.5, 0.5],std=[0.5, 0.5, 0.5])
])data_test = datasets.ImageFolder(root=test_path, transform=transform)
test_loader = DataLoader(data_test, batch_size=64, shuffle=True)class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()self.conv1 = Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(32),nn.ReLU(),nn.MaxPool2d(2, 2))self.conv2 = Sequential(nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.MaxPool2d(2, 2))self.conv3 = Sequential(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(128),nn.ReLU(),nn.MaxPool2d(2, 2))self.conv4 = Sequential(nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256),nn.ReLU(),nn.MaxPool2d(2, 2))self.dense = Sequential(nn.Linear(8 * 8 * 256, 256),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(256, 128),nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(128, 2))def forward(self, x):x1 = self.conv1(x)x2 = self.conv2(x1)x3 = self.conv3(x2)x4 = self.conv4(x3)x5 = x4.view(-1, 8 * 8 * 256)out = self.dense(x5)return outnet = torch.load(model_path)
net.eval()def get_variable(x):x = torch.autograd.Variable(x)return x.cuda() if torch.cuda.is_available() else xdef inference_model(test_img):for data in test_loader:test, _ = dataimg, _ = datatest = get_variable(test)outputs = net(test)rate, predict = torch.max(outputs.data, 1)for i in range(len(data_test)):print("It may be %s." % classes[predict[i]])img0 = img[i]img0 = img0.numpy().transpose(1, 2, 0)plt.imshow(img0)plt.title("It may be %s." % classes[predict[i]])# plt.title("It may be %s, probability is %f." % (classes[predict[i]], rate[i]))plt.show()inference_model(test_path)

结果(预测结果在图片上方和console里):预测结果在图片上方
预测结果在图片上方
可以看到预测还是蛮准的嘛~

一些闲谈

现在已经是2022年1月1日1:24了。我又长大了一岁(唉,我又老了
回首2021年。我2021年4月19日突发感想 脑瓜一热 记下了这么一句话:
哈哈
可惜的是,这个愿望只实现了,但没完全实现(谁说人工智能就一定只是会聊天的机器人啊(~o ̄3 ̄)~),我的初衷是做一个和小爱同学一样的人工智能…
目前在做超分辨率重构。
2021年初,我报名了CSDN上的一个深度学习课,当时只是打算听着玩,谁知道听的感兴趣了,就自己自学。没人指导,走了不少弯路,但还是走下来了。
笔者小时候最讨厌电脑了(小学6年级之前)。可是六年级一次电脑课上我接触了画画,我就觉得很好玩,就去研究怎么下载这样的软件,结果接触了Photoshop。谁知道这东西收费,就自己去学怎么破解。初中一年级我想为什么我自己不能编一个这样的程序呢?我就这样接触了编程。(后来还因为进了某网站后台差点惹出事,幸亏自己悬崖勒马)。
笔者从前并不喜欢数学,从前数学一直是我最讨厌的科目之一,因为我觉得我学的数学知识没有什么用到的地方,很枯燥,不理解为什么有人那么喜欢数学(我从前单纯觉得这些人是骗人的)(尽管为了高考要自我欺骗我很爱数学)。大学在某普通本科读计算机科学与技术。大一学了半年ACM,但是并不能听懂(呜呜呜)。大一上学期的寒假接触的机器学习。有趣的是,从接触机器学习开始,我发现数学原来这么实用。和编程结合后,似乎孕育出了某种神奇的力量。
啊。已经1:47了啊。以后再聊吧,我睡了()。

最后祝大家:

2022 新年快乐!

贴一张喜欢的图(侵删):
长草颜团子

这篇关于【跨年博客/轻松向】Pytorch卷积神经网络图像识别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/541769

相关文章

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

Go Mongox轻松实现MongoDB的时间字段自动填充

《GoMongox轻松实现MongoDB的时间字段自动填充》这篇文章主要为大家详细介绍了Go语言如何使用mongox库,在插入和更新数据时自动填充时间字段,从而提升开发效率并减少重复代码,需要的可以... 目录前言时间字段填充规则Mongox 的安装使用 Mongox 进行插入操作使用 Mongox 进行更

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

PyTorch使用教程之Tensor包详解

《PyTorch使用教程之Tensor包详解》这篇文章介绍了PyTorch中的张量(Tensor)数据结构,包括张量的数据类型、初始化、常用操作、属性等,张量是PyTorch框架中的核心数据结构,支持... 目录1、张量Tensor2、数据类型3、初始化(构造张量)4、常用操作5、常用属性5.1 存储(st

Debian如何查看系统版本? 7种轻松查看Debian版本信息的实用方法

《Debian如何查看系统版本?7种轻松查看Debian版本信息的实用方法》Debian是一个广泛使用的Linux发行版,用户有时需要查看其版本信息以进行系统管理、故障排除或兼容性检查,在Debia... 作为最受欢迎的 linux 发行版之一,Debian 的版本信息在日常使用和系统维护中起着至关重要的作

macOS怎么轻松更换App图标? Mac电脑图标更换指南

《macOS怎么轻松更换App图标?Mac电脑图标更换指南》想要给你的Mac电脑按照自己的喜好来更换App图标?其实非常简单,只需要两步就能搞定,下面我来详细讲解一下... 虽然 MACOS 的个性化定制选项已经「缩水」,不如早期版本那么丰富,www.chinasem.cn但我们仍然可以按照自己的喜好来更换

四种简单方法 轻松进入电脑主板 BIOS 或 UEFI 固件设置

《四种简单方法轻松进入电脑主板BIOS或UEFI固件设置》设置BIOS/UEFI是计算机维护和管理中的一项重要任务,它允许用户配置计算机的启动选项、硬件设置和其他关键参数,该怎么进入呢?下面... 随着计算机技术的发展,大多数主流 PC 和笔记本已经从传统 BIOS 转向了 UEFI 固件。很多时候,我们也

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

轻松掌握python的dataclass让你的代码更简洁优雅

《轻松掌握python的dataclass让你的代码更简洁优雅》本文总结了几个我在使用Python的dataclass时常用的技巧,dataclass装饰器可以帮助我们简化数据类的定义过程,包括设置默... 目录1. 传统的类定义方式2. dataclass装饰器定义类2.1. 默认值2.2. 隐藏敏感信息

闲置电脑也能活出第二春?鲁大师AiNAS让你动动手指就能轻松部署

对于大多数人而言,在这个“数据爆炸”的时代或多或少都遇到过存储告急的情况,这使得“存储焦虑”不再是个别现象,而将会是随着软件的不断臃肿而越来越普遍的情况。从不少手机厂商都开始将存储上限提升至1TB可以见得,我们似乎正处在互联网信息飞速增长的阶段,对于存储的需求也将会不断扩大。对于苹果用户而言,这一问题愈发严峻,毕竟512GB和1TB版本的iPhone可不是人人都消费得起的,因此成熟的外置存储方案开