树叶分类竞赛(Baseline)以及kaggle的GPU使用

树叶分类竞赛(Baseline)-kaggle的GPU使用

文章目录

  • 树叶分类竞赛(Baseline)-kaggle的GPU使用
    • 竞赛的步骤
    • 代码实现
      • 创建自定义dataset
      • 定义data_loader
      • 模型定义
      • 超参数
      • 训练模型
      • 预测和保存结果
    • kaggle使用

竞赛的步骤

本文来自于Neko Kiku提供的Baseline,感谢大佬提供代码,来自于https://www.kaggle.com/nekokiku/simple-resnet-baseline

总结一下数据处理步骤:

  1. 先观察数据,发现数据有三类,测试和训练两类csv文件,以及image文件。

csv文件处理:读取训练文件,观察种类个数,同时将种类和标签相绑定

image文件:可以利用tensorboard进行图片的观察,也可以用image图片展示

  1. 创建自定义的dataset,自定义不同的类型;接着创建DataLoader定义一系列参数
  2. 模型定义,利用选定好的模型restnet34,记得最后接一个全连接层将数据压缩至种类个数
  3. 超参数可以有效提高辨别概率,自己电脑GPU太拉跨,选定好参数再进行跑模型,提高模型效率
  4. 训练模型
  5. 预测和保存结果

学习到的优化方法:

  1. 数据增强: 在数据加载阶段,可以使用数据增强技术来增加数据的多样性,帮助模型更好地泛化。可以使用 torchvision.transforms 来实现。
  2. 调整超参数: 尝试不同的超参数,如学习率、batch size、weight decay 等,找到最佳组合。

代码实现

  • 文件处理
# 首先导入包
import torch
import torch.nn as nn
import pandas as pd
import numpy as np
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image
import os
import matplotlib.pyplot as plt
import torchvision.models as models
# This is for the progress bar.
from tqdm import tqdm
import seaborn as sns
  • 观察给出的几个文件类型以及内容,得出标签类型以及频度
# 看看label文件长啥样,先了解训练集,再看对应的标签类型
labels_dataframe = pd.read_csv('../input/classify-leaves/train.csv')
labels_dataframe.head(5)
# pd.describe()函数生成描述性统计数据,统计数据集的集中趋势,分散和行列的分布情况,不包括 NaN值。
labels_dataframe.describe()
  • 坐标展示数据,可视化种类的分布情况
#function to show bar lengthdef barw(ax): for p in ax.patches:val = p.get_width() #height of the barx = p.get_x()+ p.get_width() # x- position y = p.get_y() + p.get_height()/2 #y-positionax.annotate(round(val,2),(x,y))#finding top leaves
plt.figure(figsize = (15,30))
ax0=sns.countplot(y=labels_dataframe['label'],order=labels_dataframe['label'].value_counts().index)
barw(ax0)
plt.show()
  • 将label和数字相对应,建立字典
# 把label文件排个序
leaves_labels = sorted(list(set(labels_dataframe['label'])))
n_classes = len(leaves_labels)
print(n_classes)
leaves_labels[:10]
# 把label转成对应的数字
class_to_num = dict(zip(leaves_labels, range(n_classes)))
class_to_num
# 再转换回来,方便最后预测的时候使用
num_to_class = {v : k for k, v in class_to_num.items()}
'abies_concolor': 0,'abies_nordmanniana': 1,'acer_campestre': 2,'acer_ginnala': 3,'acer_griseum': 4,'acer_negundo': 5,'acer_palmatum': 6,'acer_pensylvanicum': 7,'acer_platanoides': 8,'acer_pseudoplatanus': 9,'acer_rubrum': 10,

创建自定义dataset

dataset分为init,getitem,len三部分

init函数:定义照片尺寸和文件路径,根据不同模式对数据进行不同的处理。

getitem函数:获取文件的函数,同样对于不同模式的请求对数据有不同的处理。学习train中数据增强的手段

len函数:返回真实长度

