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

机器学习第4周:猴痘病识别

  • 🍨本文为🔗365天深度学习训练营中的学习记录博客
  • 🍖原作者:
  • 语言环境:Python3.13
  • 编译器:jupyter notebook
  • 深度学习环境:Pytorch

一 准备工作

设置CPU模式

1 导入数据

import os,PIL,random,pathlib data_dir = './4-data/' data_dir = pathlib.Path(data_dir) data_paths = list(data_dir.glob('*')) classeNames = [str(path).split("\\")[1] for path in data_paths] classeNames

输出:

['Monkeypox', 'Others']
  • 第一步:使用pathlib.Path()函数将字符串类型的文件夹路径转换为pathlib.Path对象。
  • 第二步:使用glob()方法获取data_dir路径下的所有文件路径,并以列表形式存储在data_paths中。
  • 第三步:通过split()函数对data_paths中的每个文件路径执行分割操作,获得各个文件所属的类别名称,并存储在classeNames
  • 第四步:打印classeNames列表,显示每个文件所属的类别名称。
total_datadir = './4-data/' # 关于transforms.Compose的更多介绍可以参考:https://blog.csdn.net/qq_38251616/article/details/124878863 train_transforms = transforms.Compose([ transforms.Resize([224, 224]), # 将输入图片resize成统一尺寸 transforms.ToTensor(), # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间 transforms.Normalize( # 标准化处理-->转换为标准正态分布(高斯分布),使模型更容易收敛 mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。 ]) total_data = datasets.ImageFolder(total_datadir,transform=train_transforms) total_data

mean与std数值来源见上一篇笔记

total_data.class_to_idx

代码输出

{'Monkeypox': 0, 'Others': 1}

total_data.class_to_idx是一个存储了数据集类别和对应索引的字典。在PyTorch的ImageFolder数据加载器中,根据数据集文件夹的组织结构,每个文件夹代表一个类别,class_to_idx字典将每个类别名称映射为一个数字索引。

具体来说,如果数据集文件夹包含两个子文件夹,比如Monkeypox和Others,class_to_idx字典将返回类似以下的映射关系:{'Monkeypox': 0, 'Others': 1}

2 划分数据集

train_size = int(0.8 * len(total_data)) test_size = len(total_data) - train_size train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size]) train_dataset, test_dataset

代码输出

(<torch.utils.data.dataset.Subset at 0x1487e6a0590>, <torch.utils.data.dataset.Subset at 0x14820775310>)
train_size,test_size

输出

(1713, 429)
batch_size = 32 train_dl = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=1) test_dl = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=True, num_workers=1)
for X, y in test_dl: print("Shape of X [N, C, H, W]: ", X.shape) print("Shape of y: ", y.shape, y.dtype) break

输出

Shape of X [N, C, H, W]: torch.Size([32, 3, 224, 224]) Shape of y: torch.Size([32]) torch.int64

torch.utils.data.DataLoader()参数详解

torch.utils.data.DataLoader是 PyTorch 中用于加载和管理数据的一个实用工具类。它允许你以小批次的方式迭代你的数据集,这对于训练神经网络和其他机器学习任务非常有用。DataLoader构造函数接受多个参数,下面是一些常用的参数及其解释:

  1. dataset(必需参数):这是你的数据集对象,通常是torch.utils.data.Dataset的子类,它包含了你的数据样本。
  2. batch_size(可选参数):指定每个小批次中包含的样本数。默认值为 1。
  3. shuffle(可选参数):如果设置为True,则在每个 epoch 开始时对数据进行洗牌,以随机打乱样本的顺序。这对于训练数据的随机性很重要,以避免模型学习到数据的顺序性。默认值为False
  4. num_workers(可选参数):用于数据加载的子进程数量。通常,将其设置为大于 0 的值可以加快数据加载速度,特别是当数据集很大时。默认值为 0,表示在主进程中加载数据。
  5. pin_memory(可选参数):如果设置为True,则数据加载到 GPU 时会将数据存储在 CUDA 的锁页内存中,这可以加速数据传输到 GPU。默认值为False
  6. drop_last(可选参数):如果设置为True,则在最后一个小批次可能包含样本数小于batch_size时,丢弃该小批次。这在某些情况下很有用,以确保所有小批次具有相同的大小。默认值为False
  7. timeout(可选参数):如果设置为正整数,它定义了每个子进程在等待数据加载器传递数据时的超时时间(以秒为单位)。这可以用于避免子进程卡住的情况。默认值为 0,表示没有超时限制。
  8. worker_init_fn(可选参数):一个可选的函数,用于初始化每个子进程的状态。这对于设置每个子进程的随机种子或其他初始化操作很有用。

