动手学深度学习(Pytorch版)代码实践 -卷积神经网络-30`Kaggle`竞赛:图片分类

30Kaggle竞赛:图片分类

**比赛链接:**https://www.kaggle.com/c/classify-leaves

导入包
import torch
import torchvision
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
import numpy as np
import pandas as pd
from torch import nn
import matplotlib.pyplot as plt
from PIL import Image
import os
from torch.nn import functional as F
import torch.optim as optim
import liliPytorch as lp
import torchvision.models as models
预处理:数据集分析
train_path = '../data/classify-leaves/train.csv'
test_path = '../data/classify-leaves/test.csv'
file_path = '../data/classify-leaves/'# # 读取训练和测试数据
train_data = pd.read_csv(train_path)
test_data = pd.read_csv(test_path)# 打印数据形状
print(train_data.shape) # (18353, 2)
print(test_data.shape) # (8800, 1)#生成描述性统计数据
print(train_data.describe())
"""image             label
count          18353             18353
unique         18353               176
top     images/0.jpg  maclura_pomifera
freq               1               353
"""# 查看不同树叶的数量
print(train_data['label'].value_counts())
"""
label
maclura_pomifera            353
ulmus_rubra                 235
prunus_virginiana           223
acer_rubrum                 217
broussonettia_papyrifera    214... 
cedrus_deodara               58
ailanthus_altissima          58
crataegus_crus-galli         54
evodia_daniellii             53
juniperus_virginiana         51
Name: count, Length: 176, dtype: int64
"""
1.数据处理与加载
train_path = '../data/classify-leaves/train.csv'
test_path = '../data/classify-leaves/test.csv'
file_path = '../data/classify-leaves/'# 树叶的名字统计
labels_unique = train_data['label'].unique()
# print(labels_unique)# 树叶标签的数量
labels_num = len(labels_unique)# 提取出树叶标签,并排序
leaves_labels = sorted(list(set(train_data['label'])))
# print(leaves_labels)# 将树叶标签对应数字
labels_to_num = dict(zip(leaves_labels, range(labels_num )))
# print(labels_to_num)# 将数字对应树叶标签(用于后续预测)
num_to_labels = {value : key for key, value in labels_to_num.items()}
# print(num_to_labels)class LeavesDataset(Dataset):def __init__(self, csv_path, file_path, mode='train', valid_ratio=0.2, resize_height=224, resize_width=224):"""初始化 LeavesDataset 对象。参数:csv_path (str): 包含图像路径和标签的 CSV 文件路径。file_path (str): 图像文件所在目录的路径。mode (str, optional): 数据集的模式。可以是 'train', 'valid' 或 'test'。默认值为 'train'。valid_ratio (float, optional): 用于验证的数据比例。默认值为 0.2。resize_height (int, optional): 调整图像高度的大小。默认值为 224。resize_width (int, optional): 调整图像宽度的大小。默认值为 224。"""# 存储图像调整大小的高度和宽度self.resize_height = resize_heightself.resize_width = resize_width# 存储图像文件路径和模式(train/valid/test)self.file_path = file_pathself.mode = mode# 读取包含图像路径和标签的 CSV 文件self.data_info = pd.read_csv(csv_path, header=0)# 获取样本总数self.data_len = len(self.data_info.index)# 计算训练集样本数self.train_len = int(self.data_len * (1 - valid_ratio))# 根据模式处理数据if self.mode == 'train':# 训练模式下的图像和标签self.train_img = np.asarray(self.data_info.iloc[0:self.train_len, 0])self.train_label = np.asarray(self.data_info.iloc[0:self.train_len, 1])self.image_arr = self.train_imgself.label_arr = self.train_labelelif self.mode == 'valid':# 验证模式下的图像和标签self.valid_img = np.asarray(self.data_info.iloc[self.train_len:, 0])self.valid_label = np.asarray(self.data_info.iloc[self.train_len:, 1])self.image_arr = self.valid_imgself.label_arr = self.valid_labelelif self.mode == 'test':# 测试模式下的图像self.test_img = np.asarray(self.data_info.iloc[:, 0])self.image_arr = self.test_img# 获取图像数组的长度self.len_image = len(self.image_arr)print(f'扫描所有 {mode} 数据,共 {self.len_image} 张图像')def __getitem__(self, idx):"""获取指定索引的图像和标签。参数: idx (int): 标签文本对应编号的索引返回:如果是测试模式,返回图像张量;否则返回图像张量和标签。"""# 打开图像文件self.img = Image.open(self.file_path + self.image_arr[idx])if self.mode == 'train':# 训练模式下的数据增强trans = transforms.Compose([transforms.Resize((self.resize_height, self.resize_width)),transforms.RandomHorizontalFlip(p=0.5),transforms.RandomVerticalFlip(p=0.5),transforms.RandomRotation(degrees=30),# transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),# transforms.RandomResizedCrop(size=self.resize_height, scale=(0.8, 1.0)),transforms.ToTensor(),# transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])self.img = trans(self.img)else:# 验证和测试模式下的简单处理trans = transforms.Compose([transforms.Resize((self.resize_height, self.resize_width)),transforms.ToTensor(),# transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])self.img = trans(self.img)if self.mode == 'test':return self.imgelse:# 获取标签文本对应的编号self.label = labels_to_num[self.label_arr[idx]]return self.img, self.labeldef __call__(self, idx):"""使对象可以像函数一样被调用。参数:idx (int):标签文本对应编号的索引 返回: 调用 __getitem__ 方法并返回结果。"""return self.__getitem__(idx)def __len__(self):"""获取数据集的长度。返回: 数据集中图像的数量。"""return self.len_imagetrain_dataset = LeavesDataset(train_path, file_path)
valid_dataset = LeavesDataset(train_path, file_path, mode='valid')
test_dataset = LeavesDataset(test_path, file_path, mode='test')
2.模型构建Resnet
class Residual(nn.Module):def __init__(self, input_channels, num_channels, use_1x1conv=False, strides=1):super().__init__()self.conv1 = nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1, stride=strides)self.conv2 = nn.Conv2d(num_channels, num_channels, kernel_size=3, padding=1)if use_1x1conv:self.conv3 = nn.Conv2d(input_channels, num_channels, kernel_size=1, stride=strides)else:self.conv3 = Noneself.bn1 = nn.BatchNorm2d(num_channels)self.bn2 = nn.BatchNorm2d(num_channels)def forward(self, X):Y = F.relu(self.bn1(self.conv1(X)))Y = self.bn2(self.conv2(Y))if self.conv3:X = self.conv3(X)Y += Xreturn F.relu(Y)b1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),nn.BatchNorm2d(64),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)def resnet_block(input_channels, num_channels, num_residuals, first_block=False):blk = []for i in range(num_residuals):if i == 0 and not first_block:blk.append(Residual(input_channels, num_channels, use_1x1conv=True, strides=2))else:blk.append(Residual(num_channels, num_channels))return blk#ResNet34
# b2 = nn.Sequential(*resnet_block(64, 64, 3, first_block=True))
# b3 = nn.Sequential(*resnet_block(64, 128, 4))
# b4 = nn.Sequential(*resnet_block(128, 256, 6))
# b5 = nn.Sequential(*resnet_block(256, 512, 3))#ResNet18
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))net = nn.Sequential(b1, b2, b3, b4, b5,nn.AdaptiveAvgPool2d((1, 1)),nn.Flatten(),nn.Linear(512, labels_num)
)
3.模型训练
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):"""用GPU训练模型参数:net (torch.nn.Module): 要训练的神经网络模型train_iter (torch.utils.data.DataLoader): 训练数据加载器test_iter (torch.utils.data.DataLoader): 测试数据加载器num_epochs (int): 训练的轮数lr (float): 学习率device (torch.device): 计算设备(CPU或GPU)"""# 初始化模型权重def init_weights(m):if(type(m) == nn.Linear or type(m) == nn.Conv2d):nn.init.xavier_uniform_(m.weight)net.apply(init_weights)print('training on', device)net.to(device)# 应用初始化权重函数# optimizer = torch.optim.SGD(net.parameters(), lr = lr)optimizer = torch.optim.Adam(net.parameters(), lr=lr, weight_decay = 0.001)# 每5个epoch学习率减少到原来的0.1倍# scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)  loss = nn.CrossEntropyLoss()   # 损失函数,使用交叉熵损失animator = lp.Animator(xlabel='epoch', xlim=[1, num_epochs],legend=['train loss', 'train acc', 'test acc'])timer, num_batches = lp.Timer(), len(train_iter)for epoch in range(num_epochs):# 训练损失之和,训练准确率之和,样本数metric = lp.Accumulator(3)net.train() #训练模式for i, (X, y) in enumerate(train_iter):timer.start()optimizer.zero_grad() # 梯度清零X, y = X.to(device), y.to(device)y_hat = net(X)# 前向传播l = loss(y_hat, y) # 计算损失l.backward()# 反向传播optimizer.step() # 更新参数with torch.no_grad():metric.add(l * X.shape[0], lp.accuracy(y_hat, y), X.shape[0]) # 更新指标timer.stop()train_l = metric[0] / metric[2] # 计算训练损失train_acc = metric[1] / metric[2] # 计算训练准确率# 每训练完一个批次或每5个批次更新动画if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:animator.add(epoch + (i + 1) / num_batches,(train_l, train_acc, None))# 在验证集上计算准确率test_acc = lp.evaluate_accuracy_gpu(net, test_iter, device)animator.add(epoch + 1, (None, None, test_acc))# 打印当前epoch的训练损失,训练准确率和测试准确率print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, 'f'test acc {test_acc:.3f}')# scheduler.step()animator.show()print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, 'f'test acc {test_acc:.3f}')print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec 'f'on {str(device)}')# 打印每秒处理的样本数# 超参数设置
lr, num_epochs, batch_size = 1e-5, 120, 128# 数据加载器
train_iter = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
valid_iter = DataLoader(valid_dataset, batch_size=batch_size, shuffle=False, num_workers=4)train_ch6(net, train_iter, valid_iter, num_epochs, lr, lp.try_gpu())
plt.show()# 保存模型参数
file_path_module = '../limuPytorch/module/'
torch.save(net.state_dict(), file_path_module + 'classify_leaves.params')
4.训练调参
resNet-18,num_epochs = 10,lr=1e-4,
loss 2.239, train acc 0.429, test acc 0.149
444.5 examples/sec on cuda:0resNet-34, num_epochs = 10,lr=1e-4
loss 1.991, train acc 0.443, test acc 0.147
270.7 examples/sec on cuda:0resNet-34,num_epochs = 50,lr=1e-4,train数据增强,使用Adam
loss 0.281, train acc 0.914, test acc 0.378
244.6 examples/sec on cuda:0resNet-34,num_epochs = 50,lr=1e-5,train数据增强,使用Adam
loss 0.189, train acc 0.925, test acc 0.398
258.0 examples/sec on cuda:0resNet-18,num_epochs = 50,lr=1e-4,train数据增强,使用Adam
loss 0.199, train acc 0.955, test acc 0.338
458.0 examples/sec on cuda:0resNet-18,num_epochs = 50,lr=1e-4,train数据增强,调整数据集比例82
数据增强过度导致测试准确率(test accuracy)曲线上下震荡resNet-18,num_epochs = 50,lr=1e-4,train数据增强,调整数据集比例为82
数据增强过度导致测试准确率(test accuracy)曲线上下震荡resNet-18,num_epochs = 50,lr=1e-4,train数据增强(仅旋转),调整数据集比例为82
loss 0.129, train acc 0.966, test acc 0.838
350.7 examples/sec on cuda:0resNet-18,num_epochs = 50,lr=1e-5,train数据增强,调整数据集比例为82
loss 0.808, train acc 0.788, test acc 0.701
420.6 examples/sec on cuda:0resNet-18,num_epochs = 100,lr=1e-5,train数据增强,调整数据集比例为82
loss 0.285, train acc 0.927, test acc 0.825
409.2 examples/sec on cuda:0
5.模型预测
 def predict(model, data_loader, device):"""使用模型进行预测参数:model (torch.nn.Module): 要进行预测的模型data_loader (torch.utils.data.DataLoader): 数据加载器,用于提供待预测的数据device (torch.device): 计算设备(CPU或GPU)返回: all_preds (list): 包含所有预测结果的列表"""all_preds = []  # 存储所有预测结果model.to(device)  # 将模型移动到指定设备model.eval()  # 设置模型为评估模式with torch.no_grad():  # 在不需要计算梯度的上下文中进行for X in data_loader:  # 遍历数据加载器X = X.to(device)  # 将数据移动到指定设备outputs = model(X)  # 前向传播,计算模型输出_, preds = torch.max(outputs, 1)  # 获取预测结果all_preds.extend(preds.cpu().numpy())  # 将预测结果添加到列表中return all_preds  # 返回所有预测结果# 克隆模型clone_net = net# 加载预训练模型参数clone_net.load_state_dict(torch.load(file_path_module + 'classify_leaves.params'))# 创建验证集的数据加载器valid_iter = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=2)# 进行预测predictions = predict(clone_net, valid_iter, lp.try_gpu())# 将预测结果映射到标签for i in predictions:predictions.append(num_to_labels[int(i)])# 读取测试数据test_data = pd.read_csv(test_path)# 将预测结果添加到测试数据中test_data['label'] = pd.Series(predictions)# 创建提交文件submission = pd.concat([test_data['image'], test_data['label']], axis=2)# 保存提交文件submission.to_csv(file_path + 'submission.csv', index=False)