# 继承pytorch的dataset,创建自己的
class LeavesData(Dataset):def __init__(self, csv_path, file_path, mode='train', valid_ratio=0.2, resize_height=256, resize_width=256):"""Args:csv_path (string): csv 文件路径img_path (string): 图像文件所在路径mode (string): 训练模式还是测试模式valid_ratio (float): 验证集比例"""# 需要调整后的照片尺寸,我这里每张图片的大小尺寸不一致#self.resize_height = resize_heightself.resize_width = resize_widthself.file_path = file_pathself.mode = mode# 读取 csv 文件# 利用pandas读取csv文件self.data_info = pd.read_csv(csv_path, header=None)  #header=None是去掉表头部分# 计算 lengthself.data_len = len(self.data_info.index) - 1self.train_len = int(self.data_len * (1 - valid_ratio))if mode == 'train':# 第一列包含图像文件的名称self.train_image = np.asarray(self.data_info.iloc[1:self.train_len, 0])  #self.data_info.iloc[1:,0]表示读取第一列,从第二行开始到train_len# 第二列是图像的 labelself.train_label = np.asarray(self.data_info.iloc[1:self.train_len, 1])self.image_arr = self.train_image self.label_arr = self.train_labelelif mode == 'valid':self.valid_image = 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_imageself.label_arr = self.valid_labelelif mode == 'test':self.test_image = np.asarray(self.data_info.iloc[1:, 0])self.image_arr = self.test_imageself.real_len = len(self.image_arr)print('Finished reading the {} set of Leaves Dataset ({} samples found)'.format(mode, self.real_len))def __getitem__(self, index):# 从 image_arr中得到索引对应的文件名single_image_name = self.image_arr[index]# 读取图像文件img_as_img = Image.open(self.file_path + single_image_name)#如果需要将RGB三通道的图片转换成灰度图片可参考下面两行
#         if img_as_img.mode != 'L':
#             img_as_img = img_as_img.convert('L')#设置好需要转换的变量,还可以包括一系列的nomarlize等等操作if self.mode == 'train':transform = transforms.Compose([transforms.Resize((224, 224)),transforms.RandomHorizontalFlip(p=0.5),   #随机水平翻转 选择一个概率transforms.ToTensor()])else:# valid和test不做数据增强transform = transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor()])img_as_img = transform(img_as_img)if self.mode == 'test':return img_as_imgelse:# 得到图像的 string labellabel = self.label_arr[index]# number labelnumber_label = class_to_num[label]return img_as_img, number_label  #返回每一个index对应的图片数据和对应的labeldef __len__(self):return self.real_len
# 设置文件路径,读取文件
train_path = '../input/classify-leaves/train.csv'
test_path = '../input/classify-leaves/test.csv'
# csv文件中已经images的路径了,因此这里只到上一级目录
img_path = '../input/classify-leaves/'train_dataset = LeavesData(train_path, img_path, mode='train')
val_dataset = LeavesData(train_path, img_path, mode='valid')
test_dataset = LeavesData(test_path, img_path, mode='test')
print(train_dataset)
print(val_dataset)
print(test_dataset)

定义data_loader

# 定义data loader,如果报错的话,改变num_workers为0
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,batch_size=8, shuffle=False,num_workers=5)val_loader = torch.utils.data.DataLoader(dataset=val_dataset,batch_size=8, shuffle=False,num_workers=5)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,batch_size=8, shuffle=False,num_workers=5)
# 给大家展示一下数据长啥样
def im_convert(tensor):""" 展示数据"""image = tensor.to("cpu").clone().detach()image = image.numpy().squeeze()image = image.transpose(1,2,0)image = image.clip(0, 1)return imagefig=plt.figure(figsize=(20, 12))
columns = 4
rows = 2dataiter = iter(val_loader)
inputs, classes = dataiter.next()for idx in range (columns*rows):ax = fig.add_subplot(rows, columns, idx+1, xticks=[], yticks=[])ax.set_title(num_to_class[int(classes[idx])])plt.imshow(im_convert(inputs[idx]))
plt.show()
  • 可以自己尝试一下用tensorboard展示一下图片,我贴出我的代码
from torch.utils.tensorboard import SummaryWriter
from PIL import Image
import numpy as np
import os# 注意这个图片的路径和之前的路径不同
image_path = './dataset/images'
writer = SummaryWriter("logs")
image_filenames = os.listdir(image_path)
batch_size = 10for i in range(0, int(len(image_filenames)/1000), batch_size):batch_images = image_filenames[i:i + batch_size]for j, img_filename in enumerate(batch_images):img_concise = os.path.join(image_path, img_filename)img = Image.open(img_concise)img_array = np.array(img)# writer.add_image(f"test/batch_{i // batch_size}/img_{j}", img_array, j, dataformats='HWC')writer.add_image(f"test_batch{i}", img_array, j, dataformats='HWC')writer.close()
# 观察是否在GPU上运行
def get_device():return 'cuda' if torch.cuda.is_available() else 'cpu'device = get_device()
print(device)

模型定义

