数据集搭建

一、数据集

  在深度学习中,数据集扮演着至关重要的角色。它们是训练机器学习模型的基础,决定了模型能够学习到的模式和特征。要训练自己的模型,首要任务就是找到需要的合适数据集。可以通过在网上查找资源、雇佣人力采集、自己采集等方式实现数据的采集工作。按照给定的标签格式分类,这些数据集可以分类为:

  • 单标签数据集:标签表示所属类别,用于分类任务
  • 多标签数据集:一个样本可以属于多类的情况
  • 回归标签数据集:表示样本连续值,用于回归任务

  数据集划分:假设你已经拥有了所需要的数据集(别急,下一节会介绍如何构建自己的数据集并将其封装为模型需要的格式),那么如何使用数据集对模型进行训练与评估呢,重要的一点是如何划分训练集与测试集,而训练集又可细分为训练集与验证集,常用的数据集比例为训练集:验证集:测试集=6:2:2,这是对于数据足够的情况下。若数据集采集到的数据量有限,那就可以考虑使用N折交叉验证来对模型进行训练与评估。


二、数据集搭建

  pytorch中提供了Dataset类与Dataloader类可以帮助我们很轻松的完成数据集的构造工作。这里需要知道,我们使用这两类进行构造,是为了将数据转化为模型所接受的形式——张量,也就是tensor形式(tensor可以认为是一种数据的形式,就像矩阵、数组一样,其可以是一维的,也可以是多维的,与矩阵或数组不同的是,tensor可以携带梯度信息)
  Dataset类是将需要训练的数据转化为训练数据+标签的格式,并将其以列表的形式返回。拿图像分类任务举例,Dataset返回类型为图像处理后得到的矩阵与该图像所属的类别标签。Dataloader则负责将数据集以batchsize大小划分,得到训练数据的张量与标签的张量。
下面是Dataset类的模板:

class MyDataSet(Dataset):
    def __init__(self):
        self.data=......
        self.label=......
 
    def __getitem__(self, item):
        data= ...
        label= ...
        return data, label
 
    def __len__(self):
        return len(self.data)

  在构建自己的数据集时,只需要继承父类Dataset,并重写__getitem__方法与__len__方法,这两个是必不可少的,其他的可以根据需求添加,比如我可以加一个比较大小的函数(如果需要的话)。Dataset类本质上获取数据集是通过__getitem__方法中的索引item查找列表中的item项,__len__方法则是确定可访问列表长度,即item的最大值是多少。


三、不同数据集加载方式

  在构建自己的数据集时,个人笔记本配置不同,所带有的运行内存也不同。构建的数据集有大有小,小数据集或许只有几十MB,大数据集可以达到几百个GB。提前加载到内存中的数据集比在磁盘上边读取边构建数据集运行起来要节省时间。因此就需要权衡利弊,看是否需要一次性加载到内存中增加运行速度,还是分次加载到内存中以节约内存空间。这就是数据集的不同加载方法,数据集较小,内存充足则推荐使用一次性加载,因为其可以提高数据访问的效率。数据集大,内存小则使用多次加载,这样会多次访问磁盘进行数据加载工作,节省内存但是降低效率。

  那么如何实现一次性加载与多次加载呢?很简单,前面我们已经提到了Dataset类的重写,即实现__init__、__getitem__与 __len__方法即可。将数据集一次性加载到内存中,可以在 __init__方法中实现,多次加载数据集则在__getitem__方法中实现。使用__init__实现一次性加载时,__init__接受的参数输入为实际的数据列表与标签列表,在此方法中实现对数据的处理构造工作,__getitem__用来访问处理完后的列表中的元素。多次加载时,__init__函数接受的参数为文件地址列表与标签列表,在 __getitem__方法中实现对数据的具体处理。下面使用两段代码来展示不同数据加载方式。

3.1 一次性加载

  假设我有一个用于训练的npy文件,此文件中的每一行都是一个训练单元。前面的n个元素是训练的数据,最后一个元素是标签或者预测值。构建数据集则需要做的是,将此文件读入到内存中并进行处理,获取到所需要的数据列表与标签列表。

from torch.utils.data import Dataset
import numpy as np
class Mydataset(Dataset):
    def __init__(self,root):
        #root为文件地址
        self.file=[]#存储数据的列表
        self.label=[]#存储标签的列表
        data = np.load(root)#读取数据文件,此文件存储的为1000*7的数组
        #假设每一行的前面六个数字是训练数据,最后一位是标签或者预测值
        for _,i in enumerate(data):#以行为序号遍历
            self.file.append(i[0:-1])#训练数据
            self.label.append(i[-1])#标签
    def __getitem__(self, item):
        data=self.file[item]#获取指定序号的数据
        label=self.label[item]#获取指定序号的标签
        return data,label
    def __len__(self):
        return len(self.file)

  上述代码中,root是文件的地址,传入的文件类型是npy类型,可以使用下面代码生成一个npy文件试验进一步理解下。其他类型的文件的处理与此类似,均是将数据文件读入后进行处理,并将每个训练单元(此例子中为一行)加入到数据列表与标签列表中。