二 构建CNN网络

import torch.nn.functional as F class Network_bn(nn.Module): def __init__(self): super(Network_bn, self).__init__() """ nn.Conv2d()函数: 第一个参数(in_channels)是输入的channel数量 第二个参数(out_channels)是输出的channel数量 第三个参数(kernel_size)是卷积核大小 第四个参数(stride)是步长,默认为1 第五个参数(padding)是填充大小,默认为0 """ self.conv1 = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=5, stride=1, padding=0) self.bn1 = nn.BatchNorm2d(12) self.conv2 = nn.Conv2d(in_channels=12, out_channels=12, kernel_size=5, stride=1, padding=0) self.bn2 = nn.BatchNorm2d(12) self.pool = nn.MaxPool2d(2,2) self.conv4 = nn.Conv2d(in_channels=12, out_channels=24, kernel_size=5, stride=1, padding=0) self.bn4 = nn.BatchNorm2d(24) self.conv5 = nn.Conv2d(in_channels=24, out_channels=24, kernel_size=5, stride=1, padding=0) self.bn5 = nn.BatchNorm2d(24) self.fc1 = nn.Linear(24*50*50, len(classeNames)) def forward(self, x): x = F.relu(self.bn1(self.conv1(x))) x = F.relu(self.bn2(self.conv2(x))) x = self.pool(x) x = F.relu(self.bn4(self.conv4(x))) x = F.relu(self.bn5(self.conv5(x))) x = self.pool(x) x = x.view(-1, 24*50*50) x = self.fc1(x) return x device = "cuda" if torch.cuda.is_available() else "cpu" print("Using {} device".format(device)) model = Network_bn().to(device) model

输出

Using cuda device
Network_bn( (conv1): Conv2d(3, 12, kernel_size=(5, 5), stride=(1, 1)) (bn1): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, bias=True, track_running_stats=True) (conv2): Conv2d(12, 12, kernel_size=(5, 5), stride=(1, 1)) (bn2): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, bias=True, track_running_stats=True) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv4): Conv2d(12, 24, kernel_size=(5, 5), stride=(1, 1)) (bn4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, bias=True, track_running_stats=True) (conv5): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1)) (bn5): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, bias=True, track_running_stats=True) (fc1): Linear(in_features=60000, out_features=2, bias=True) )

三 训练模型

设置超参数

loss_fn = nn.CrossEntropyLoss() # 创建损失函数 learn_rate = 1e-4 # 学习率 opt = torch.optim.SGD(model.parameters(),lr=learn_rate)

编写训练函数

# 训练循环 def train(dataloader, model, loss_fn, optimizer): size = len(dataloader.dataset) # 训练集的大小,一共60000张图片 num_batches = len(dataloader) # 批次数目,1875(60000/32) train_loss, train_acc = 0, 0 # 初始化训练损失和正确率 for X, y in dataloader: # 获取图片及其标签 X, y = X.to(device), y.to(device) # 计算预测误差 pred = model(X) # 网络输出 loss = loss_fn(pred, y) # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失 # 反向传播 optimizer.zero_grad() # grad属性归零 loss.backward() # 反向传播 optimizer.step() # 每一步自动更新 # 记录acc与loss train_acc += (pred.argmax(1) == y).type(torch.float).sum().item() train_loss += loss.item() train_acc /= size train_loss /= num_batches return train_acc, train_loss

编写测试函数

