(机器学习深度学习常用库、框架|Pytorch篇)第二节:Pytorch中数据加载方法(DataLoader、DataSet和Sampler)

news2024/11/25 8:16:13

文章目录

  • 一:DataLoader,、DataSet、Sampler三者的关系
  • 二:DataLoader,、DataSet、Sampler详解
    • (1)Dataset
      • A:基本介绍
      • C:Pytroch内置数据集
    • (2)Sampler
      • A:SequentialSampler(顺序采样)
      • B:RandomSampler
      • C:SubsetRandomSampler(重要)
    • (3)Dataloader

注意:本文会用到一个txt数据,有1372个,5个维度(前4个维度为输入,最后1个维度为预测输出)

  • 下载链接
3.6216,8.6661,-2.8073,-0.44699,0
4.5459,8.1674,-2.4586,-1.4621,0
3.866,-2.6383,1.9242,0.10645,0
3.4566,9.5228,-4.0112,-3.5944,0
0.32924,-4.4552,4.5718,-0.9888,0
4.3684,9.6718,-3.9606,-3.1625,0
3.5912,3.0129,0.72888,0.56421,0
....

一:DataLoader,、DataSet、Sampler三者的关系

Pytorch对于数据集的处理,有三个非常重要的类,它们都位于torch.utils.data

  • Dataset:是数据集的类,主要用于定义数据集,也即数据来源

    • 例如 :你的数据是最简单的txt文件,那么在加载时你必须把这个txt封装为一个类,才可以由DataLoader加载(后面举例)
  • Sampler:是采样器,用于从数据集中选出数据(Sampler会返回数据集的索引indicies,然后Dataloader通过indicies选取数据)

  • Dataloader:专门用于数据加载的类,其中上面的DatasetSampler会作为参数传递给Dataloader。在训练、测试时数据将直接由Dataloader得到,例如

    • 加载训练集trainloader = Dataloader(dataset = trainDataset, sampler = train_sampler)
    • 加载验证集valloader = Dataloader(dataset = valDataset, sampler = val_sampler)
    • 加载测试集testloader= Dataloader(dataset = testDataset, sampler = test_sampler)

三者关系如下图所示

在这里插入图片描述

二:DataLoader,、DataSet、Sampler详解

(1)Dataset

A:基本介绍

Dataset 位于 torch.utils.data 下,我们需要通过继承Dataset 类来定义自己的数据集MyDatasetMyDataset这个类至少要重写以下两个方法

  • __getitem__(self, idx):重写该函数后,你的MyDataset的实例mydataset就可以像Python的基本类型那样进行索引操作了,也即mydataset[idx]

  • __len__(sef):重写该函数后,你的MyDataset的实例mydataset就可以像Python的基本类型那样len获取长度,也即len(mydataset)

from torch.utils.data import Dataset

class MyDataset(Dataset):
	def __init__(self):
        ...
        
    def __getitem__(self, index):
        return ...
    
    def __len__(self):
        return ...

以前文中给定的那个txt数据为例,进行封装

import torch
from torch.utils.data import DataLoader
from config import parameters  # config文件是我用来保存参数的文件,可忽略
import numpy as np

class MyDataset(torch.utils.data.Dataset):
    def __init__(self, data_path):
        self.dataset = np.loadtxt(data_path, delimiter=',')
        # 一般需要把数据集“洗牌”一下
        np.random.shuffle(self.dataset)

    def __getitem__(self, idx):
        item = self.dataset[idx]
        # 前四个维度为输入X
        # 后1个维度为输出y
        X, y = item[:parameters.in_features], item[parameters.in_features:]
        """
        	在进行返回时需要一些处理,例如
	            to(parameters.device):会把数据送到CPU或GPU
	            squeeze():会把维度为1的那个维度去掉
        """
        return torch.Tensor(X).float().to(parameters.device), \
               torch.Tensor(y).squeeze().long().to(parameters.device)
    # 返回数据的个数
    def __len__(self):
        return np.shape(self.dataset)[0]

将1372条数据按照7:2:1的比例划分为训练集、验证集和测试集,分别对应如下文件

  • train.txt:路径为parameters.trainset_path
  • val.txt:路径为parameters.valset_path
  • test.txt:路径为parameters.testset_path
import numpy as np
from config import parameters
import os

# 训练集、验证集和测试集划分比例
trainset_ratio = 0.7
valset_ratio = 0.2
test_set = 0.1