在查阅下了解到利用了迁移学习,通过不改变模型前面一些层的参数可以加快训练速度,也称作冻结层,我在下面贴上冻结层的目的;模型利用上节课学到的resnet模型,模型全封装好了直接调用,只需要在最后一层添加一个全连接层,使得最后的输出结果为模型的类型即可。

  • 减少训练时间:通过不更新某些层的参数,可以减少计算量,从而加快训练速度。
  • 防止过拟合:冻结一些层的参数可以避免模型在小数据集上过拟合,特别是在迁移学习中,预训练的层通常已经学到了良好的特征。
# 是否要冻住模型的前面一些层
def set_parameter_requires_grad(model, feature_extracting):if feature_extracting:model = modelfor param in model.parameters():param.requires_grad = False
# resnet34模型
def res_model(num_classes, feature_extract = False, use_pretrained=True):model_ft = models.resnet34(pretrained=use_pretrained)set_parameter_requires_grad(model_ft, feature_extract)num_ftrs = model_ft.fc.in_featuresmodel_ft.fc = nn.Sequential(nn.Linear(num_ftrs, num_classes))return model_ft

超参数

# 超参数
learning_rate = 3e-4
weight_decay = 1e-3
num_epoch = 50
model_path = './pre_res_model.ckpt'

训练模型

  • 训练和验证分类模型的模版,需要很大时间去训练,可以利用kaggle的GPU来跑模型
# Initialize a model, and put it on the device specified.
model = res_model(176) # 之前观察到树叶的类别有176个
model = model.to(device)
model.device = device
# For the classification task, we use cross-entropy as the measurement of performance.
criterion = nn.CrossEntropyLoss()# Initialize optimizer, you may fine-tune some hyperparameters such as learning rate on your own.
optimizer = torch.optim.Adam(model.parameters(), lr = learning_rate, weight_decay=weight_decay)# The number of training epochs.
n_epochs = num_epochbest_acc = 0.0
for epoch in range(n_epochs):# ---------- Training ----------# Make sure the model is in train mode before training.model.train() # These are used to record information in training.train_loss = []train_accs = []# Iterate the training set by batches.for batch in tqdm(train_loader):# A batch consists of image data and corresponding labels.imgs, labels = batchimgs = imgs.to(device)labels = labels.to(device)# Forward the data. (Make sure data and model are on the same device.)logits = model(imgs)# Calculate the cross-entropy loss.# We don't need to apply softmax before computing cross-entropy as it is done automatically.loss = criterion(logits, labels)# Gradients stored in the parameters in the previous step should be cleared out first.optimizer.zero_grad()# Compute the gradients for parameters.loss.backward()# Update the parameters with computed gradients.optimizer.step()# Compute the accuracy for current batch.acc = (logits.argmax(dim=-1) == labels).float().mean()# Record the loss and accuracy.train_loss.append(loss.item())train_accs.append(acc)# The average loss and accuracy of the training set is the average of the recorded values.train_loss = sum(train_loss) / len(train_loss)train_acc = sum(train_accs) / len(train_accs)# Print the information.print(f"[ Train | {epoch + 1:03d}/{n_epochs:03d} ] loss = {train_loss:.5f}, acc = {train_acc:.5f}")# ---------- Validation ----------# Make sure the model is in eval mode so that some modules like dropout are disabled and work normally.model.eval()# These are used to record information in validation.valid_loss = []valid_accs = []# Iterate the validation set by batches.for batch in tqdm(val_loader):imgs, labels = batch# We don't need gradient in validation.# Using torch.no_grad() accelerates the forward process.with torch.no_grad():logits = model(imgs.to(device))# We can still compute the loss (but not the gradient).loss = criterion(logits, labels.to(device))# Compute the accuracy for current batch.acc = (logits.argmax(dim=-1) == labels.to(device)).float().mean()# Record the loss and accuracy.valid_loss.append(loss.item())valid_accs.append(acc)# The average loss and accuracy for entire validation set is the average of the recorded values.valid_loss = sum(valid_loss) / len(valid_loss)valid_acc = sum(valid_accs) / len(valid_accs)# Print the information.print(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f}")# if the model improves, save a checkpoint at this epochif valid_acc > best_acc:best_acc = valid_acctorch.save(model.state_dict(), model_path)print('saving model with acc {:.3f}'.format(best_acc))

预测和保存结果