def test (dataloader, model, loss_fn): size = len(dataloader.dataset) # 测试集的大小,一共10000张图片 num_batches = len(dataloader) # 批次数目,313(10000/32=312.5,向上取整) test_loss, test_acc = 0, 0 # 当不进行训练时,停止梯度更新,节省计算内存消耗 with torch.no_grad(): for imgs, target in dataloader: imgs, target = imgs.to(device), target.to(device) # 计算loss target_pred = model(imgs) loss = loss_fn(target_pred, target) test_loss += loss.item() test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item() test_acc /= size test_loss /= num_batches return test_acc, test_loss

正式训练

epochs = 20 train_loss = [] train_acc = [] test_loss = [] test_acc = [] for epoch in range(epochs): model.train() epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt) model.eval() epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn) train_acc.append(epoch_train_acc) train_loss.append(epoch_train_loss) test_acc.append(epoch_test_acc) test_loss.append(epoch_test_loss) template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%,Test_loss:{:.3f}') print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss)) print('Done')

输出

Epoch: 1, Train_acc:92.4%, Train_loss:0.254, Test_acc:80.4%,Test_loss:0.456 Epoch: 2, Train_acc:93.4%, Train_loss:0.244, Test_acc:80.4%,Test_loss:0.438 Epoch: 3, Train_acc:93.6%, Train_loss:0.232, Test_acc:79.5%,Test_loss:0.451 Epoch: 4, Train_acc:93.8%, Train_loss:0.232, Test_acc:80.9%,Test_loss:0.429 Epoch: 5, Train_acc:93.2%, Train_loss:0.229, Test_acc:80.9%,Test_loss:0.424 Epoch: 6, Train_acc:94.2%, Train_loss:0.222, Test_acc:81.8%,Test_loss:0.422 Epoch: 7, Train_acc:94.2%, Train_loss:0.217, Test_acc:80.7%,Test_loss:0.432 Epoch: 8, Train_acc:94.0%, Train_loss:0.215, Test_acc:82.8%,Test_loss:0.430 Epoch: 9, Train_acc:94.8%, Train_loss:0.210, Test_acc:82.3%,Test_loss:0.426 Epoch:10, Train_acc:95.2%, Train_loss:0.200, Test_acc:81.6%,Test_loss:0.418 Epoch:11, Train_acc:95.2%, Train_loss:0.196, Test_acc:82.5%,Test_loss:0.407 Epoch:12, Train_acc:95.3%, Train_loss:0.196, Test_acc:83.0%,Test_loss:0.413 Epoch:13, Train_acc:96.1%, Train_loss:0.192, Test_acc:82.1%,Test_loss:0.427 Epoch:14, Train_acc:95.6%, Train_loss:0.185, Test_acc:83.0%,Test_loss:0.400 Epoch:15, Train_acc:96.5%, Train_loss:0.181, Test_acc:83.0%,Test_loss:0.396 Epoch:16, Train_acc:96.1%, Train_loss:0.180, Test_acc:83.2%,Test_loss:0.399 Epoch:17, Train_acc:96.4%, Train_loss:0.173, Test_acc:80.9%,Test_loss:0.431 Epoch:18, Train_acc:96.8%, Train_loss:0.166, Test_acc:82.8%,Test_loss:0.402 Epoch:19, Train_acc:96.1%, Train_loss:0.166, Test_acc:82.1%,Test_loss:0.398 Epoch:20, Train_acc:97.3%, Train_loss:0.161, Test_acc:82.8%,Test_loss:0.414 Done

四、 结果可视化

1. Loss与Accuracy图

import matplotlib.pyplot as plt #隐藏警告 import warnings warnings.filterwarnings("ignore") #忽略警告信息 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 plt.rcParams['figure.dpi'] = 100 #分辨率 from datetime import datetime current_time = datetime.now() # 获取当前时间 epochs_range = range(epochs) plt.figure(figsize=(12, 3)) plt.subplot(1, 2, 1) plt.plot(epochs_range, train_acc, label='Training Accuracy') plt.plot(epochs_range, test_acc, label='Test Accuracy') plt.legend(loc='lower right') plt.title('Training and Validation Accuracy') plt.xlabel(current_time) # 打卡请带上时间戳,否则代码截图无效 plt.subplot(1, 2, 2) plt.plot(epochs_range, train_loss, label='Training Loss') plt.plot(epochs_range, test_loss, label='Test Loss') plt.legend(loc='upper right') plt.title('Training and Validation Loss') plt.show()