7.扩展学习
# 模型构建
# 加载预训练的ResNet-18模型
#加载一个预训练的ResNet-18模型,这个模型已经在ImageNet数据集上进行了预训练。
#可以利用其提取特征的能力。
pretrained_net = models.resnet18(pretrained=True)# 克隆预训练的ResNet-18模型,用于分类叶子数据集
classify_leaves_net = pretrained_net# 修改最后的全连接层,将其输出特征数改为176(有176个类别)
# classify_leaves_net.fc.in_features 获取原始全连接层的输入特征数。
classify_leaves_net.fc = nn.Linear(classify_leaves_net.fc.in_features, 176)# 使用Xavier均匀分布初始化新的全连接层的权重
nn.init.xavier_uniform_(classify_leaves_net.fc.weight)# 模型训练部分更改优化器
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device,param_group=True):"""param_group (bool, optional): 是否对参数进行分组设置不同的学习率。默认值为True"""# optimizer = torch.optim.SGD(net.parameters(), lr = lr)# optimizer = torch.optim.Adam(net.parameters(), lr=lr, weight_decay = 0.001)if param_group:# 如果参数分组设置为True,分离出最后一层全连接层的参数# 列表params_1x,包含除最后一层全连接层外的所有参数。params_1x = [param for name, param in net.named_parameters()if name not in ["fc.weight", "fc.bias"]]optimizer = torch.optim.Adam([{'params': params_1x},  # 其他层的参数使用默认学习率{'params': net.fc.parameters(), 'lr': lr * 10}  # 全连接层的参数使用更高的学习率], lr=lr, weight_decay=0.001)else:# 如果参数分组设置为False,所有参数使用相同的学习率optimizer = torch.optim.Adam(net.parameters(), lr=lr, weight_decay=0.001)

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

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

