当前位置: 首页 > news >正文

人工智能——卷积神经网络自定义模型全流程初识

用卷积神经网络,自行编写一个模型,实现模型的训练,验证,测试

主要步骤:

        1、先自定义一个卷积神经网路模型

        2、对模型进行训练

        3、模型验证

        4、测试

一、定义模型

我们需要定义一个多层的卷积神经网络,先定义一层卷积,对其使用激活函数激活,然后进行池化操作。多定义几层后进行全连接层定义,将卷积后得到的局部特征图像传入全连接神经网路进行整体识别。

代码:

#定义一个多层的卷积神经网络
import torch
import torch.nn as nnclass NumberModel(nn.Module):def __init__(self):super(NumberModel, self).__init__()#调用父类的构造函数#进行第一层卷积、激活、池化self.conv1 = nn.Sequential(nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5,stride=1,),nn.ReLU(),)self.pool1 = nn.AdaptiveMaxPool2d(output_size=14)#进行第二层卷积、激活、池化self.conv2 = nn.Sequential(nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5,stride=1,),nn.ReLU(),)self.pool2 = nn.AdaptiveMaxPool2d(output_size=5)#全连接层self.fc1 = nn.Sequential(nn.Linear(5*5*16,120),nn.ReLU(),)self.fc2 = nn.Sequential(nn.Linear(120,84),nn.ReLU(),)self.fc3 = nn.Linear(84,10)def forward(self, x):#卷积层、池化层前向传播x = self.conv1(x)x = self.pool1(x)x =self.conv2(x)x = self.pool2(x)#将卷积池化后得到的(N,C,H,W)转为全连接需要的二维张量(N,in_features)x = x.view(x.shape[0],-1)#x.shape[0]为batch_size,-1表示自动计算实际上就是把C*H*W计算一张图像上的像素点个数#全连接层前向传播x = self.fc1(x)x = self.fc2(x)out = self.fc3(x)return out

二、训练模型(难点!)

1、训练模型前,一般需要对数据进行数据预处理和数据增强        ----->        transforms.Compose

2、读入数据

3、对数据进行加载        ——>        DataLoader

DataLoader可以将数据集(Dataset)包装成一个可迭代的对象,方便在训练时按批次加载数据,还支持多进程加速、数据打乱等功能

经过 DataLoader 输出的对象是批次数据(batch data),通常是一个元组。在绝大多数情况下(例如处理图像、文本等常见数据),DataLoader 每次迭代会返回一个包含输入数据(data) 和标签(target) 的元组 (data, target):

  • data:批次输入数据,形状为 [batch_size, ...]... 表示数据本身的维度,如图像的 [通道数, 高, 宽],文本的 [序列长度] 等),类型通常是 torch.Tensor
  • target:批次标签数据,形状为 [batch_size],类型通常是 torch.Tensor(整数型,对应分类任务的类别索引)

4、定义设备,使用GPU运行还是CPU运行        ——>        torch.device

5、用优化器优化        ——>        opt.Adam

6、定义损失函数(交叉熵损失函数)

7、定义训练轮次

8、训练

1、理清楚循环步骤

总共要训练epochs轮,所以要进行循环

每一个轮次当中,又要对多个批次的数据进行处理——>因此一轮中对数据集不同批次也要进行循环。经过DataLoader方法后,整个数据集划分为了多个批次,每次迭代返回(数据, 标签)。

处理时,用enumerate函数,给DataLoader方法返回的元组(数据, 标签)元素加上序号。

        例如:

fruits = ['苹果', '香蕉', '橘子']
for idx, fruit in enumerate(fruits):print(idx, fruit)输出:
0 苹果
1 香蕉
2 橘子

在搞清楚怎么循环处理后,对每个批次进行处理

2、首先是训练、前向传播,将数据传给model

3、将输出output(预测)和标签target传给损失函数计算该批次下的损失值

4、因为我们计算的是整个数据集平均的损失值,也就是每个批次的损失值之和除以所有数据,因此我们要将每个批次得到的损失值累加——>loss = loss_fn(output, targets),loss_total += loss

5、计算准确率,首先要得到每个批次预测准确的个数acc,然后累计所有批次预测准确的个数acc_total,然后用所有批次预测准确的累计个数除以所有数据的个数,就可以得到数据集平均准确值