# 设置随机种子,读取源数据并打乱
np.random.seed(parameters.seed)
dataset = np.loadtxt(parameters.data_path, delimiter=',')
np.random.shuffle(dataset)

# 样本数量
n_items = np.shape(dataset)[0]

# 划分数据

trainset = dataset[:int(trainset_ratio*n_items), ]
valset = dataset[int(trainset_ratio*n_items):int(trainset_ratio*n_items)+int(valset_ratio*n_items), :]
testset = dataset[int(trainset_ratio*n_items)+int(valset_ratio*n_items):, ]


# 存储
np.savetxt(os.path.join(parameters.data_dir, 'train.txt'), trainset, delimiter=',')
np.savetxt(os.path.join(parameters.data_dir, 'val.txt'), valset, delimiter=',')
np.savetxt(os.path.join(parameters.data_dir, 'test.txt'), testset, delimiter=',')

测试如下,当我们传入的数据不同,就会生成不同的MyDataset实例

if __name__ == '__main__':
    myDataset_train = MyDataset(parameters.trainset_path)  # 训练数据集
    myDataset_val = MyDataset(parameters.valset_path)  # 验证数据集 
    myDataset_test = MyDataset(parameters.testset_path)  # 测试数据集 
    
    print("训练集长度:", len(myDataset_train))
    print("验证集长度:", len(myDataset_val))
    print("测试集长度:", len(myDataset_test))

	"""
	数据集封装好之后,可由Dataloader加载,这里第一个参数dataset便是
	你的MyDataset实例,传入即可
	bathsize会将你的训练集数组按照每组16个进行分割
	每次从traninloader中读取16个数据
	(Dataloader其余参数战术不管)
	"""
    trainloader = DataLoader(dataset=myDataset_train, batch_size=16, shuffle=True, drop_last=True)

    for batch in trainloader :
        X, y = batch
        print(X)
        print(y)
        break

如下图

  • len(myDataset_train):本质是在调用__len__(self)
  • X, y = batch:本质是在调用__getitem__(self, idx)

在这里插入图片描述

C:Pytroch内置数据集

在Pytorch中内置了很多常用的数据集,这些数据集已经被封装好了,所以无需你手动封装,直接可以用Dataloader加载。主要有以下几种

  • torchvision.datasets:提供了许多计算机视觉方面的数据集。torchvision是Pytorch的一个图形库,主要用来构建计算机视觉模型,非常重要,会在后续文章中详细介绍

    在这里插入图片描述

  • torchtext :提供了很多文本处理方向的数据集

  • torchaudio :提供了很多音频处理方向的数据集

例如,以MNIST数据集为例,导入后直接可以被Dataloader加载

  • 注意:下面的一些参数如果不了解可以暂时忽略,只看整体逻辑即可
#  原始数据训练数据
train_set = torchvision.datasets.MNIST(
    root='./data/',
    train=True,
    transform=transforms.ToTensor(),
    download=False
)
#  测试集
test_set = torchvision.datasets.MNIST(
    root='./data/',
    train=False,
    transform=transforms.ToTensor(),
    download=False
)


train_loader = DataLoader(train_set, batch_size=64, drop_last=True)
test_loader = DataLoader(test_set, batch_size=64, drop_last=False)

(2)Sampler

Sampler位于torch.utils.data下,和Dataloader一样,也需要重写Sampler类,但Pytorch中已经为我们实现了很多非常实用的Sampler子类,所以我们使用它们足矣。以下三个较常用

from torch.utils.data import sampler

sampler.RandomSampler:随机采样
sampler.SequentialSampler:顺序采样
sampler.BatchSampler:批采样

Sampler返回的是索引,Dataloader会根据该索引到Dataset中选取数据

A:SequentialSampler(顺序采样)

SequentialSampler会按照顺序进行采样,接受一个可迭代对象作为参数。SequentialSampler在被遍历时,遍历的就是采样后的索引

例如,对于之前的那个txt数据

from torch.utils.data import sampler

myDataset= MyDataset(parameters.data_path)
print(len(myDataset))

SequentialSampler = sampler.SequentialSampler(myDataset)

for index in SequentialSampler :
    print(index, myDataset[index])

在这里插入图片描述

实际使用时,SequentialSampler或其他采样器将作为参数传递到Dataloader中的sampler,所以我们在采样时一般会给一个简单的数字列表,范围为待采样数据集长度

myDataset= MyDataset(parameters.data_path)

