PyTorch:数据读取1 - Datasets和TensorDataset

本文介绍PyTorch中数据加载的高效方式,包括使用DataLoader进行mini-batch处理,自定义Datasets类以适应不同数据源,并展示官方MNIST数据集的处理流程。
部署运行你感兴趣的模型镜像

-柚子皮-

Datasets

在输入流水线中,准备数据的代码是这么写的

data = datasets.CIFAR10("./data/", transform=transform, train=True, download=True)

datasets.CIFAR10就是一个Datasets子类,data是这个类的一个实例。

为什么要定义Datasets?

PyTorch提供了一个工具函数torch.utils.data.DataLoader。通过这个类,我们可以让数据变成mini-batch,且在准备mini-batch的时候可以多线程并行处理,这样可以加快准备数据的速度。

Datasets就是构建这个类的实例的参数之一。

DataLoader的使用参考[PyTorch:数据读取2 - Dataloader]。

数据集划分

1 建议使用sklearn.preprocessing.model_selection

ds_train, ds_eval = model_selection.train_test_split(dataset, test_size=0.2, shuffle=args.if_shuffle_data)

2 train_size = int(0.8 * len(full_dataset))
test_size = len(full_dataset) - train_size
train_dataset, test_dataset = torch.utils.data.random_split(full_dataset, [train_size, test_size])

Note: dataloader应该是不能进行划分的。

[Pytorch划分数据集的方法]

自定义Datasets

框架

dataset必须继承自torch.utils.data.Dataset。

内部要实现两个函数:

        一个是__lent__用来获取整个数据集的大小;

        一个是__getitem__用来从数据集中得到一个数据片段item

import torch.utils.data as data
class CustomDataset(data.Dataset):
    """Custom data.Dataset compatible with data.DataLoader."""

    def __init__(self, filename, data_info, oth_params):
        """Reads source and target sequences from txt files."""
        # # # 从文件中读取数据
        self.file = open(filename, 'r')
        ...
        # # # 或者从外部数据结构data_info中读取数据
        self.all_texts = data_info['all_texts']
        self.all_labels = data_info['all_labels']

        # # # 构建字典,映射token和id
        self.vocab = data_info['vocab']

    def __getitem__(self, index):
        """Returns one data pair (source and target)."""
        # # # 从文件读取
        # 1. Read one data from file (e.g. using numpy.fromfile, PIL.Image.open).
        # 2. Preprocess the data (e.g. torchvision.Transform或者word2id什么的).
        # 3. Return a data pair(source and target) (e.g. image and label).

        # # # 或者直接读取
        item_info = {
            "text": self.all_texts[index],
            "label": self.all_labels[index]
        }
        return item_info

    def __len__(self):
        # return the total size of your dataset.
        return len(self.all_texts)

示例

从文件中读取数据写入Dataset

class Dataset(torch.utils.data.Dataset):
    def __init__(self, filepath=None,dataLen=None):
        self.file = filepath
        self.dataLen = dataLen
        
    def __getitem__(self, index):
        A,B,path,hop= linecache.getline(self.file, index+1).split('\t')
        return A,B,path.split(' '),int(hop)

    def __len__(self):
        return self.dataLen

随机mock一个分类数据

class Dataset(data.Dataset):
    """Custom data.Dataset compatible with data.DataLoader."""

    def __init__(self, df, lang: Lang):
        inputs_dim = vars(Config)['inputs_dim']
        self.x = torch.randint(0, 5, (5, inputs_dim), dtype=torch.float)

        self.label = torch.tensor([0, 0, 1, 1, 0, 1, 0, 1, 0, 1], dtype=torch.float)

        self.src_word2id = lang.word2id
        self.trg_word2id = lang.word2id
        # self.mem_word2id = mem_word2id

    def __getitem__(self, index):
        """Returns one data pair (source and target)."""
        x = self.x[index]
        label = self.label[index]

        item_info = {
            "x": x,
            "label": label
        }
        return item_info

官方MNIST的例子

(代码被缩减,只留下了重要的部分):

class MNIST(data.Dataset):
    def __init__(self, root, train=True, transform=None, target_transform=None, download=False):
        self.root = root
        self.transform = transform
        self.target_transform = target_transform
        self.train = train  # training set or test set

        if download:
            self.download()

        if not self._check_exists():
            raise RuntimeError('Dataset not found.' +
                               ' You can use download=True to download it')

        if self.train:
            self.train_data, self.train_labels = torch.load(
                os.path.join(root, self.processed_folder, self.training_file))
        else:
            self.test_data, self.test_labels = torch.load(os.path.join(root, self.processed_folder, self.test_file))

    def __getitem__(self, index):
        if self.train:
            img, target = self.train_data[index], self.train_labels[index]
        else:
            img, target = self.test_data[index], self.test_labels[index]

        # doing this so that it is consistent with all other datasets
        # to return a PIL Image
        img = Image.fromarray(img.numpy(), mode='L')

        if self.transform is not None:
            img = self.transform(img)

        if self.target_transform is not None:
            target = self.target_transform(target)

        return img, target

    def __len__(self):
        if self.train:
            return 60000
        else:
            return 10000

-柚子皮-

TensorDataset

TensorDataset本质上与python zip方法类似,对数据进行打包整合。
官方文档[torch.utils.data — PyTorch 2.0 documentation]

