第N3周:NLP中的数据集构建

      本人往期文章可查阅: 深度学习总结

   

       对于初学者,NLP中最烦人的问题之一就是数据集的构建问题,处理不好就会引起shape问题(各种由于shape错乱导致的问题)。这里我给出一个模板,大家可根据这个模板来构建。

       torch.utils.data PyTorch 中用于数据加载和预处理的模块。其中包括 Dataset DataLoader  两个类,它们通常结合使用来加载和处理数据。

1. Dataset

       torch.utils.data.Dataset 是一个抽象类,用于表示数据集。它需要用户自己实现两个方法: __len__ __getitem__ 。其中, __len__ 方法返回数据集的大小, __getitem__ 方法用于根据给定的索引返回一个数据样本。

以下是一个简单的示例,展示了如何定义一个数据集:

import torch
from torch import nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader,Dataset

class MyDataset(Dataset):
    def __init__(self,texts,labels):
        self.texts=texts  # 存储文本数据
        self.labels=labels  # 存储标签数据
        
    def __len__(self):
        return len(self.labels)  # 返回数据集的长度(样本数量)
    
    def __getitem__(self,idx):
        texts=self.texts[idx]  # 获取第 idx 个文本
        labels=self.labels[idx]  # 获取第 idx 个标签
        return texts,labels  # 返回文本和标签

        在这个示例中,MyDataset 继承了torch.utils.data.Dataset 类,并实现了 __len__ __getitem__ 方法。__len__ 方法返回数据集的大小,这里使用了 Python 内置函数 len __getitem__ 方法根据给定的索引返回一个数据样本,这里返回的是数据列表中对应的元素。

2. DataLoader

        torch.utils.data.DataLoader 是PyTorch 中一个重要的类,用于高校加载数据集。它可以处理数据的批次化、打乱顺序、多线程数据加载等功能。以下是一个简单的示例:

# 假设我们有以下三个样本,分别由不同数量的单词索引组成
text_data=[
    torch.tensor([1,2,3,4],dtype=torch.long), # 样本1
    torch.tensor([4,3,2],dtype=torch.long), # 样本2
    torch.tensor([1,2],dtype=torch.long)  # 样本3
]

# 对应的标签
labels=torch.tensor([1,0,1],dtype=torch.float)

# 创建数据集和数据加载器
my_dataset=MyDataset(text_data,labels)
data_loader=DataLoader(my_dataset,batch_size=2,shuffle=True,collate_fn=lambda x:x)

for batch in data_loader:
    print(batch)

代码输出:

[(tensor([1, 2]), tensor(1.)), (tensor([4, 3, 2]), tensor(0.))]
[(tensor([1, 2, 3, 4]), tensor(1.))]

       在这个示例中,我们首先创建了一个 MyDatase 实例 my_dataset ,它包含了一个整数列表。然后,我们使用 DataLoader 类创建了一个数据加载器 data_loader ,它将 data_loader 作为输入,并将数据分成大小为4的批次,并对数据进行随机化。最后,遍历 data_loader ,并打印出每个批次的数据。

3. DataLoader参数讲解

函数原型:

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,
)

常用的参数:

1. dataset:一个数据集对象,必须实现  __len__  和 __getitem__ 方法。

2. batch_size:每个batch的大小。

3. shuffle:是否对数据进行洗牌(随机打乱)。

4. sampler:一个数据采样器,用于对数据进行自定义采样。

5. batch_sampler:一个batch采样器,用于对batch进行自定义采样。

6. num_workers:用于数据加载的子进程数量。默认值为0,表示在主进程中加载数据。

7. collate_fn:用于将一个batch的数据合并成一个张量或者元组。

8. pin_memory:是否将数据存储在pin memory中(锁定物理内存,用于GPU加速数据传输),默认值为False。

9. drop_last:如果数据不能完全分成batch,是否删除最后一批数据。默认为False。

10. timeout:当数据加载器陷入死锁时,等待数据准备的最大秒数。默认值为0,表示无线等待。

11. worker_init_fn:用于每个数据加载器进程的初始化函数。可以用来设置特定的随机种子。

12. multiprocessing_context:用于创建数据加载器子进程的上下文。

       以上是  torch.utils.data.DataLoader 中一些常用的参数,使用时根据实际情况选择相应的参数组合。

3.1 sampler参数详解

       sampler 是一个用于指定数据集采样方式的类,它控制 DataLoader 如何从数据集中选取样本。PyTorch 提供了多种 Sampler 类,例如 RandomSampler 和 SequentialSampler ,分别用于随机采样和顺序采样。以下是一个示例:

from torch.utils.data.sampler import RandomSampler

my_sampler=RandomSampler(my_dataset)

my_dataloader=data.DataLoader(
    my_dataset,
    batch_size=4,
    shuffle=False,
    sampler=my_sampler
)

       在这个示例中,我们使用 RandomSampler 类来指定采样方式,然后将其传递给 DataLoader sampler 参数。这将覆盖默认的 shuffle 参数,使数据集按照 sampler 指定的采样方式进行。 

       通常情况下,sampler 的值取决于 shuffle 参数的设置:

默认值

  • 如果 shuffle=False

    • 默认的 samplertorch.utils.data.SequentialSampler

    • 这种采样器会按顺序遍历数据集,不进行任何随机打乱。

  • 如果 shuffle=True

    • 默认的 samplertorch.utils.data.RandomSampler

    • 这种采样器会在每个 epoch 开始时随机打乱数据集。