2 指定图片进行预测

torch.squeeze()详解

对数据的维度进行压缩,去掉维数为1的的维度

函数原型:

torch.squeeze(input, dim=None, *, out=None)

关键参数说明:

  • input (Tensor):输入Tensor
  • dim (int, optional):如果给定,输入将只在这个维度上被压缩
>>> x = torch.zeros(2, 1, 2, 1, 2) >>> x.size() torch.Size([2, 1, 2, 1, 2]) >>> y = torch.squeeze(x) >>> y.size() torch.Size([2, 2, 2]) >>> y = torch.squeeze(x, 0) >>> y.size() torch.Size([2, 1, 2, 1, 2]) >>> y = torch.squeeze(x, 1) >>> y.size() torch.Size([2, 2, 1, 2])

输出

torch.Size([2, 2, 1, 2])
from PIL import Image classes = list(total_data.class_to_idx) def predict_one_image(image_path, model, transform, classes): test_img = Image.open(image_path).convert('RGB') # plt.imshow(test_img) # 展示预测的图片 test_img = transform(test_img) img = test_img.to(device).unsqueeze(0) model.eval() output = model(img) _,pred = torch.max(output,1) pred_class = classes[pred] print(f'预测结果是:{pred_class}')
# 预测训练集中的某张照片 predict_one_image(image_path='./4-data/Monkeypox/M01_01_00.jpg', model=model, transform=train_transforms, classes=classes)
预测结果是:Monkeypox

五 保存模型

# 模型保存 PATH = './model.pth' # 保存的参数文件名 torch.save(model.state_dict(), PATH) # 将参数加载到model当中 model.load_state_dict(torch.load(PATH, map_location=device))

输出

<All keys matched successfully>

六 验证模型

首先加载模型

import torch import torch.nn as nn import torchvision.transforms as transforms import torchvision from torchvision import transforms, datasets import os,PIL,pathlib device = torch.device("cuda" if torch.cuda.is_available() else "cpu") import os,PIL,random,pathlib data_dir = './4-data/' data_dir = pathlib.Path(data_dir) data_paths = list(data_dir.glob('*')) classeNames = [str(path).split("\\")[1] for path in data_paths] total_datadir = './4-data/' # 关于transforms.Compose的更多介绍可以参考:https://blog.csdn.net/qq_38251616/article/details/124878863 train_transforms = transforms.Compose([ transforms.Resize([224, 224]), # 将输入图片resize成统一尺寸 transforms.ToTensor(), # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间 transforms.Normalize( # 标准化处理-->转换为标准正态分布(高斯分布),使模型更容易收敛 mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。 ]) total_data = datasets.ImageFolder(total_datadir,transform=train_transforms) import os,PIL,random,pathlib import torch.nn.functional as F class Network_bn(nn.Module): def __init__(self): super(Network_bn, self).__init__() """ nn.Conv2d()函数: 第一个参数(in_channels)是输入的channel数量 第二个参数(out_channels)是输出的channel数量 第三个参数(kernel_size)是卷积核大小 第四个参数(stride)是步长,默认为1 第五个参数(padding)是填充大小,默认为0 """ self.conv1 = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=5, stride=1, padding=0) self.bn1 = nn.BatchNorm2d(12) self.conv2 = nn.Conv2d(in_channels=12, out_channels=12, kernel_size=5, stride=1, padding=0) self.bn2 = nn.BatchNorm2d(12) self.pool = nn.MaxPool2d(2,2) self.conv4 = nn.Conv2d(in_channels=12, out_channels=24, kernel_size=5, stride=1, padding=0) self.bn4 = nn.BatchNorm2d(24) self.conv5 = nn.Conv2d(in_channels=24, out_channels=24, kernel_size=5, stride=1, padding=0) self.bn5 = nn.BatchNorm2d(24) self.fc1 = nn.Linear(24*50*50, len(classeNames)) def forward(self, x): x = F.relu(self.bn1(self.conv1(x))) x = F.relu(self.bn2(self.conv2(x))) x = self.pool(x) x = F.relu(self.bn4(self.conv4(x))) x = F.relu(self.bn5(self.conv5(x))) x = self.pool(x) x = x.view(-1, 24*50*50) x = self.fc1(x) return x model = Network_bn().to(device) PATH = './model.pth' # 保存的参数文件名 model.load_state_dict(torch.load(PATH, map_location=device)) from PIL import Image classes = list(total_data.class_to_idx) def predict_one_image(image_path, model, transform, classes): test_img = Image.open(image_path).convert('RGB') # plt.imshow(test_img) # 展示预测的图片 test_img = transform(test_img) img = test_img.to(device).unsqueeze(0) model.eval() output = model(img) _,pred = torch.max(output,1) pred_class = classes[pred] print(f'预测结果是:{pred_class}')

