【深度好文】多任务模型中的DataLoader实现

对于多任务学习multi-task-learning(MTL)问题,经常会要求特定的训练过程,比如数据处理,模型结构和性能评估函数.本文主要针对数据处理部分进行展开,主要针对多个标注好的数据集如何来训练一个多任务模型.

本文主要从两个方面进行展开:
1.将两个或多个dataset组合成pytorch中的一个Dataset.这个dataset将会作为pytorch中Dataloader的输入.
2.修改batch产生过程,以确保在第一个batch中产生第一个任务的数据,在第二个batch中产生下一个任务的数据.

为了简单处理,我们将以两个dataset作为例子来讲述.通常来说,dataset的数目以及data的类型不会对我们的整体方案带来太大影响.一个pytorch的Dataset需要实现 __getitem__()函数.这个函数的作用为预取数据并且为给定index准备数据.

第一节 定义dataset

首先,我们先来定义两个dummy dataset,如下所示:

import torch
from torch.utils.data.dataset import ConcatDataset


class MyFirstDataset(torch.utils.data.Dataset):
    def __init__(self):
        # dummy dataset
        self.samples = torch.cat((-torch.ones(5), torch.ones(5)))

    def __getitem__(self, index):
        # change this to your samples fetching logic
        return self.samples[index]

    def __len__(self):
        # change this to return number of samples in your dataset
        return self.samples.shape[0]


class MySecondDataset(torch.utils.data.Dataset):
    def __init__(self):
        # dummy dataset
        self.samples = torch.cat((torch.ones(50) * 5, torch.ones(5) * -5))

    def __getitem__(self, index):
        # change this to your samples fetching logic
        return self.samples[index]

    def __len__(self):
        # change this to return number of samples in your dataset
        return self.samples.shape[0]


first_dataset = MyFirstDataset()
second_dataset = MySecondDataset()
concat_dataset = ConcatDataset([first_dataset, second_dataset])

上述代码中,我们定义了两个dataset,其中第一个dataset长度为10,其中前5个sample为-1,后5个sample为1;其中第二个dataset长度为55,其中前50个sample为5,后5个sample为-5.上述数据集仅仅为了说明方便.在实际应用中,我们应该会同时拥有sample和label,当然我们也可能会从一个目录或者数据库中读取数据,但是上面简单的dataset足够帮助我们来了解整个实现流程.

第二节 定义dataloader

接着我们来定义Dataloader,这里我们使用pytorch中的concat_data来实现两个dataset的合并.
代码如下:

batch_size = 8

# basic dataloader
dataloader = torch.utils.data.DataLoader(dataset=concat_dataset,
                                         batch_size=batch_size,
                                         shuffle=True,
                                         drop_last=True
                                         )

for inputs in dataloader:
    print(inputs)

运行结果如下:

tensor([ 5.,  5.,  5.,  5., -1.,  5.,  5.,  5.])
tensor([ 5.,  1., -1., -1.,  5.,  5.,  5., -5.])
tensor([5., 5., 5., 5., 5., 5., 5., 5.])
tensor([ 5., -5., -5.,  5.,  5.,  5.,  5.,  5.])
tensor([-1.,  5., -1.,  5.,  5.,  5.,  5.,  5.])
tensor([ 5.,  5., -5.,  5.,  5.,  5.,  5.,  1.])
tensor([5., 5., 5., 5., 1., 5., 5., 5.])
tensor([ 5.,  1.,  5., -5.,  5.,  5.,  1.,  5.])

对于我们的concat_dataset来说,每个batch有8个sample.每个sample的次序是随机的.

第三节 定义sampler

到现在为止,上述实现都很简单直接.上述dataset被合并成一个dataset,并且sample都是从原先dataset中随机挑选组合成batch的.现在让我们来写控制每个batch中的sample来源.我们预期达到的目的在每一个batch中,数据仅来自一个task的dataset,在下一个batch中进行切换.此时我们需要自己定义sample,其代码实现如下:

import math
import torch
from torch.utils.data.sampler import RandomSampler


