树叶分类竞赛(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 length

def barw(ax): 
    
    for p in ax.patches:
        val = p.get_width() #height of the bar
        x = p.get_x()+ p.get_width() # x- position 
        y = p.get_y() + p.get_height()/2 #y-position
        ax.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_height
        self.resize_width = resize_width

        self.file_path = file_path
        self.mode = mode

        # 读取 csv 文件
        # 利用pandas读取csv文件
        self.data_info = pd.read_csv(csv_path, header=None)  #header=None是去掉表头部分
        # 计算 length
        self.data_len = len(self.data_info.index) - 1
        self.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
            # 第二列是图像的 label
            self.train_label = np.asarray(self.data_info.iloc[1:self.train_len, 1])
            self.image_arr = self.train_image 
            self.label_arr = self.train_label
        elif 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_image
            self.label_arr = self.valid_label
        elif mode == 'test':
            self.test_image = np.asarray(self.data_info.iloc[1:, 0])
            self.image_arr = self.test_image
            
        self.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_img
        else:
            # 得到图像的 string label
            label = self.label_arr[index]
            # number label
            number_label = class_to_num[label]

            return img_as_img, number_label  #返回每一个index对应的图片数据和对应的label

    def __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 image

fig=plt.figure(figsize=(20, 12))
columns = 4
rows = 2

dataiter = 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 = 10

for 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 = model
        for 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_features
    model_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_epoch

best_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 = batch
        imgs = 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 epoch
    if valid_acc > best_acc:
        best_acc = valid_acc
        torch.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 = batch
    with 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        导出输出文件即可

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

奥数与C++小学四年级(第十一题 试商)

参考程序代码&#xff1a; #include <iostream> using namespace std; int main() { int dividend 2023; int count 0; // 余数从0开始遍历到被除数 for (int remainder 0; remainder < dividend; remainder) { int divisor remainder 2; // 计算商 if…

GPT-Sovits-2-微调模型

1. 大致步骤 上一步整理完数据集后&#xff0c;此步输入数据, 微调2个模型VITS和GPT&#xff0c;位置在 <<1-GPT-SoVITS-tts>>下的<<1B-微调训练>> 页面的两个按钮分别执行两个文件: <./GPT_SoVITS/s2_train.py> 这一步微调VITS的预训练模型…

关于前端程序员使用Idea快捷键配置的说明

相信很多前端程序员 转到后端第一件事就是安装Idea然后学习java&#xff0c;在这里面最难的不是java的语法&#xff0c;而是关于快捷键的修改&#xff0c;前端程序员用的最多的估计就是VsCode或者Webstorm&#xff0c;就拿我自己举例我经常使用Vscode&#xff0c;当我写完代码下…

ubuntu运行gazebo导致内存越来越少

1.用vscode看代码会一直有没用的日志缓存&#xff0c;可以删掉&#xff08;文件夹留着&#xff0c;可以把里面的东西删掉&#xff09; 2.运行gazebo的模型会有很多缓存文件&#xff0c;可以删掉 log文件夹非常大

视频智能分析平台LiteAIServer入侵检测算法平台部署行人入侵检测算法:智能安防的新利器

在当今数字化时代&#xff0c;安全防护成为了社会各界高度关注的重要议题。随着人工智能技术的不断发展&#xff0c;视频智能分析平台LiteAIServer 行人入侵检测算法应运而生&#xff0c;为安防领域带来了全新的突破与变革。 视频智能分析平台LiteAIServer 行人入侵检测算法是基…

架构师备考-非关系型数据库

基础理论 CAP 理论 C&#xff08;Consistency&#xff09;一致性。一致性是指更新操作成功并返回客户端完成后&#xff0c;所有的节点在同一时间的数据完全一致&#xff0c;与ACID 的 C 完全不同。A &#xff08;Availability&#xff09;可用性。可用性是指服务一直可用&…

七、k8s快速入门之资源控制器

文章目录 :star: RC:star: Deployment:three: create 和 apply的区别 :star: DaemonSet:star: job&&CronJob ⭐️ RC 1️⃣ 查看版本 kubect api-resource 或 kubect explain rs2️⃣ 编写Yaml文档 [rootmaster ~]# vim pod/rc.yaml apiVersion: extensions/v1beta1…

FreeRTOS移植到STM32F103C8T6(HAL库)

目录 一、将STM32F103ZET6代码变更成STM32F103C8T6 二、 将FreeRTOS码源添加到文件 三、代码更改适配 四、测试 一、将STM32F103ZET6代码变更成STM32F103C8T6 点击魔法棒&#xff0c;点击Device&#xff0c;选择芯片为STM32F103C8T6 进行编译&#xff0c;无报错无警告&am…

Nginx 的 Http 模块介绍(上)

Nginx 的 Http 模块介绍&#xff08;上&#xff09; 1. http 请求 11 个处理阶段介绍 Nginx 将一个 Http 请求分成多个阶段&#xff0c;以模块为单位进行处理。其将 Http请求的处理过程分成了 11 个阶段&#xff0c;各个阶段可以包含任意多个 Http 的模块并以流水线的方式处理…

六西格玛项目助力,手术机器人零部件国产化稳中求胜——张驰咨询

项目背景 XR-1000型腔镜手术机器人是某头部手术机器人企业推出的高端手术设备&#xff0c;专注于微创手术领域&#xff0c;具有高度的精确性和稳定性。而XR-1000型机器人使用的部分核心零部件长期依赖进口&#xff0c;特别是高精度电机、关节执行机构和视觉系统等&#xff0c;…

基于Python爬虫与文本挖掘的网络舆情监控系统【附源码】

基于Python爬虫与文本挖掘的网络舆情监控系统 效果如下&#xff1a; 系统登录界面 注册页面界面 管理员主界面 用户界面 网络舆情管理界面 看板详细页面 系统简介界面 用户主界面 网络舆情界面 研究背景 随着网络空间舆论的日益活跃&#xff0c;其对社会事件的影响愈发显著。…

光影重塑 艺术无界——中央美术学院国际学院与北京曦烽摄影学院联展启幕

10月28日&#xff0c;中央美术学院国际学院与北京曦烽摄影学院联合举办的《重塑》摄影展&#xff0c;在中央美术学院国际学院艺术空间启幕。展览旨在打破传统“时尚摄影”的话语界限&#xff0c;通过镜头展现时尚的更多维度&#xff0c;既关注视觉美感&#xff0c;更深入挖掘时…

【Linux 25】网络套接字 socket 概念

文章目录 &#x1f308; 一、IP 地址概念⭐ 1. IP 地址的作用⭐ 2. 源 IP 地址和目的 IP 地址 &#x1f308; 二、端口号概念⭐ 1. 源端口号和目的端口号⭐ 2. 端口号范围划分⭐ 3. 端口号 VS 进程 ID⭐ 4. 套接字 socket 的概念 &#x1f308; 三、传输层的典型代表协议⭐ 1. …

配置mysql 主主模式 GTID

文章目录 一、前提二、修改my.cnf主1 10.255.131.9主2 10.255.131.10 三、配置主主3.1 配置主 10.255.131.93.2 配置从 10.255.131.103.3 配置主 10.255.131.103.4 配置从 10.255.131.9 四、验证五、同步问题排查以及恢复5.1 查看同步状态5.2 查看同步是否数据一致性&#xff0…

自动化研磨领域的革新者:半自动与自动自磨机的技术突破

据QYResearch调研团队最新报告“全球半自动和自动自磨机市场报告2023-2029”显示&#xff0c;预计2029年全球半自动和自动自磨机市场规模将达到5.3亿美元&#xff0c;未来几年年复合增长率CAGR为3.5%。 图00001. 半自动和自动自磨机&#xff0c;全球市场总体规模 如上图表/数据…

最长方连续方波信号

更多关于刷题的内容欢迎订阅我的专栏华为刷题笔记 该专栏题目包含两部分&#xff1a; 100 分值部分题目 200 分值部分题目 所有题目都会陆续更新&#xff0c;订阅防丢失 题目描述 输入一串方波信号&#xff0c;求取最长的完全连续交替方波信号&#xff0c;并将其输出&#x…

ARB链挖矿DApp系统开发模式定制

在区块链生态中&#xff0c;挖矿作为一种获取加密资产的方式&#xff0c;越来越受到关注。ARB链凭借其高效的性能和灵活的智能合约系统&#xff0c;成为了开发挖矿DApp的理想平台。本文将探讨ARB链挖矿DApp的开发模式定制&#xff0c;包括架构设计、功能实现以及最佳实践。 ARB…

YoloV8改进策略:Block改进|RFE模块,提高小物体的识别精度|即插即用|代码+修改过程

摘要 论文介绍 本文介绍了一种基于YOLOv5的人脸检测方法,命名为YOLO-FaceV2。该方法旨在解决人脸检测中的尺度变化、简单与困难样本不平衡以及人脸遮挡等问题。通过引入一系列创新模块和损失函数,YOLO-FaceV2在WiderFace数据集上取得了优异的表现,特别是在小物体、遮挡和困…

使用 Elasticsearch 进行语义搜索

Elasticsearch 是一款功能强大的开源搜索引擎&#xff0c;可用于全文搜索、分析和数据可视化。传统上&#xff0c;Elasticsearch 以其执行基于关键字/词汇的搜索的能力而闻名&#xff0c;其中文档基于精确或部分关键字匹配进行匹配。然而&#xff0c;Elasticsearch 已经发展到支…

计算机网络:网络层 —— 虚拟专用网 VPN

文章目录 虚拟专用网 VPN 概述内联网 VPN外联网 VPN 虚拟专用网 VPN 概述 虚拟专用网&#xff08;Virtual Private Network&#xff0c;VPN&#xff09;&#xff1a;利用公用的因特网作为本机构各专用网之间的通信载体&#xff0c;这样形成的网络又称为虚拟专用网。 出于安全…