相关文章

pytest测试框架flaky插件重试失败用例

Pytest提供了丰富的插件来扩展其功能,本章介绍下插件flaky ,用于在测试用例失败时自动重新运行这些测试用例。与前面文章介绍的插件pytest-rerunfailures功能有些类似,但是功能上不如pytest-rerunfailures插件丰富。 flaky官方并没有明确pyt…

【FFmpeg】AVCodecContext结构体

【FFmpeg】AVCodecContext结构体 1. AVCodecContext的定义1.1 struct AVCodecInternal *internal1.1.1 struct FramePool *pool 参考: FFMPEG结构体分析:AVCodecContext 示例工程: 【FFmpeg】调用ffmpeg库实现264软编 【FFmpeg】调用ffmpeg库…

SSM框架 --- SpringMVC --- exercise1

1.创建Maven项目 2.导入依赖&#xff08;导入SpringMvc与Servlet的坐标&#xff09;&#xff1a; <dependencies> <!--servlet依赖的坐标--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId&…

git stash Pop 后丢失,要如何找回?

文章目录 须知背景描述解决过程 须知 写在前面&#xff1a;我们都知道 stash list 中如果 pop 出来一条&#xff0c;那 list 里就会少一条&#xff0c;但其实使用 git stash pop 并没有真正地将该条 stash 删掉的&#xff0c;而是删除引用而已&#xff0c;因此当我们误 pop 时…