class BatchSchedulerSampler(torch.utils.data.sampler.Sampler):
    """
    iterate over tasks and provide a random batch per task in each mini-batch
    """
    def __init__(self, dataset, batch_size):
        self.dataset = dataset
        self.batch_size = batch_size
        self.number_of_datasets = len(dataset.datasets)
        self.largest_dataset_size = max([len(cur_dataset.samples) for cur_dataset in dataset.datasets])

    def __len__(self):
        return self.batch_size * math.ceil(self.largest_dataset_size / self.batch_size) * len(self.dataset.datasets)

    def __iter__(self):
        samplers_list = []
        sampler_iterators = []
        for dataset_idx in range(self.number_of_datasets):
            cur_dataset = self.dataset.datasets[dataset_idx]
            sampler = RandomSampler(cur_dataset)
            samplers_list.append(sampler)
            cur_sampler_iterator = sampler.__iter__()
            sampler_iterators.append(cur_sampler_iterator)

        push_index_val = [0] + self.dataset.cumulative_sizes[:-1]
        step = self.batch_size * self.number_of_datasets
        samples_to_grab = self.batch_size
        # for this case we want to get all samples in dataset, this force us to resample from the smaller datasets
        epoch_samples = self.largest_dataset_size * self.number_of_datasets

        final_samples_list = []  # this is a list of indexes from the combined dataset
        for _ in range(0, epoch_samples, step):
            for i in range(self.number_of_datasets):
                cur_batch_sampler = sampler_iterators[i]
                cur_samples = []
                for _ in range(samples_to_grab):
                    try:
                        cur_sample_org = cur_batch_sampler.__next__()
                        cur_sample = cur_sample_org + push_index_val[i]
                        cur_samples.append(cur_sample)
                    except StopIteration:
                        # got to the end of iterator - restart the iterator and continue to get samples
                        # until reaching "epoch_samples"
                        sampler_iterators[i] = samplers_list[i].__iter__()
                        cur_batch_sampler = sampler_iterators[i]
                        cur_sample_org = cur_batch_sampler.__next__()
                        cur_sample = cur_sample_org + push_index_val[i]
                        cur_samples.append(cur_sample)
                final_samples_list.extend(cur_samples)

        return iter(final_samples_list)

上述定义了一个BatchSchedulerSampler类,实现了一个新的sampler iterator.首先,通过为每一个单独的dataset创建RandomSampler;接着,在每一个dataset iter中获取对应的sample index;最后,创建新的sample index list.这里我们使用batchsize=8,那么我们将会从每个dataset中预取8个samples.
接着我们来测试上述sampler,代码如下:

import torch
from multi_task_batch_scheduler import BatchSchedulerSampler

batch_size = 8

# dataloader with BatchSchedulerSampler
dataloader = torch.utils.data.DataLoader(dataset=concat_dataset,
                                         sampler=BatchSchedulerSampler(dataset=concat_dataset,
                                                                       batch_size=batch_size),
                                         batch_size=batch_size,
                                         shuffle=False)

for inputs in dataloader:
    print(inputs)

运行结果如下:

tensor([ 1., -1.,  1.,  1., -1., -1., -1.,  1.])
tensor([ 5.,  5.,  5.,  5.,  5., -5.,  5., -5.])
tensor([ 1., -1., -1., -1., -1.,  1.,  1.,  1.])
tensor([5., 5., 5., 5., 5., 5., 5., 5.])
tensor([ 1.,  1., -1., -1.,  1.,  1.,  1.,  1.])
tensor([5., 5., 5., 5., 5., 5., 5., 5.])
tensor([-1.,  1., -1., -1., -1., -1.,  1., -1.])
tensor([-5.,  5.,  5.,  5.,  5.,  5.,  5.,  5.])
tensor([ 1., -1.,  1., -1., -1.,  1., -1.,  1.])
tensor([ 5., -5.,  5.,  5.,  5.,  5.,  5.,  5.])
tensor([-1., -1.,  1., -1.,  1., -1., -1.,  1.])
tensor([ 5.,  5.,  5., -5.,  5.,  5.,  5.,  5.])
tensor([ 1.,  1., -1., -1.,  1.,  1.,  1.,  1.])
tensor([5., 5., 5., 5., 5., 5., 5., 5.])

Wow,综上,我们实现了每一个minibatch仅从一个dataset中取数据的功能,并且下一个minibatch从不同任务的dataset中取batch.

参考:链接