6、acc怎么算?用这个方法:

        pre = output.argmax(dim=1)

        acc = torch.sum(pre == targets)

 torch.argmax(..., dim=1) 在干嘛?

假如一个批次有32张图片,想办法取到每张图片在不同类别下面得分最高的索引——torch.argmax(..., dim=1)

argmax 是 “取最大值的索引”。结合 dim=1,就是对每张图片的 10 个得分取最大值所在的位置(即类别索引)

  • 第 1 张图的得分中,最大值是 3.2(对应索引 3)→ 预测为数字 3;
  • 第 2 张图的得分中,最大值是 4.1(对应索引 4)→ 预测为数字 4;

因此 pre 的结果是:

tensor([3, 4])  # 第1张图预测为3,第2张图预测为4

pre 的形状是 (N,)(即 (32,) 当 batch_size=32 时),每个元素是对应图片的预测类别。

torch.sum(pre == target) 和torch.sum(pre == target)在干嘛

pre 是模型预测的类别(如 [3,4]),target 是真实标签(如 [3,5])。
pre == target 会逐元素比较,返回布尔值

sum 会把布尔值转为数字(True=1False=0)并求和,结果是 “当前批次中预测正确的样本数量”

7、acc_total累计总的正确样本数

 print(f"{epoch + 1}/{epochs}:该轮次平均损失值:loss_total / len(train_dataset),该轮次平均准确率:acc_total / len(train_dataset)")

该轮次平均损失值:loss_total / len(train_dataset)

该轮次平均准确率:acc_total / len(train_dataset)")

9、保存模型——>torch.save(model.state_dict(), "输入路径")

#定义模型后进行模型的训练
import torch
import torch.nn as nn
import torch.optim as opt
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST
from model import NumberModeltransform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,)),#均值和标准差transforms.Resize((32, 32)),#随机旋转transforms.RandomRotation(30),#随机水平翻转transforms.RandomHorizontalFlip(p=0.5),#随机垂直翻转transforms.RandomVerticalFlip(p=0.5),#随机裁剪transforms.RandomCrop(32, padding=4),
])
#读取数据集
train_dataset = MNIST(root='../data/MNIST',train=True,transform=transform,download=False
)
#加载数据集
data_loader = DataLoader(train_dataset,batch_size=32,shuffle=True,
)
#定义设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = NumberModel().to(device)
#定义优化器
optimizer = opt.Adam(model.parameters(), lr=0.001)
#轮次
epochs = 10
#损失函数
loss_fn = nn.CrossEntropyLoss(reduction="sum")#对当前批次的所有样本的损失求和model.train()
model_path = '../weight/model1.pth'#训练
for epoch in range(epochs):acc_total = 0loss_total = 0for batch_idx, (data,target) in enumerate(data_loader):data, targets = data.to(device), targets.to(device)output = model(data)loss = loss_fn(output, targets)pre = output.argmax(dim=1)acc = torch.sum(pre == targets)acc_total += accloss_total += loss#反向传播optimizer.zero_grad()loss.backward()optimizer.step()print(f"{epoch + 1}/{epochs}:该轮次平均损失值:loss_total / len(train_dataset),该轮次平均准确率:acc_total / len(train_dataset)")#保存模型
torch.save(model.state_dict(), model_path)
print("保存模型成功!")

三、验证

前面步骤与训练差不多,也是:

1、训练模型前,一般需要对数据进行数据预处理和数据增强        ----->        transforms.Compose

2、读入数据

3、对数据进行加载        ——>        DataLoader

4、定义设备,使用GPU运行还是CPU运行        ——>        torch.device

5、这里就不用再定义轮次、优化器什么的了,因为已经训练好模型的参数了,只需要将模型训练好的模型权重参数导入即可

model_path="../weight/model.pth"
model.load_state_dict(torch.load(model_path))

6、验证——>model.eval()

7、在进行训练前,关闭梯度计算,因为已经导入了训练好的模型——>with torch.no_grad():

8、计算测试的准确率(和验证类似,只是不再需要关注损失值)

9、打印总的准确率:acc_total.item()/len(val_data)