# 0 ~ 1371
index_list = list(range(myDataset))
# 采样
SequentialSampler = sampler.SequentialSampler(index_list)
dataloader = DataLoader(bankfakedataset, batch_size=16, sampler=SequentialSampler , drop_last=True)

B:RandomSampler

RandomSampler 进行随机采样,接受一个可迭代对象作为参数,其他参数含义为

  • replacement:默认为False,表示不放回采样
  • num_samples:当replacement=True时才能设置此参数,表示要采出的样本个数
 myDataset = BankfakeDataset(parameters.data_path)
 print(len(myDataset))


index_list = list(range(myDataset))
RandomSampler = sampler.RandomSampler(index_list )
for index in RandomSampler:
    print(index, myDataset[index])

在这里插入图片描述

C:SubsetRandomSampler(重要)

SubsetRandomSampler可以设置子集的随机采样

# 100个数据的索引
index_list = list(range(10))
# 切片,分为0~6和7-9这两个部分
index_list1 = list(index_list[:7])
index_list2 = list(index_list[7:])


subRandomSampler1 = sampler.SubsetRandomSampler(index_list1)
subRandomSampler2 = sampler.SubsetRandomSampler(index_list2)

for index in subRandomSampler1:
    print(index, end=' ')
print()
for index in subRandomSampler2:
    print(index, end=' ')

在这里插入图片描述

SubsetRandomSampler多用于数据集的划分,例如划分为训练集、验证集和测试集,使用非常频繁

例如对于之前的那个txt数据,我们在加载之前是直接把原始数据分为了3个文件。这里我们改用采样的方式进行,直接在原始数据集上进行SubsetRandomSampler

myDataset = BankfakeDataset(parameters.data_path)
myDataset_num = len(myDataset)
print('原数据集长度', myDataset_num)

index_list = list(range(myDataset_num))
# 按照7:2:1的比例进行划分
train_num = int(0.7 * myDataset_num)
val_num = int(0.2 * myDataset_num)

train_index = index_list[: train_num]
val_index = index_list[train_num : train_num + val_num]
test_index = index_list[train_num+val_num :]

# 分别采样
train_sampler = sampler.SubsetRandomSampler(train_index)
val_sampler = sampler.SubsetRandomSampler(val_index)
test_sampler = sampler.SubsetRandomSampler(test_index)

# 查看区间范围
print('(', min(train_sampler), max(train_sampler), ')')
print('(', min(val_sampler), max(val_sampler), ')')
print('(', min(test_sampler), max(test_sampler), ')')

# 通过原数据根据sampler加载数据
trainloader = DataLoader(myDataset, batch_size=16, sampler=train_sampler, drop_last=False)
valloader = DataLoader(myDataset, batch_size=16, sampler=val_sampler, drop_last=False)
testloader = DataLoader(myDataset, batch_size=16, sampler=test_sampler, drop_last=False)

print(len(trainloader))  # 960 / 16
print(len(valloader))  # 274 / 16
print(len(testloader)) # 138 / 16

在这里插入图片描述

这里还要补充一点,对于torchvision.datasets下的数据集,它只会给你训练集和测试集。如下,以MNIST数据集为例,如果train=True则加载训练集,反之加载测试集。但有时我们还需要一个验证集,所以可以通过采样的方式对测试集再次划分,示例如下

from torch.utils.data import sampler

from torch.utils.data import DataLoader
import torchvision.datasets as dataset
import torchvision.transforms as transforms

#  按照80%的训练数据和20%的验证数据拆分原始训练数据,得到sampler
split_num = int(60000 * 0.8)
index_list = list(range(60000))
train_index, val_index = index_list[:split_num], index_list[split_num:]

train_sampler = sampler.SubsetRandomSampler(train_index)
val_sampler = sampler.SubsetRandomSampler(val_index)


#  原始数据训练数据
train_set = dataset.MNIST(
    root='./data/',
    train=True,
    transform=transforms.ToTensor(),
    download=False
)
#  测试集
test_set = dataset.MNIST(
    root='./data/',
    train=False,
    transform=transforms.ToTensor(),
    download=False
)


if __name__ == '__main__':


    train_loader = DataLoader(train_set, sampler=train_sampler, batch_size=1, drop_last=True)
    val_loader = DataLoader(train_set, sampler=val_sampler, batch_size=1, drop_last=False)
    print(len(train_loader))
    print(len(val_loader))

在这里插入图片描述

(3)Dataloader

