美文网首页
pytorch Dataset类

pytorch Dataset类

作者: 三方斜阳 | 来源:发表于2021-02-05 08:12 被阅读0次

    官网:Dataset类

    简介

    Dataset是一个包装类,用来将数据包装为Dataset类,然后传入DataLoader中,我们再使用DataLoader这个类来更加快捷的对数据进行操作。在训练模型时使用到此函数,用来把训练数据分成多个小组,此函数每次抛出一组数据。直至把所有的数据都抛出。就是做一个数据的初始化。


    官网参数

    参数解释:

    dataset:需要load的数据
    batch_size:每个batch的大小,一次返回几条数据处理
    shuffle:是否进行shuffle操作
    num_workers:加载数据的时候使用几个子进程

    使用方式很固定,直接记住代码格式:
    import torch.utils.data as Data
    
    input_batch, target_batch = make_data(sentence)
    dataset = Data.TensorDataset(input_batch, target_batch)
    loader = Data.DataLoader(dataset, batch_size=16, shuffle=True)
    #训练
    for epoch in range(10000):
      for x, y in loader:
          pred = model(x)
          loss = criterion(pred, y)
          if (epoch + 1) % 1000 == 0:
              print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
          optimizer.zero_grad()#torch三件套
          loss.backward()
          optimizer.step()
    ####分割线就是我
    #将数据处理成需要的格式tensor类型
    train_inputs, train_token, train_mask, train_labels=make_data(sentence)
    train_data = Data.TensorDataset(train_inputs, train_token, train_mask, train_labels)
    train_dataloader = Data.DataLoader(train_data, batch_size=batch_size, shuffle=True)
    for _ in range(2):
        for i, batch in enumerate(train_dataloader):#因为数据是四种,所以用迭代器的方式处理,bach=[tensor1,tensor2,tensor3,tensor4]
                batch = tuple(t.to(device) for t in batch)#转换成tuple并且指定cuda运行
                loss = model(batch[0], token_type_ids=batch[1], attention_mask=batch[2], labels=batch[3])[0]
                print(loss.item())
    
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
                
                if i % 10 == 0:
                  eval(model, validation_dataloader)
    

    以上图第二段例子代码来看:
    首先是把原句子输入预处理函数 make_data;这个函数是自己定义的,按照任务要求,一般调用 tokenizer 来处理;举个例子:
    下面是一个预处理的函数示例:

    def make_data(sentences,labels):
        input_ids,token_type_ids,attention_mask=[],[],[]
        #input_ids是每个词对应的索引idx ;token_type_ids是对应的0和1,标识是第几个句子;attention_mask是对句子长度做pad
        #input_ids=[22,21,...499] token_type_ids=[0,0,0,0,1,1,1,1] ;attention_mask=[1,1,1,1,1,0,0,0]补零
        for i in range(len(sentences)):
            encoded_dict = tokenizer.encode_plus(
            sentences[i],
            add_special_tokens = True,      # 添加 '[CLS]' 和 '[SEP]'
            max_length = 96,           # 填充 & 截断长度
            pad_to_max_length = True,
            return_tensors = 'pt',         # 返回 pytorch tensors 格式的数据
            )
            input_ids.append(encoded_dict['input_ids'])
            token_type_ids.append(encoded_dict['token_type_ids'])
            attention_mask.append(encoded_dict['attention_mask'])
      
        input_ids = torch.LongTensor(input_ids)#每个词对应的索引
        token_type_ids = torch.LongTensor(token_type_ids)#0&1标识是哪个句子
        attention_mask = torch.LongTensor(attention_mask)#[11100]padding之后的句子
        labels = torch.LongTensor(labels)#所有实例的label对应的索引idx
    
      return input_ids, token_type_ids, attention_mask, labels
    

    经过这个处理之后的返回值 然后调用 Data.TensorDataset 和 Data.DataLoader;这个其实就是把所有需要的数据都装载到了一个dict 里面,然后被封装好,设定 batch 的大小,然后进行训练:

    train_inputs, train_token, train_mask, train_labels=make_data(sentence)
    train_data = Data.TensorDataset(train_inputs, train_token, train_mask, train_labels)
    train_dataloader = Data.DataLoader(train_data, batch_size=batch_size, shuffle=True)
    for i, batch in enumerate(train_dataloader):
       batch = tuple(t.to(device) for t in batch)#转换成tuple并且指定cuda运行
       loss = model(batch[0], token_type_ids=batch[1], attention_mask=batch[2], labels=batch[3])[0]
     #这里通过batch下标就可以达到访问各个类别训练数据的目的
    

    改写dataset 类

    在我们自己的模型训练中,常常需要使用非官方自制的数据集。
    我们可以通过改写torch.utils.data.Dataset中的getitemlen来载入我们自己的数据集。
    getitem:获取数据集中的数据
    len:获取整个数据集的长度(即个数)
    看下面的一个例子:

    class IMDbDataset(torch.utils.data.Dataset):
        def __init__(self, encodings, labels):
            self.encodings = encodings
            self.labels = labels
    
        def __getitem__(self, idx):
            item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
            item['labels'] = torch.tensor(self.labels[idx])
            return item
    #item={"input_ids":[] ,"token_type_ids":[],"attention_mask":[],"labels":[]}
    
        def __len__(self):
            return len(self.labels)
    
    train_encodings = tokenizer(train_texts, truncation=True, padding=True)
    test_encodings = tokenizer(test_texts, truncation=True, padding=True)
    
    train_dataset = IMDbDataset(train_encodings, train_labels)
    test_dataset = IMDbDataset(test_encodings, test_labels)
    
    train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
    for epoch in range(3):
        for batch in train_loader:
            optim.zero_grad()
            input_ids = batch['input_ids'].to(device)
            attention_mask = batch['attention_mask'].to(device)
            labels = batch['labels'].to(device)
            outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
            loss = outputs[0]
            loss.backward()
            optim.step()
    

    这个例子跟上文例子其实相差不多,只是这个地方把 作为分类任务的 label 数据传入 重写的 dataset 类,加入训练数据的 dict 中
    item={"input_ids":[] ,"token_type_ids":[],"attention_mask":[],"labels":[]}
    上文的例子是直接把 label 和其他类别的训练数据如:input_ids ,attention_mask 等一起传入 Data.TensorDataset() 其实也是一样的目的,这个地方只是给一个简单的例子,表示在实际的任务中,如果需要更加复杂的封装训练数据,需要重写 dataset 类中的这些函数来达到加载数据的目的;

    参数 collate_fn 用法:

    将一个list的sample组成一个mini-batch的函数,可以自定义这个参数,将自己的数据处理成一个 batch,padding mask 等操作:

    def custom_collate(batch):
        transposed = list(zip(*batch))
        lst = []
        # transposed[0]: list of token ids of text
        padded_seq = []
        max_seq_len = len(max(transposed[0], key=len))
        for seq in transposed[0]:
            padded_seq.append(seq + [0] * (max_seq_len - len(seq)))
        lst.append(torch.LongTensor(padded_seq))
    
        # tansposed[1]: list of tag ids of SAME LENGTH!
        padded_tag = []
        att_mask = []
        for seq in transposed[1]:
            padded_tag.append(seq + [0] * (max_seq_len - len(seq)))
            att_mask.append([1] * len(seq) + [0] * (max_seq_len - len(seq)))
        lst.append(torch.LongTensor(padded_tag))
        lst.append(torch.FloatTensor(att_mask))
    
        return lst
    
    dataset = MyDataset(train_tokens, train_tags)
    
    train_loader = DataLoader(dataset=dataset, batch_size=train_batch, collate_fn=custom_collate, shuffle=True)
    
    
    • simple example:
    # a simple custom collate function, just to show the idea
    def my_collate(batch):
        data = [item[0] for item in batch]
        target = [item[1] for item in batch]
        target = torch.LongTensor(target)
        return [data, target]
    

    1.

    from torch.utils.data import TensorDataset, DataLoader, RandomSampler, SequentialSampler
    """定义dataloader,在训练阶段shuffle数据,预测阶段不需要shuffle"""
    
    train_data = TensorDataset(tr_inputs, tr_masks, tr_tags)
    train_sampler = RandomSampler(train_data)
    train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=batch_size)
    
    valid_data = TensorDataset(val_inputs, val_masks, val_tags)
    valid_sampler = SequentialSampler(valid_data)
    valid_dataloader = DataLoader(valid_data, sampler=valid_sampler, batch_size=batch_size)
    
    
    

    参考:
    huggingface fine-tuning with custom dataset
    BERT Fine-Tuning Tutorial with PyTorch · Chris McCormick (mccormickml.com)
    https://ptorch.com/docs/1/utils-data

    相关文章

      网友评论

          本文标题:pytorch Dataset类

          本文链接:https://www.haomeiwen.com/subject/xvqitltx.html