import numpy as np
from dataser import Mydataset
x=np.random.rand(1000,7)
np.save('test.npy',x)
data=Mydataset('test.npy')
print("数据集构建成功,长度为",len(data))

3.2 分批次加载

  这里我们以一个图形分类任务为例,假设我有一个文件夹objects,文件夹下有4个子文件夹,分别是people,car,animal,plant。每个子文件夹下都有若干张图像,例如people文件夹下包含着若干张拍摄的人的图像。要进行分批次读取数据集,我们需要将文件地址处理为列表,并对各个文件夹设置标签。获取文件地址列表与对应的标签列表的代码read_file.py如下所示:

import os
# 设置要遍历的根目录
root_dir = 'plot'
# 初始化图片路径列表和标签列表
def readlist(root):
    image_paths = []
    labels = []
    # 创建标签到数字的映射字典
    label_to_id = {}
    next_id = 0
    # 遍历根目录及其所有子文件夹
    for dirpath, dirnames, filenames in os.walk(root_dir):
        # 获取当前文件夹的名称作为标签
        label = os.path.basename(dirpath)
        # 如果标签还未在映射字典中,则添加新的标签编号
        if label not in label_to_id:
            label_to_id[label] = next_id
            next_id += 1
        # 遍历当前文件夹下的所有文件
        for filename in filenames:
            # 判断文件是否为图片文件
            if filename.endswith('.jpg') or filename.endswith('.png') or filename.endswith('.jpeg'):
                # 获取图片的完整路径
                image_path = os.path.join(dirpath, filename)
                # 获取当前标签的编号
                label_id = label_to_id[label]
                # 添加图片路径和标签编号到各自的列表中
                image_paths.append(image_path)
                labels.append(label_id)
    # 打印结果
    print("图片路径列表:")
    print(image_paths)
    print("标签列表:")
    print(labels)
    print("标签到编号的映射:")
    print(label_to_id)
    return image_paths,labels
readlist(root_dir)

  上述代码为遍历文件夹,将文件名转为数字标签,里面的图像地址加入到图像地址列表中,打印的代码可以删除掉,此处为了方便验证而添加。下面的代码将演示,如何实现多次加载数据集。

from torch.utils.data import Dataset
from file import read_file
from torchvision import transforms
from PIL import Image
class Mydataset(Dataset):
    def __init__(self,image,label,transform=None):
        #image为图像地址的列表,label为标签列表
        self.file=image
        self.label=label
        self.transform=transform if not None else None
    def __getitem__(self, item):
        #处理每一个读入的图像
        root = self.file[item]#图像地址
        image = Image.open(root)#图像类别标签
        if self.transform:#进行图像变换(若需要)
            image=self.transform(image)
        label=self.label[item]#获取指定序号的标签
        return image,label
    def __len__(self):
        return len(self.file)
transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
#如何使用
root = "plot"#你的文件夹路径
ima,la = readlist(root)#获取图像与标签列表
mydataset=Mydataset(ima,la,transform)#创建数据集

  代码中我们构建了自己的数据集,构建数据集需要图像地址列表与图像标签列表,图像变换可以在需要的情况下去添加。


四、数据集使用

  在重写Dataset类后,我们面对的问题是,如何将数据集转化为模型接受的张量形式。很简单,只需要调用Dataloader类即可。此类可以按照设置的批量大小构造输入张量,并返回张量列表。假设数据集长度为100,即100个训练样本。设置batchsize为5,则Dataloader类会返回一个100/5=20个元素的列表,每个列表元素是一个包含5个训练样本的张量。

from torch.utils.data import Dataloader
#数据集是traindata
trainloader = Dataloader(traindata,batch_size=5,
shuffle=True,num_workers=0,drop_last=False )
for trainer,label in enumerate(trainloader):
    ...训练代码,,,

这里对参数进行一下具体介绍:

  • batch_size:参数是批量大小,即一次使用几个训练样本。
  • shuffle:是否在每个epoch中打乱样本顺序,将整个数据集训练一遍叫做一个epoch,True表示打乱,默认为False。
  • num_works:表示需要加载数据的子进程,默认0,使用主进程加载,可以根据自己的设备设定。
  • drop_last:最后一个批次中的样本数量小于设定的batchsize是否需要丢弃,True表示丢弃,默认False。

总结

  以上就是分享的如何搭建自己的数据集的知识,如有任何疑问或任何纰漏,请批评指正,不吝赐教,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值