saveFileName = './submission.csv'
## predict
model = res_model(176)# create model and load weights from checkpoint
model = model.to(device)
model.load_state_dict(torch.load(model_path))# Make sure the model is in eval mode.
# Some modules like Dropout or BatchNorm affect if the model is in training mode.
model.eval()# Initialize a list to store the predictions.
predictions = []
# Iterate the testing set by batches.
for batch in tqdm(test_loader):imgs = batchwith torch.no_grad():logits = model(imgs.to(device))# Take the class with greatest logit as prediction and record it.predictions.extend(logits.argmax(dim=-1).cpu().numpy().tolist())preds = []
for i in predictions:preds.append(num_to_class[i])test_data = pd.read_csv(test_path)
test_data['label'] = pd.Series(preds)
submission = pd.concat([test_data['image'], test_data['label']], axis=1)
submission.to_csv(saveFileName, index=False)
print("Done!!!!!!!!!!!!!!!!!!!!!!!!!!!")

kaggle使用

  1. 创建kaggle账户
  2. 创建一个Dataset,将树叶信息导入/还可以通过kaggle自身的数据集进行数据的导入
  3. 创建一个Notebook

在这里插入图片描述

  1. 导入的文件放在了/kaggle/input,将导入的文件放在根目录下使得代码中的导入文件路径不会变
cp -r /文件 命名
cp -r /kaggle/input/leaf-dataset dataset

在这里插入图片描述

  1. 打开右侧边栏,将其修改为GPUP100,每周有30个小时的运行时间

在这里插入图片描述

  1. 运行代码,发现输出的结果都在根目录下,将输出的结果导出到/kaggle/Working
 cp -r submission.csv /kaggle/working        导出输出文件即可

在这里插入图片描述

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

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

相关文章

四足机器人实战篇之二十二:四足机器人支撑腿反作用力规划之反馈控制及线性约束条件优化方法

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言一、先使用反馈+前馈的控制方式,根据躯干期望的位置速度,计算出当前身体姿态的虚拟反作用力(实现躯体平衡控制器)二、再建立线性约束的凸优化问…

企业物流管理数据仓库建设的全面指南

文章目录 一、物流管理目标二、总体要求三、数据分层和数据构成(1)数据分层(2)数据构成 四、数据存储五、数据建模和数据模型(1)数据建模(2)数据模型 六、总结 在企业物流管理中&…

设计模式基础概念(行为模式):责任链模式(Chain Of Responsibility)

概述 责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。 该模式建议你将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于…

centos7 安装python3.9.4,解决import ssl异常

本篇文章介绍如何在centos7中安装python3.9.4(下文简称python3),解决python3安装后import ssl模块失败问题,为什么我要在centos7中安装python呢,因为我需要在服务器中跑python数据处理脚本。 安装python3同时解决import ssl模块失败问题总共包…

【分布式技术】分布式序列算法Snowflake深入解读