AI在软件开发中的应用

AI在软件开发中的应用可以帮助开发人员更高效地编写和测试代码&#xff0c;并提高软件的质量和性能。它能够帮助加快软件的部署和维护过程&#xff0c;提供更好的开发体验。 编码辅助 帮助开发人员更快地编写代码。例如&#xff0c;AI可以识别代码中的语法错误&#xff0c;并提…

WSL+Anconda(pytorch深度学习)环境配置

动机 最近在读point cloud相关论文&#xff0c;准备拉github上相应的code跑一下&#xff0c;但是之前没有深度学习的经验&#xff0c;在配置环境方面踩了超级多的坑&#xff0c;依次来记录一下。 一开始我直接将code拉到了windows本地来运行&#xff0c;遇到了数不清的问题&a…

LoRaWAN网关源代码分析(基础概念篇)

目录 一、简介 1、lora_gateway 2、packet_forwarder 二、目录结构 1、lora_gateway 2、packet_forwarder 一、简介 LoRaWAN网关的实现主要依赖两个源代码&#xff1a;lora_gateway和packet_forwarder。接下来&#xff0c;我们将从分析源代码入手&#xff0c;移植LoRaWAN源…

ThinkPHP:查询数据库数据之后,更改查询数据的字段名称

一、原始查询数据 含有字段item_no&#xff0c;lot_num&#xff0c;position $data[brushed] db::table(wip_station_transaction) ->where([wip_entity_name>$wip_entity_name,line_code>$line_code,]) ->field([item_no, lot_num, position]) ->select(); …