验证图片

predict_one_image(image_path='./4-data/Others/NM01_01_00.jpg', model=model, transform=train_transforms, classes=classes)

输出:

预测结果是:Others
http://www.jsqmd.com/news/961688/

相关文章:

  • AI Slop 正在吞噬互联网:当生成式泛滥成为技术社区的隐形杀手
  • BEVFormer TensorRT部署工具包:含INT8量化流程、CUDA自定义算子源码与Docker一键构建环境
  • FOC轮腿机器人:嵌入式运动控制系统的技术实现与创新
  • MuleSoft与LangChain协同架构:企业级AI中台的工程实践
  • 2026 芜湖防水补漏瓷砖空鼓修复推荐,苏易修缮本土直营,长江圩区汛期返渗皖南丘陵山泉渗水梅季高湿闷泡冬夏温差裂漏软基沉降翘砖就近微创修 - 苏易修缮
  • LabVIEW串口调试助手开发:从数据流原理到工程实践
  • Atom简体中文汉化包:为开发者打造无障碍编程体验的本地化解决方案
  • 2026 铜陵防水补漏瓷砖空鼓修复推荐,苏易修缮本土直营,长江汛期江水顶渗皖南超长梅雨矿区岩溶沉降南部丘陵山体渗水冬夏温差开裂沿江滨湖软基翘砖就近微创修 - 苏易修缮
  • 8D报告怎么写
  • 深度解析FOC轮腿机器人:从零构建智能平衡机器人的完整攻略
  • MATLAB版LDPC码实战包:从随机H矩阵生成到LLR-BP译码及BER曲线绘制
  • 电源设计实战宝典:从EMC、安规到PCB布局的工程师指南
  • 上市智慧食堂厂家盘点:从资质到落地的客观对比 - 互联网科技品牌测评
  • 高云GW1NSR-4C SoC开发环境搭建:从FPGA到ARM Cortex-M3的全流程指南
  • 别死记定义了!用‘家族辈分图’和‘公司层级’来理解哈斯图中的上下界与确界
  • 2026年PDF压缩到最小全方案:保姆级教程+免费工具+Adobe专业设置
  • 终极键盘连击解决方案:免费开源工具KeyboardChatterBlocker完整指南
  • 湖北心理健康指导师怎么报?2026最新政策、考试难度与拿证流程 - 教育推荐官【官方】
  • C/C++混合编程:extern “C“解决链接错误与符号管理
  • FPGA底层优化:利用逻辑单元控制信号实现MUX面积优化
  • 如何高效提交第一个开源 PR?从 Fork 到 Merge 的完整实战指南(附模板)
  • 东北师范大学考研辅导班怎么选?靠谱机构推荐与横向评测 - 推荐评测师
  • LinkSwift网盘直链下载助手:告别限速,实现高速下载自由的终极指南
  • 负反馈电路分析:瞬时极性法与四大经典架构实战指南
  • 2026年拉链源头厂家实力解析:金属拉链、树脂拉链、尼龙拉链等全品类供应商评估 - 品牌企业推荐师(官方)
  • 3个颠覆性功能:Obsidian Excel插件如何重塑你的笔记数据管理
  • Adobe-GenP 3.0终极指南:5分钟快速激活Adobe创意套件
  • 如何快速解决Paradox游戏模组冲突:智能模组管理工具的终极指南
  • 物联网操作系统技术讲座深度解析:从理论到实战的竞赛赋能
  • 四轴飞行器PID控制进阶:从单环到串级PID的实战调参指南