4. 自定义Dataset类

       除了使用 torchvision.datasets 中提供的数据集,我们还可以使用 torch.utils.data.Dataset 类来自定义自己的数据集。自定义数据集需要实现 __len____getitem__ 方法。

  • __init__ :用来初始化数据集
  • __len__ :方法返回数据集中样本的数量
  • __getitem__ :给定索引值,返回该索引值对应的数据;它是 python built-in 方法,其主要作用是能让该类可以像list一样通过索引值对数据进行访问。

以下是一个示例:

class MyDataset(data.Dataset):
    def __init__(self,data_path):
        self.data_list=torch.load(data_path)
        
    def __len__(self):
        return len(self.data_list)
    
    def __getitem__(self,index):
        x=self.data_list[index][0]
        y=self.data_list[index][1]
        return x,y

       在这个示例中, MyDataset 类继承自 torch.utils.data.Dataset 类,实现了 __len__ 和 __getitem__ 方法。MyDataset 类的构造函数接受一个数据路径作为参数,数据集被保存为一个由数据-标签对组成的列表。

示例:

假设文件内容如下:

data = [
    (torch.tensor([1, 2, 3]), torch.tensor(0)),  # 样本1
    (torch.tensor([4, 5, 6]), torch.tensor(1)),  # 样本2
    (torch.tensor([7, 8, 9]), torch.tensor(0))   # 样本3
]
torch.save(data, 'data.pt')

使用 MyDatasetDataLoader 加载数据

import torch
from torch.utils.data import DataLoader

# 自定义数据集
class MyDataset(torch.utils.data.Dataset):
    def __init__(self, data_path):
        self.data_list = torch.load(data_path)
        
    def __len__(self):
        return len(self.data_list)
    
    def __getitem__(self, index):
        x = self.data_list[index][0]
        y = self.data_list[index][1]
        return x, y

# 示例数据路径
data_path = 'data.pt'

# 创建数据集
dataset = MyDataset(data_path)

# 创建 DataLoader
data_loader = DataLoader(dataset, batch_size=2, shuffle=True)

# 遍历 DataLoader
for batch in data_loader:
    x, y = batch
    print("Batch X:", x)
    print("Batch Y:", y)

由于shuffle=True,输出可能如下:

Batch X: tensor([[1, 2, 3],
                 [4, 5, 6]])
Batch Y: tensor([0, 1])
Batch X: tensor([[7, 8, 9]])
Batch Y: tensor([0])

5. 自定义Sampler类

       除了使用 torch.utils.data.sampler 中提供的采样器,我们还可以使用 Sampler 类来自定义自己的采样器。自定义采样器需要实现 __iter____len__ 方法。

  • __iter__ 方法返回一个迭代器,用于遍历数据集中的样本索引。
  • __len__ 方法返回数据集中样本的数量。

以下是一个示例:

class MySampler(Sampler):
    def __init__(self,data_source):
        self.data_source=data_source
    
    def __iter__(self):
        return iter(range(len(self.data_source)))
    
    def __len__(self):
        return len(self.data_source)

       在这个示例中,MySampler 类继承自 torch.utils.data.sampler.Sampler 类,实现了 __iter____len__ 方法。

示例:

假设数据集为

data = [torch.tensor([1, 2, 3]), torch.tensor([4, 5, 6]), torch.tensor([7, 8, 9])]
dataset = MyDataset(data)

使用自定义采样器

from torch.utils.data import Sampler

class MySampler(Sampler):
    def __init__(self, data_source):
        self.data_source = data_source

    def __iter__(self):
        return iter(range(len(self.data_source)))

    def __len__(self):
        return len(self.data_source)

# 创建自定义采样器
sampler = MySampler(dataset)

# 创建 DataLoader,使用自定义采样器
data_loader = DataLoader(dataset, batch_size=2, sampler=sampler)

# 遍历 DataLoader
for batch in data_loader:
    print(batch)

输出:

tensor([[1, 2, 3],
        [4, 5, 6]])
tensor([[7, 8, 9]])

6. 自定义Transform类

       除了使用 torchvision.transforms 中提供的变化,我们还可以使用 transforms 模块中的 Compose 类来自定义自己的变化。Compose 类将多个变换组合在一起,并按照顺序应用它们。

以下是一个示例:

from torchvision import transforms

class MyTransform(object):
    def __call__(self,x):
        x=self.crop(x)
        x=self.to_tensor(x)
        return x
    
    def crop(self,x):
        # 这里实现裁剪变换
        # …………
        return x
    
    def to_tensor(self,x):
        # 这里实现张量化变换
        # …………
        return x

my_transform=transforms.Compose([
    MyTransform()
])

# 创建数据集和数据加载器
my_dataset=MyDataset(data_path)
my_dataloader=DataLoader(
    my_dataset,
    batch_size=32,
    shuffle=True,
    num_workers=4
)

# 遍历数据集
for batch in my_dataloader:
    # 在这里处理数据批次
    pass

       在这个示例中, MyTransform 类实现了一个自定义的变换,它将裁剪和张量化两个变换组合在一起。transforms.Compose 将这个自定义变换组合成一个变换序列,并在数据集的每个样本上应用这个序列。

你可能感兴趣的:(自然语言处理,深度学习,pytorch)