代码:

#模型验证
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from model1 import NumberModel
#数据预处理
transform1 = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))
])
#数据集
val_data = MNIST(root='../data/MNIST', train=False, transform=transform1, download=False)#加载数据集
val_loader = DataLoader(dataset=val_data,batch_size=32,shuffle=False
)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = NumberModel()
#加载预训练好的权重参数
model_path="../weight/model.pth"
model.load_state_dict(torch.load(model_path))model.to(device)
#验证
model.eval()
#关闭梯度计算
with torch.no_grad():acc_total = 0for idx,(data,target) in enumerate(val_loader):#数据移动到设备data, target = data.to(device), target.to(device)#用模型训练输出类别预测output = model(data)#预测结果,output返回的是(N,10)N表示图片数,10 对应 MNIST 的 10 个类别的得分,# dim取1就是取10这个维度,经过argmax后得到得分值最大得到的索引值,也就是预测的类别pre = torch.argmax(output, dim=1)#利用布尔运算,判断torch.sum(pre==target)acc_total += torch.sum(pre==target)print(f'总准确率为:{acc_total.item()/len(val_data):.3f}')

四、预测

1、先把训练好的模型加载进来

2、加载我们需要预测的图片

3、在预测前对图片进行一个预处理:用cv2读出来的图片是数组类型,且维度不一样,所以要先将nmupy转为张量,然后再升维到和(N,C,H,W)一直

4、将转为张量的图片放入模型进行预测,打印预测得分最大的索引

from model import NumberModel
import torch
import numpy as np
import cv2 as cv# 加载模型
model = NumberModel()
model.load_state_dict(torch.load('../weight/model.pth'))# 加载图片
img = cv.imread('../data/image.png')
# 转为灰度图
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
print(img.shape)
# 转为张量,并升维
img = torch.tensor(img, dtype=torch.float32).unsqueeze(0).unsqueeze(0)
# 预测
out = model(img)
print(out.argmax(dim=1))

http://www.dtcms.com/a/330569.html

相关文章:

  • .NET 的 WebApi 项目必要可配置项都有哪些?
  • CPUcores-【硬核优化】CPU增强解锁全部内核!可优化游戏性能、提升帧数!启用CPU全内核+超线程,以更高优先级运行游戏!支持各种游戏和应用优化~
  • Mybatis学习笔记(四)
  • 【论文阅读】基于卷积神经网络和预提取特征的肌电信号分类
  • CSS isolation属性
  • NVIDIA Nsight Deep Learning Designer使用
  • 第3节 深度学习避坑指南:从过拟合到玄学优化
  • toRefs、storeToRefs实际应用
  • 分布式系统架构设计模式:从微服务到云原生
  • Flutter sqflite插件
  • Day57--图论--53. 寻宝(卡码网)
  • Nacos-4--Nacos1.x长轮询的理解
  • PiscTrace基于YOLO追踪算法的物体速度检测系统详解
  • 【软考中级网络工程师】知识点之入侵防御系统:筑牢网络安全防线
  • 【入门级-算法-2、入门算法:模拟法】
  • 解决“Win7共享文件夹其他电脑网络无法发现共享电脑名称”的问题
  • 融合服务器助力下的电视信息发布直播点播系统革新
  • 服务器装两个cpu
  • 1780. 判断一个数字是否可以表示成三的幂的和
  • MongoDB 从入门到生产:建模、索引、聚合、事务、分片与运维实战(含 Node.js/Python 示例)
  • 基于现代 C++ 的湍流直接数值模拟 (DNS) 并行算法优化与实现
  • 9.【C++进阶】继承
  • 河南萌新联赛2025第(五)场:信息工程大学”(补题)
  • QLab Pro for Mac —— 专业现场音频与多媒体控制软件
  • Boost库中Pool 基础内存池(boost::pool<>)的详细用法解析和实战应用
  • filezilla mac新版本MacOS-12.6.3会自动进入全屏模式BUG解决方法
  • 图论Day2学习心得
  • 支持pcm语音文件缓存顺序播放
  • springBoot+knife4j+openapi3依赖问题参考
  • 图灵测试:人工智能的“行为主义判据”与哲学争议