DataloaderDatasetSampler等进行打包,完成数据的读取和执行工作,其参数如下,其中dataset为必须参数,其余为可选参数

DataLoader(dataset, batch_size=1, shuffle=False, sampler=None,
           batch_sampler=None, num_workers=0, collate_fn=None,
           pin_memory=False, drop_last=False, timeout=0,
           worker_init_fn=None, *, prefetch_factor=2,
           persistent_workers=False)

常用参数含义如下

  • dataset:传入一个Dataset实例

  • batch_size:指定每一个batch包含的样本数量

    • 什么是batch?:训练时不能把整个数据集全部送入模型中训练,那样内存和显存会吃不消,所以对于我们会将其分为多个batch,一次只送入一个batch进行训练,这里的batch数目最好为2的n次方,例如16,表示一个batch中有16条样本数据
    • 类型int
    • 默认:1
  • shuffle:在每个epoch开始时,会对数据集进行“洗牌”操作,也即重新打乱顺序

    • 什么是epoch?:当数据集中的全部数据样本通过神经网络一次并且返回一次的过程即完成一次训练称为一个epoch
    • 类型bool
    • 默认值False
  • sampler:传入一个自定义的Sampler实例,定义从Dataset中取数据的策略,Sampler会返回一个索引

    • 默认值None
  • batch_sampler:也是传入一个自定义的Sampler实例,但与sampler参数不同的是,它接受的Sampler是一次返回一个batch的索引

    • 默认值None
  • num_workers:定义有多少个线程来处理数据,数值越大,训练速度越快

    • 注意:此参数要根据你CPU、GPU、内存等信息来设定,性能不行,值再高也没效果
    • 类型int
    • 默认:0,此时意味着所有的数据都会被加载进主进程
  • collate_fn:传入一个函数,其作用是将一个batch的样本打包为一个大的tensor,该tensor的第一维就是这些样本。没有特殊需求此参数无需设置

  • pin_mermory:如果为True,表示将加载的数据拷贝至CUDA的固定内存中,可以提升模型的训练速度

    • 类型bool
    • 默认False
  • drop_last:设置batch_size往往会导致数据集无法完整分为若干个batch,比如数据集长度为1000,如果batch_size设置为了64,那么前15个batch中每个batch都有64条数据,最后一个batch只有40条数据。因此如果drop_last设置为了true,那么Dataloader将不会加载最后一个batch

  • 注意:对于训练集一般会设置为True,对于验证集和测试集一般会设置为False

    • 类型bool
    • 默认False
  • timeout:表示加载一个batch的最大等待时间,如果超出该时间还没有加载完毕,就放弃这个batch

    • 类型:int(>=0)
    • 默认:0

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

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

相关文章

【算法与数据结构】排序详解(C语言)

目录 前言 插入排序 希尔排序 选择排序 堆排序 冒泡排序 快速排序 hoare版本 ​编辑 挖坑法 前后指针版本 优化 非递归实现 归并排序 非递归实现 前言 🎄在生活中我们必不可少的就是对一组数据进行排序,所谓排序,就是使一串…

ByteBuffer常用方法与分析

目录 目标 常用API 工具方法 演示案例 allocate(int capacity)和allocateDirect(int capacity) put()和get() flip()和hasRemaining() clear() compact() wrap() 总结 目标 掌握ByteBuffer常用方法,分析ByteBuffer对象在切换读写模式的情况下基本属性的变…

【REDIS】安装配置 可视化工具

Redis作为一个高性能,内存可存储化的no SQL数据库,近两年来发展迅猛,然而并没有比较成熟的管理工具来使用,或者是我不知道 下载redis 并安装: 双击安装,可以安装到d: 盘 配置文件是 .conf Redis作为一个…

排序——快排(递归/非递归)

目录 定义 递归 三种方法 1.hoare法 2.挖坑法 3.双指针法 整体 优化1 优化2 非递归 定义 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集…

快速掌握e语言,以js语言对比,快速了解掌握。