DAC测试实验——FPGA学习笔记7

一、DAC简介 DAC全称Digital to Analog Converter&#xff0c;即数模转换器。它用于将主控芯片产生的数字值(0和1)转换为模拟值(电压值)。 1、DAC参数指标 2、DAC类型 常用的DAC可大致分为权电阻网络DAC、T型电阻网络DAC、倒T型电阻网络DAC以及权电流型DAC。 3、AD9708/3PD9…

ChatGPT 简介

ChatGPT 是一种基于大型语言模型的对话系统&#xff0c;由 OpenAI 开发。它的核心是一个深度学习模型&#xff0c;使用了 GPT&#xff08;Generative Pre-trained Transformer&#xff09;架构。以下是 ChatGPT 的原理和工作机制的详细介绍&#xff1a; ### GPT 架构 1. **Tr…

Linux - 记一次某Java程序启动报错(申请内存失败)

文章目录 问题可能原因分析可能原因分析尝试各种解决方案尝试解决过程 解决办法&#xff1a; 调整 overcommit_meory参数overcommit_memory详解什么是 overcommit_memory&#xff1f;overcommit_memory 的选项及其含义配置 overcommit_memory查看当前设置设置 overcommit_memor…

github-chinese,跟英文GitHub说拜拜

背景 对于我们程序员来说,Github是一个常逛的web网站,里面学习资源众多,不管是查问题还是查资料都离不开他。 但是Github作为一个国际化的网站,语言主要是英语,所以对于一些英语似懂非懂的同学来说还是有一些难处。 想过找一个国内中文的Github作为一个平替网站,但是资…

