手机网站开发企业,三打哈网络推广平台,做商品二维码检测的网站,网站首页焦点图说实话网上很多关于叶子分类比赛的代码能取得的成绩都很好,但对于我这个业余人员太专业了#xff0c;而且很多文章都有自己的想法#xff0c;这让我这个仿写沐神代码的小菜鸡甚是头痛。 但好在我还是完成了#xff0c;虽然结果并不是很好#xff0c;但是如果跟着沐神走的同…说实话网上很多关于叶子分类比赛的代码能取得的成绩都很好,但对于我这个业余人员太专业了而且很多文章都有自己的想法这让我这个仿写沐神代码的小菜鸡甚是头痛。 但好在我还是完成了虽然结果并不是很好但是如果跟着沐神走的同学在学习上应该没什么大问题。于是这篇文章的重点不是调参获得一个好成绩而是把牵扯到的难点与思路好好的解释一下方便同学们模仿。
竞赛地址:https://www.kaggle.com/c/classify-leaves 文章目录 第一部分 加载并读取数据第二部分 定义网络第三部分 损失函数,验证函数,优化器第四部分 训练可能出现的bug拓展内容正常加载图像数据的其他方式类别索引在做什么train_iter迭代器在迭代时__getitem_在干什么 第一部分 加载并读取数据 难点:如何接受并处理图像数据–使用自定义函数进行处理 import os
import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Imageclass CustomDataset(Dataset):def __init__(self, csv_file, root_dir, transformNone):初始化数据集。Args:csv_file (str): 数据集的csv文件路径其中包含图像的文件名和标签。root_dir (str): 图像文件的根目录路径。transform (callable, optional): 一个可选的转换函数用来对图像进行处理。# 读取csv文件并将数据存储到pandas DataFrame中。self.data_frame pd.read_csv(csv_file)# 存储图像文件的根目录路径。self.root_dir root_dir# 存储可选的图像转换函数。self.transform transform# 将字符串类型的标签转换为整数索引同时获取标签到整数索引的映射。self.data_frame[label], self.label_mapping pd.factorize(self.data_frame[label])def __len__(self):返回数据集中的样本数。return len(self.data_frame)def __getitem__(self, idx):根据给定的索引idx获取对应的数据项。Args:idx (int): 数据项的索引。Returns:tuple: 包含图像和其对应标签的元组。# 如果idx是torch tensor类型先转换为列表。if torch.is_tensor(idx):idx idx.tolist()# 构建图像文件的完整路径。img_name os.path.join(self.root_dir, self.data_frame.iloc[idx, 0])# 打开图像文件。image Image.open(img_name)# 获取对应的标签整数索引。label self.data_frame.iloc[idx, 1]# 如果有转换函数应用之。if self.transform:image self.transform(image)# 返回图像和标签。return image, labeldef get_num_classes(self):返回数据集中不同类别的总数。return len(self.label_mapping)transform transforms.Compose([transforms.Resize(256),transforms.RandomRotation(20),transforms.RandomHorizontalFlip(),transforms.CenterCrop(224),transforms.ColorJitter(brightness0.5, contrast0.5, saturation0.5),transforms.ToTensor(),transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225])
])# 创建图像数据集实例
dataset CustomDataset(csv_fileC:/Users/xiaox/pytorch/SucTest/train.csv,root_dirC:/Users/xiaox/pytorch/SucTest,transformtransform)num_classes dataset.get_num_classes()
print(fTotal number of classes: {num_classes})# 数据加载和划分
from torch.utils.data import DataLoader, random_split
total_size len(dataset)
train_size int(total_size * 0.8)
test_size total_size - train_size
train_dataset, test_dataset random_split(dataset, [train_size, test_size])# 加载数据集
train_loader DataLoader(train_dataset, batch_size128, shuffleTrue)
test_loader DataLoader(test_dataset, batch_size128, shuffleTrue)1.如何自定义Dataset以用来灵活处理图像数据[数据的变化]1.定义__init__函数(读取csv文件图像文件transform标签编码) [相当于将csv文件读取到Dataframe数据类型中将标签映射为整数] 2.定义__getitem__函数(获取图像并转换,与图像对应的标签的索引)[相当于返回一张被转换的图片 与图片对应的Label对应的整数索引]2.为什么使用类别索引将字符串映射成整数最重要的一点:神经网络中字符串无法转化为tensor类型无法加入到net网络中3.为什么选择类别索引而不是独热编码[独热编码就是预测房价中对于各个字符串标签的处理方法]独热编码在交叉熵损失函数中不适用可拓展内容:
1.正常加载图像数据的其他方式(dataset,compose,data_loader的关系)
2.类别索引在做什么
3.train_iter迭代器在迭代时__getitem_在干什么第二部分 定义网络 使用了Resnet50 from torch import nn
from d2l import torch as d2l
from torch.nn import functional as F
import torchvision.models as modelsmodel models.resnet50(weightsNone) # 使用预训练的ResNet-50# 首先获取全连接层的输入特征数量
num_ftrs model.fc.in_features# 使用Dropout层和新的全连接层创建一个新的Sequential模块
model.fc nn.Sequential(nn.Dropout(0.5),nn.Linear(num_ftrs, 176)
)
第三部分 损失函数,验证函数,优化器 这里我使用了Adam作为优化器 #这是评估模型平均准确率的函数
def evaluate_accuracy_gpu(net, data_iter, deviceNone): #save使用GPU计算模型在数据集上的精度if isinstance(net, nn.Module):#1net.eval() # 设置为评估模式#2if not device:device next(iter(net.parameters())).device# 正确预测的数量总预测的数量#3metric d2l.Accumulator(2)#4## 4.1with torch.no_grad():## 4.2for X, y in data_iter:### 4.2.1if isinstance(X, list):# BERT微调所需的之后将介绍X [x.to(device) for x in X]else:X X.to(device)### 4.2.2y y.to(device)### 4.2.3 注意:d2l原有库可能表示:acc d2l.accuracy(net(X), y) metric.add(acc * y.numel(), y.numel())print(d2l.accuracy(net(X), y))metric.add(d2l.accuracy(net(X), y), y.numel())#5return metric[0] / metric[1]#save
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device,weight_decay):用GPU训练模型(在第六章定义)#1def 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)#2net.to(device)#更改了优化器#optimizer torch.optim.SGD(net.parameters(), lrlr)optimizer torch.optim.Adam(net.parameters(), lrlr, weight_decayweight_decay)#4loss nn.CrossEntropyLoss()#5animator d2l.Animator(xlabelepoch, xlim[1, num_epochs],legend[train loss, train acc, test acc])#6timer, num_batches d2l.Timer(), len(train_iter)#7for epoch in range(num_epochs):# 训练损失之和训练准确率之和样本数#7.1metric d2l.Accumulator(3)#7.2net.train()#7.3for 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():#7.4metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])timer.stop()#7.5train_l metric[0] / metric[2]train_acc metric[1] / metric[2]#7.6if (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 evaluate_accuracy_gpu(net, test_iter)animator.add(epoch 1, (None, None, test_acc))print(floss {train_l:.3f}, train acc {train_acc:.3f}, ftest acc {test_acc:.3f})print(f{metric[2] * num_epochs / timer.sum():.1f} examples/sec fon {str(device)})第四部分 训练
## 开始训练
lr 1e-4
batch_size 128
num_epochs 20
weight_decay 1e-3train_ch6(model, train_loader, test_loader, num_epochs, lr, d2l.try_gpu(),weight_decay)可能出现的bug CUDA错误
1.检查数据类型与形状是否合理(断言测试)
2.检查网络输出种类是否正常(获取类别个数)
3.检查网络是否正常(前向输出测试)
4.检查网络每一层是否正常(循环测试)首先:可以尝试重启,有可能是把内存用完了,重启试一下在进行下面的排查拓展内容
正常加载图像数据的其他方式 #### 当图片所在文件夹代表一个标签时使用或数据集有对应的加载函数
import torch
from torchvision import transforms,datasets
from torch import nn
from d2l import torch as d2l# 0.定义载入图像的格式 AlexNet的输入是227
transform transforms.Compose([transforms.Resize(256), # 将图像缩放使最短边为256像素transforms.CenterCrop(227), # 从图像中心裁剪224x224大小的图像transforms.ToTensor(), # 将图像转换为PyTorch张量transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) # 归一化处理
])# 例子:读取图像数据(图片所在文件夹代表一个标签)
dataset datasets.ImageFolder(rootC:\\Users\\xiaox\\pytorch\\SucTest\\img\\, transformtransform)# 例子加载 CIFAR-10 数据集(数据集有对应的加载函数)
train_set datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform)# 2.定义迭代器
train_loader torch.utils.data.DataLoader(train_set, batch_size64, shuffleTrue)类别索引在做什么
## 标签编码定义
在处理分类问题时尤其是在使用机器学习或深度学习模型时通常需要将文本或字符串类型的标签labels转换成整数索引。这是因为大多数算法都优化以处理数值数据而不是文本数据。在你的代码中这个转换是通过 Pandas 的 factorize 函数实现的。### pd.factorize()
这个函数用于将一个具有重复值的数组转换为一个整数数组其中每个唯一值都被分配一个整数标识符。它还返回一个包含原始数据中唯一值的数组这可以作为标签到整数的映射。#### 示例解释假设你有一个CSV文件其中包含如下的数据其中每行代表一个样本第一列是图像的文件名第二列是图像的标签如动物种类
image_name, label
cat001.jpg, cat
dog001.jpg, dog
cat002.jpg, cat
bird001.jpg, bird
使用 pd.factorize() 函数处理 label 列时会发生以下操作labels, label_mapping pd.factorize([cat, dog, cat, bird])
结果
- labels 会是 [0, 1, 0, 2]。这里cat 被映射为 0dog 被映射为 1bird 被映射为 2。注意第一个出现的标签cat是第一个被赋予新索引的。
- label_mapping 会是 [cat, dog, bird]这是一个数组其中索引位置对应于在 labels 中分配给每个唯一标签的整数。通过这种方式原始的字符串标签被转换为整数使得它们可以更容易地被模型处理同时你还保持了一个从整数索引回到原始标签的映射这在模型预测结束后将预测的整数标签转换回人类可读的标签时非常有用。train_iter迭代器在迭代时__getitem_在干什么
for X,y in train_iter:做了什么DataLoader 创建一个迭代器。每次迭代时从数据集通过 Dataset 对象中请求下一批数据。
(既向dataset对象随即指定batch_size个索引,来获取数据)数据集的 __getitem__ 方法按索引获取数据和标签这通常是随机访问支持数据的随机打乱和批处理。
(dataset通过idx与__getitem__获得指定的数据然后返回给dataloader直到所有的batch_size个数据都被返回)