关注公众号《AI算法之道》,获取更多AI算法资讯.
在这里插入图片描述

  • 14
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 要用PyTorch实现BERT的文多分类任务,可以按照以下步骤进行: 1. 准备数据:首先需要将文多分类数据集准备好,并对其进行处理,使其适合输入BERT模型。可以使用PyTorch提供的DatasetDataLoader类来加载数据集,并将文本数据转化为BERT模型需要的张量形式。 2. 加载预训练模型:PyTorch提供了许多已经在海量文本数据上预训练好的BERT模型。可以使用HuggingFace提供的transformers库的预训练模型进行加载。 3. 修改网络结构:加载预训练模型后,需要对其进行微调,以适应文多分类任务。可以添加一个全连接层,将预训练模型的输出连接到全连接层,从而得到最终的分类结果。 4. 训练模型:将准备好的数据集输入到BERT模型,使用反向传播算法更新模型参数,直到训练损失收敛。 5. 模型评估:使用测试集对模型进行评估,可以计算准确率、精度、召回率等指标,以评估模型的性能。 以上是使用PyTorch实现BERT文多分类的大致步骤。具体实现需要参考相关文档和代码。 ### 回答2: PyTorch是一个非常流行的深度学习库,可以用于实现BERT文多分类任务。下面我将简要介绍如何使用PyTorch实现这个任务。 首先,我们需要安装PyTorch和transformers(一个用于自然语言处理的库,其包括了预训练的BERT模型)。 接下来,我们需要加载预训练的BERT模型和tokenizer。你可以通过以下代码加载文的BERT模型: ```python from transformers import BertForSequenceClassification, BertTokenizer model_name = 'bert-base-chinese' num_labels = 10 # 根据你的分类任务设定类别数量 tokenizer = BertTokenizer.from_pretrained(model_name) model = BertForSequenceClassification.from_pretrained(model_name, num_labels=num_labels) ``` 然后,我们需要加载和预处理我们的数据。你可以使用PyTorchDatasetDataLoader来完成这个任务。你需要将你的文本数据转换为BERT可以理解的格式: ```python # 假设你的数据是一个包含文本和标签的列表 data = [ {'text': '这是文本1', 'label': 0}, {'text': '这是文本2', 'label': 1}, # 更多样本... ] # 将文本转换为BERT可以理解的格式 inputs = tokenizer.batch_encode_plus( [item['text'] for item in data], pad_to_max_length=True, max_length=512, # 根据你的文本长度设定 truncation=True, return_tensors='pt' ) # 创建PyTorchDataset dataset = torch.utils.data.TensorDataset( inputs['input_ids'], inputs['attention_mask'], torch.tensor([item['label'] for item in data]) ) # 创建PyTorchDataLoader dataloader = torch.utils.data.DataLoader( dataset, batch_size=16, # 根据你的显存大小设定 shuffle=True ) ``` 最后,我们可以开始训练模型。下面是一个非常简单的训练循环: ```python device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model.to(device) optimizer = torch.optim.AdamW(model.parameters(), lr=1e-5) for epoch in range(10): # 根据你的训练需求设定迭代次数 model.train() for input_ids, attention_mask, labels in dataloader: input_ids = input_ids.to(device) attention_mask = attention_mask.to(device) labels = labels.to(device) optimizer.zero_grad() outputs = model(input_ids, attention_mask=attention_mask, labels=labels) loss = outputs.loss loss.backward() optimizer.step() ``` 这是一个简单的PyTorch实现BERT文多分类的示例。你可以根据你的具体任务需求进行适当的修改和调整。同时,你可能还需要评估模型和保存/加载模型等操作。 ### 回答3: PyTorch是一个开源深度学习框架,可以方便地实现BERT文多分类任务。下面是一个使用PyTorch实现BERT文多分类的简单示例: 1. 数据准备:首先,需要准备用于训练和测试的文文本数据集。数据集应包含已经标注好类别的样本。 2. 数据预处理:使用文分词工具对文本数据进行分词处理,并根据需要进行数据清洗和处理。可以使用NLTK或jieba等开源文分词工具。 3. BERT模型加载:从Hugging Face的Transformers库导入预训练的BERT模型和tokenizer。可以选择不同的文BERT模型,如BERT-Base、BERT-Large等。 4. 构建模型:使用PyTorch构建BERT分类模型。根据需要,可以添加dropout层、全连接层等。 5. 设置优化器和损失函数:选择一个合适的优化器和损失函数,如Adam优化器和交叉熵损失函数。 6. 训练模型:使用训练数据来训练BERT模型。可以选择合适的epochs、batch size等参数。 7. 模型评估:使用测试数据对训练好的模型进行评估。计算模型在测试集上的准确率、精确率、召回率等指标。 8. 模型应用:使用已经训练好的模型对新的文文本进行分类预测。 需要注意的是,以上是一个简要的流程,实际应用还需要对数据进行进一步处理和优化,例如处理不平衡的类别分布、调整模型参数等。此外,还可以使用交叉验证等技术来进一步提高模型的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵卓不凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值