文章目录 概述Snowflake算法的构成:Snowflake算法的特点:Snowflake算法存在的问题: 🔍 雪片算法在分布式系统中是如何保证ID的唯一性和有序性的?唯一性(Uniqueness)有序性(Orderline…

纯CSS实现UI设计中常见的丝带效果(5)

原文传送门:纯CSS实现UI设计中常见的丝带效果 网页中的丝带效果在设计中扮演着多重角色,其作用可以归纳为以下几个方面: 视觉吸引与装饰 增强视觉吸引力:丝带效果以其独特的形态和色彩,能够迅速吸引用户的注意力&…

TP41Y阀套式排污阀

在现代工业领域中,阀门作为一种关键的控制元件,广泛应用于各种流体系统中。其中,TP41Y阀套式排污阀以其独特的设计和优异的性能,在石油、天然气、化工等行业中占据了重要的地位。本文将对TP41Y阀套式排污阀进行详细的专业解析&…

Python | Leetcode Python题解之第522题最长特殊序列II

题目&#xff1a; 题解&#xff1a; class Solution:def findLUSlength(self, strs: List[str]) -> int:def is_subseq(s: str, t: str) -> bool:pt_s pt_t 0while pt_s < len(s) and pt_t < len(t):if s[pt_s] t[pt_t]:pt_s 1pt_t 1return pt_s len(s)ans …

Flink SQL中Changelog事件乱序处理原理

本文围绕Flink SQL实时数据处理中的Changelog事件乱序问题&#xff0c;分析了Flink SQL中Changelog事件乱序问题的原因&#xff0c;并提供了解决方案以及处理Changelog事件乱序的建议。以帮助您更好地理解Changelog的概念和应用&#xff0c;更加高效地使用Flink SQL进行实时数据…

HTML CSS

目录 1. 什么是HTML 2. 什么是CSS ? 3. 基础标签 & 样式 3.1 新浪新闻-标题实现 3.1.1 标题排版 3.1.1.1 分析 3.1.1.2 标签 3.1.1.3 实现 3.1.2 标题样式 3.1.2.1 CSS引入方式 3.1.2.2 颜色表示 3.1.2.3 标题字体颜色 3.1.2.4 CSS选择器 3.1.2.5 发布时间字…

Open3D(C++) 基于法线微分的点云分割

目录 一、算法原理二、代码实现三、结果展示1、原始点云2、分割结果本文由CSDN点云侠原创,原文链接,首发于:2024年11月1日。 一、算法原理 使用C++版本Open3D复现的PCL里边基于法线微分的分割算法。PCL 基于法线微分(DoN)的点云分割【2024最新版】。网上有大量相关算法介…

Xcode 15.4 运行flutter项目,看不到报错信息详情?

Xcode升级后&#xff0c;遇到了奇怪的事情&#xff1a; 运行flutter项目&#xff0c;左侧栏显示有报错信息&#xff0c;但是点击并没有跳转出具体的error详情。【之前都会自己跳转出来的&#xff0c;升级后真的是无厘头】 方案&#xff1a; 点击左侧导航栏最右边的图标——>…

Java基础(8)异常

目录 1.前言 2.正文 2.1异常的引入 2.2异常的类型 2.2.1编译时异常 2.2.2运行时异常 2.3区分Exception与Error 2.4异常的声明&#xff0c;抛出与捕获 2.4.1throw 2.4.2throws 2.4.2try-catch与finally 2.6自定义异常 3.小结 1.前言 哈喽大家好啊&#xff0c;Java…

解决rabbitmq-plugins enable rabbitmq_delayed_message_exchange :plugins_not_found

问题&#xff1a;我是在docker-compose环境部署的 services:rabbitmq:image: rabbitmq:4.0-managementrestart: alwayscontainer_name: rabbitmqports:- 5672:5672- 15672:15672environment:RABBITMQ_DEFAULT_USER: rabbitRABBITMQ_DEFAULT_PASS: 123456volumes:- ./rabbitmq/…

JavaScript语法基础——变量,数据类型,运算符和程序控制语句(小白友好篇,手把手教你学会!)

一、JavaScript概述 JavaScript是一种高级编程语言&#xff0c;常用于网页开发和服务器端应用程序。它是一种动态类型语言&#xff0c;可以在浏览器中直接解释执行&#xff0c;而不需要编译。 脚本&#xff08;Script&#xff09;是一种与计算机程序相关的指令集或代码块&…

Android 中View.post的用法

View.post 是 Android 中 View 类的一个方法&#xff0c;它允许我们在视图 (View) 完成其布局 (Layout) 阶段后&#xff0c;将一个任务放到主线程的消息队列中&#xff0c;以便稍后执行。这种方式通常用于确保在 View 的尺寸、位置等布局属性已经计算完成后执行某些操作。 基本…

健康之路押注医药零售:毛利率下滑亏损扩大,医疗咨询人次大幅减少

《港湾商业观察》黄懿 2024年9月13日&#xff0c;健康之路股份有限公司&#xff08;下称“健康之路”&#xff09;再次递表港交所&#xff0c;建银国际为独家保荐人。健康之路国内运营主体为健康之路&#xff08;中国&#xff09;信息技术有限公司和福建健康之路信息技术有限公…

在pycharm中使用sqllite

在pycharm中使用sqllite sqllite 简介 SQLite 是一个开源的、轻量级的、关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它设计用于嵌入到应用程序中&#xff0c;并且可以在无需外部服务器进程的情况下运行。SQLite 提供了完整的 SQL 语言支持&#xff0c;允…

游戏启动失败:8种修复xinput1_3.dll错误的几种方法教程,轻松解决xinput1_3.dll错误

当你准备好在一天的工作后放松一下&#xff0c;启动你最爱的游戏&#xff0c;却突然收到一个“xinput1_3.dll 丢失”的错误消息&#xff0c;这无疑是令人沮丧的。幸运的是&#xff0c;xinput1_3.dll丢失问题通常可以通过几个简单的步骤来解决。本文将详细介绍这些步骤&#xff…

多线程和线程同步基础篇学习笔记(Linux)

大丙老师教学视频&#xff1a;10-线程死锁_哔哩哔哩_bilibili 目录 大丙老师教学视频&#xff1a;10-线程死锁_哔哩哔哩_bilibili 线程概念 为什么要有线程 线程和进程的区别 在处理多任务的时候为什么线程数量不是越多越好? Linux提供的线程API 主要接口 线程创建 pth…