源码说明:r"""Dataset wrapping tensors.

    Each sample will be retrieved by indexing tensors along the first dimension.

    Args: *tensors (Tensor): tensors that have the same size of the first dimension.
    """

该类通过每一个 tensor 的第一个维度进行索引。因此,该类中的 tensor 第一维度必须相等。

import torch
from torch.utils.data import TensorDataset

# a的形状为[4, 3], b的形状为[4], b的第一维与a相同
a = torch.tensor([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]])
b = torch.tensor([1, 2, 3, 4])
train_data = TensorDataset(a, b)
print(train_data[0])
# (tensor([1, 1, 1]), tensor(1))
print(train_data[0:2])
# (tensor([[1, 1, 1],
#  [2, 2, 2]]), tensor([1, 2]))

取数据的时候,如上就是取每个tensor的下标对应数据后再组合成类似tuple的对象。 

from: -柚子皮-

ref: [pytorch学习笔记(六):自定义Datasets]

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

import torch # torch框架 from torch.optim import optimizer from torch.utils.data import TensorDataset # 把目标值转化为TensorDataset from torch.utils.data import DataLoader # 使用DataLoader构建一个可迭代的对象 import torch.nn as nn # 构建模型需要的torch.nn import torch.optim as optim # 优化器 from sklearn.datasets import make_regression from sklearn.model_selection import train_test_split # 帮助我们把训练集划分 import matplotlib.pylab as plt # 绘图 import numpy as np # 数据处理 import pandas as pd import time # 构建数据集 from torchsummary import summary # 导入summary工具包 def create_dataset(): # 使用pandas读取数据 data = pd.read_csv('D:/python/手机价格预测.csv') # 特征值目标值 # iloc 使用语法为 .iloc[行位置, 列位置] :表示所有行 x, y = data.iloc[:, :-1], data.iloc[:, -1] # 类型转换:特征值,目标值 x, y = x.astype(np.float32), y.astype(np.int64) # y = y.astype(np.int64) 以上简化写法 # 数据集划分 train目标值 valid特征值 x_train, x_valid, y_train, y_valid = train_test_split(x, y, train_size=0.8, random_state=88) # 构建数据集,转化为pytorch的形式 train_dataset = TensorDataset(torch.from_numpy(x_train.values), torch.tensor(y_train.values)) valid_dataset = TensorDataset(torch.from_numpy(x_valid.values), torch.tensor(y_valid.values)) # 返回结果 return train_dataset, valid_dataset, x_train.shape[1], len(np.unique(y)) # 模型实例化 # 确保代码块只在脚本直接运行时执行,而不是在导入模块时执行。 if __name__ == '__main__': # 获取数据 train_dataset, valid_dataset, input_dim, class_num = create_dataset() print('输入特征数', input_dim) print('分类个数', class_num) class Model(nn.Module): def __init__(self, input_dim, output_dim): # super()允许子类在不需要明确指定父类名称的情况下调用父类的方法 super(Model, self).__init__() """ nn.Linear是PyTorch库中定义的一个线性变换层,常用于神经网络中。 它执行一个简单的线性变换y=Wx+b,其中W是权重矩阵,b是偏置向量。 """ self.l1 = nn.Linear(20, 128) self.l2 = nn.Linear(128, 256) self.l3 = nn.Linear(256, 4) def forward(self, x): x = torch.relu(self.l1(x)) x = torch.relu(self.l2(x)) out = self.l3(x) return out # 模型实例化 if __name__ == '__main__': # 使用给定的input_dimclass_num参数实例化一个名为Model的神经网络模型。 model = Model(input_dim, class_num) # 将模型从CPU移动到GPU上,以便利用GPU加速计算。这一步需要确保系统上有可用的CUDA设备。 model = model.to('cuda') # 使用summary函数(通常来自torchinfo库)打印模型的结构信息。 # 这里指定了输入数据的形状批量大小。 # input_size参数指定了输入张量的形状(不包括批次维度),batch_size指定了批次大小。 summary(model, input_size=(input_dim,), batch_size=16) # 模型训练 def train(dataset): # 初始化模型 model = Model() # 损失函数 loss = nn.CrossEntropyLoss() # 优化方法 optim.SGD(model.parameters(), lr=0.001) # 训练轮数 epochs = 50 # 遍历每个轮数的数据 for epochs in range(epochs): # 初始化数据加载器 dataloader = DataLoader(dataset, shuffle=True, batch_size=8) # 计算损失 total_loss = 0 total_num = 1 # 遍历每个批次数据进行处理 for x, y in dataloader: # 将数据送入网络中进行预测 predict = model(x) # 计算损失值 loss_values = loss(predict, y) # 梯度清零 optimizer.zero_grad() # 反向传播 loss_values.backwar() # 参数更新 optimizer.step() # 损失计算 total_loss += loss_values.item() total_num += 1 # 打印损失变换的结果 epochs+1轮次 # total_loss/total_num平均损失 # 保存在"D:\python\phone.pth" print(epochs + 1, total_loss / total_num) torch.save(model.state_dict(), "D:\python\phone.pth") # 模型训练 调用训练函数 train_data, test_dataset, _ = create_dataset() train(dataset=train_data) 检查以上问题
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值