易语言,怎么调试输出,查看内容 在js语言里,弹窗是 alert()在易语言里,弹窗是 信息框 (“弹出显示内容”, 0, “标题”, ); 在js语言里,调试输出是 console.log()在易语言里,调试输出是 调试输出 (“输出内…

开发过程中使用,可以早点下班的coding小技巧

前言 在实际开发过程中,通过时间的沉淀,一些老人常常能写出一些让小白大吃一惊“骚操作”,那些“骚操作”通常简单的离谱,却能做很多事,属实是让很多新人摸不着头脑。 做一件事时间长了,技巧也就有了。 下面来个情景小剧场: 初入职场小鱼仔:这傻逼是不是写错了,~~ s…

基于凸几何和K均值的高光谱端元提取算法(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

Sentinel统一异常处理

五.统一异常处理—BlockException 在上述规则测试中,当违反规则时,出来的异常信息页面不够友好和统一,我们可以通过设置统一的异常处理类,针对不同规则显示不同异常信息。 创建一个配置类,实现BlockExceptionHandler…

numpy数组,numpy索引,numpy中nan和常用方法

一:【numpy数组】 1.1为什么要学习numpy 1.快速 2.方便 3.科学计算的基础库 1.2什么是numpy 一个python中做科学计算的基础库,重在数值计算,也是大部分python科学计算库的基础库,多用于在大型,多维数组上执行数组运…

常用的键盘事件

1、键盘事件 键盘事件触发条件onkeyup某个键盘按键被松开时触发onkeydown某个键盘按键被按下时触发onkeypress某个键盘按键被按下时触发(但它不识别功能键,比如ctrl、shift等) 注意: 如果使用addEventListener不需要加ononkeypr…

Go 堆数据结构使用

说到 container/heap 下的堆数据结构,让我们不需要从零开始实现这个数据结构。如果只是日常工作,其实还挺难用到堆的,更多的还是在写算法题的时候会用到。 基本概念 堆分为大顶堆和小顶堆,区分这两种类型方便我们处理问题。大顶…

Docker安装Zookeeper教程(超详细)

生命无罪,健康万岁,我是laity。 我曾七次鄙视自己的灵魂: 第一次,当它本可进取时,却故作谦卑; 第二次,当它在空虚时,用爱欲来填充; 第三次,在困难和容易之…

第六章:关系数据理论

一、问题的提出、范式 1、【多选题】下列说法中正确的是: 正确答案: ABCD 2、【多选题】关系模式R(项目序号,项目代码,项目名称),项目序号是码。一个项目代码只有一个项目名称。下列说法不正确…

文献检索报告

文献检索第一篇检索作业总结第一章检索任务1.1检索课题1.2确定选题所属学科1.3中英文检索词第二章检索策略与结果2.1检索中文期刊文献2.1.1 CNKI中国期刊全文数据库2.1.2 维普期刊全文数据库2.1.3 万方期刊数据库2.1.4 超星期刊全文2.2检索中文学位论文2.2.1 CNKI博硕学位论文数…

virtio-net发包流程分析

virtio-net发包流程分析 virtio-net发包流程前端驱动部分 总流程 start_xmit|---->free_old_xmit_skbs /* 释放backend处理过的desc */|---->xmit_skb /* 调用xmit_skb函数将网络包写入virtqueue */| |---->sg_set_buf /* 数据包头部填入scatterlist */| | |---->…

手撕红黑树、三种情况就可玩转红黑

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸 文章目录一、红黑树概念二、红黑树性质三、红黑树 插入①变色(c红 p红 g黑 u存在且红)②旋转(c红 p红 g黑 u存在且…

熟人服务器被黑,五种实战方法强化linux服务器安全性!

公司护网行动,五种实战方法,下面直接上实操: 1.修改ssh端口为59527,并开放防火墙端口 修改ssh配置文件 /etc/ssh/sshd_config,将端口号修改为59527.同时保留ssh默认的22端口,为了防止修改端口号失败以后,远程登录不上服务器 2.修改firewall配置 默认情况下,防火墙是…

JVM——垃圾回收

垃圾回收 1、如何判断对象可以回收? 一、引用计数法 当一个对象被其他变量引用时,使其计数1(若被引用两次,计数为2),若某个变量不在引用它时,使其计数-1;当这个对象引用计数变为0时意味着不…

吴恩达【神经网络和深度学习】Week1——深度学习概述

文章目录1、What is a neural network?2、Supervised Learning with Neural Networks2.1、Examples2.2、The classification of data3、Why is Deep Learning taking off?4、Quiz课程笔记整理按照所讲章节的标题来完成1、What is a neural network? 以房价预测模型…

基于HTML5 技术的开放自动化HMI

人机交互接口(HMI)是自动化系统中不可或缺的一部分。传统的做法是提供一个HMI 显示屏,并且通过组态软件来配置显示屏的功能,通过modbus 或者以太网与PLC 连接。 现在,事情变得复杂了许多,用户不仅需要通过专…