访问网站时IP被屏蔽是什么原因?

在互联网使用中&#xff0c;有时我们可能会遇到访问某个网站时IP地址被屏蔽的情况。IP地址被网站屏蔽是一个相对常见的现象&#xff0c;而导致这种情况的原因多种多样&#xff0c;包括恶意行为、违规访问等。本文将解释IP地址被网站屏蔽的常见原因&#xff0c;同时&#xff0c;…

【AI原理解析】— 小模型(总述)

目录 1. 线性模型 2. 决策树 3. 朴素贝叶斯 4. 小型神经网络 5. 多模态小模型&#xff08;特定类型的小型神经网络&#xff09; 1. 线性模型 原理&#xff1a; 线性模型是试图通过属性的线性组合来进行预测的函数。其表达式可以表示为 y w^T * x b&#xff0c;其中w和b…

Day 30:100346. 使二进制数组全部等于1的最小操作次数Ⅱ

Leetcode 100346. 使二进制数组全部等于1的最小操作次数Ⅱ 给你一个二进制数组 nums 。 你可以对数组执行以下操作 任意 次&#xff08;也可以 0 次&#xff09;&#xff1a; 选择数组中 任意 一个下标 i &#xff0c;并将从下标 i 开始一直到数组末尾 所有 元素 反转 。 反转 …

Kafka 集群元数据之Zookeeper存储介绍

Kafka 集群元数据之Zookeeper存储介绍? 在 Kafka 集群中,ZooKeeper 存储了大量的元数据,管理和协调 Kafka 的各个组件。以下是 ZooKeeper 中创建 的主要信息及其作用: 1. Broker 信息 路径: /brokers/ids/[broker_id]/brokers/topics/[topic_name]/brokers/seqid作用:…

平面设计软件PS/AI/ID/CDR怎么选怎么下载(附教程)

随着设计行业的普遍化&#xff0c;平面设计软件也越来越多且功能越来越强大。平面设计软件需要在电脑上运行使用&#xff0c;来进行平面画面、平面文字的设计工作。如大家所了解的&#xff0c;Adobe Photoshop、Adobe Illustrator、CorelDRAW、Adobe InDesign是平面设计中最常用…

Kubernetes相关生态

1、Prometheus、Metrics Server与Kubernetes监控体系 简介&#xff1a; Prometheus 项目与 Kubernetes 项目一样&#xff0c;也来自于 Google 的 Borg 体系&#xff0c;它的原型系统&#xff0c;叫作 BorgMon&#xff0c;是一个几乎与 Borg 同时诞生的内部监控系统 Pro…

数学概念之集合

简介 集合(Set)是一种数学概念,在编程中也被广泛使用。它可以被定义为一个无序、不重复的元素的集合。下面我们更详细地来介绍集合: 什么是集合? 集合是由一些确定的、互不相同的元素组成的整体。集合中的元素是无序的,即元素之间没有先后关系。集合中的元素是唯一的,即不能…

MQTT服务器/MQTT_C#客户端/Websoket连MQTT

1 . 搭建MQTT服务器 找到上传中的 emqx-5.3.2-windows-amd64 打开bin如下: 链接: emqx-5.3.2-windows-amd64 如果安装失败 在上传中找到链接: VC_redist.x64.exe 安装。 正确后在浏览器输入 http://127.0.0.1:18083 会有如下mqtt服务端管理页面: 进入客户端认证,创建一个…