美文网首页
Bert中transformers的一些问题记录

Bert中transformers的一些问题记录

作者: IT_小马哥 | 来源:发表于2020-10-31 12:05 被阅读0次

    我觉得最详细的就是这个:这里

    dataset返回多模态信息

    • 在处理个人数据集的时候有有时需要返回多模态信息,可以将多模态信息包装为一个字典返回,然后用DataLoader接受就行
    lass ExampleDataset(Dataset):
        def __init__(self, ):
            pass
    
        def __len__(self):
            pass
    
        def __getitem__(self, index):
            return {"text":text, "img":img,"label":label}
    
    • 然后用DataLoader接受
    train_dataset = ExampleDataset()
    train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2)
    
    • 在训练的阶段重新接收,但是这时候接受是一个batch_size 维度的列表
     for epoch in epochs:
        for index, data in enumerate(train_dataloader):
            text, img, label = data["text"], data["img"], data["label"]
    

    加载模型

    • 只需要加载一个model和tokenizer,输入下载好模型的路径
    from transformers import BertTokenizer, BertModel
    tokenizer = BertTokenizer.from_pretrained(Bert_chinsese_path)
    model = BertForSequenceClassification.from_pretrained(Bert_chinsese_path)
    

    优化器的使用

    from transformers import  AdamW
     no_decay = ['bias', 'LayerNorm.weight']
    optimizer_grouped_parameters = [
        {'params': [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)],
         'weight_decay': weight_decay},
        {'params': [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
    ]
    optimizer = AdamW(optimizer_grouped_parameters, lr=learning_rate)
    

    transformers将一个text转换为input_ids、token_type_ids、attention_mask的问题

    • 在这里有两种转换,一中在dataset中将文本转换为tensor转换,一种在训练的时候接受到text,然后转换为tenosr

    在dataset中转换

    • 获取到文本之后,通过encode_plus()函数,获取到文本的相关tensor
    class MyDataset(Dataset):
        def __init__(self, path_to_file):
            self.dataset = pd.read_csv(path_to_file, sep="\t", names=["text", "label"])
    
        def __len__(self):
            return len(self.dataset)
    
        def __getitem__(self, idx):
            text = self.dataset.loc[idx, "text"]
            label = self.dataset.loc[idx, "label"]
            encode_dict_result = tokenizer.encode_plus(text, add_special_tokens=True, max_length=256,
                                                       pad_to_max_length=True, return_attention_mask=True,
                                                       return_tensors='pt', truncation=True)
            input_ids = encode_dict_result["input_ids"]
            token_type_ids = encode_dict_result["token_type_ids"]
            attention_mask = encode_dict_result["attention_mask"]
            sample = {"input_ids": input_ids, "token_type_ids": token_type_ids, "attention_mask": attention_mask, "label": label}
            return sample
    
    • 当你训练的时候重新可以将需要的取出来
    • label的维度一直是batch_size 的维度。一般就是一个列表的标签
    • 需要注意的是,这时候获取的input_ids、token_type_ids、attention_mask的维度都是【batch_size ,1 , max_length】,但是Bert相关模型的输入都是【batch_size ,max_length】,所以需要压缩掉中间的一维
        for i, batch in enumerate(MyDataLoader):
            input_ids, token_type_ids, label = batch["input_ids"], batch["token_type_ids"], batch["label"]
            # 压缩掉中间的一维
            input_ids, token_type_ids = input_ids.squeeze(1), token_type_ids.squeeze(1)
    
    • 当然可以直接在dataset中压缩好之后再返回
        def __getitem__(self, idx):
            text = self.dataset.loc[idx, "text"]
            label = self.dataset.loc[idx, "label"]
            encode_dict_result = tokenizer.encode_plus(text, add_special_tokens=True, max_length=256,
                                                       pad_to_max_length=True, return_attention_mask=True,
                                                       return_tensors='pt', truncation=True)
    
            input_ids = encode_dict_result["input_ids"].squeeze(1)
            token_type_ids = encode_dict_result["token_type_ids"].squeeze(1)
            attention_mask = encode_dict_result["attention_mask"].squeeze(1)
            sample = {"input_ids": input_ids, "token_type_ids": token_type_ids, "attention_mask": attention_mask, "label": label}
            return sample
    

    在训练的时候转换text为Tensor

    • 在这时候 dataeset返回的text就是batch_size长度的一个list,list中每个元素就是一条text
    • 如果一条text通过encode_plus()函数。返回的维度就是【1 ,max_length 】,但是Bert的输入维度必须是【batch_size ,max_length】,所以需要我们将每个文本的Tensor放入一个列表,然后转换为Tensor。就是将batch_size级别的数据压缩在一个矩阵里
    • 这时返回的数据维度为【batch_size ,1 , max_length】,压缩掉中间的一维之后就可以用了。在这里我是在函数convert_text_to_ids()直接进行压缩
    • 下边这个是数据压缩函数
    def convert_text_to_ids(texts, max_length=256):
        if isinstance(texts, str):
            encode_dict_result = tokenizer.encode_plus(texts, add_special_tokens=True, max_length=max_length,
                                                       pad_to_max_length=True, return_attention_mask=True,
                                                       return_tensors='pt', truncation=True)
            input_ids = encode_dict_result["input_ids"]
            token_type_ids = encode_dict_result["token_type_ids"]
            attention_mask = encode_dict_result["attention_mask"]
            return {"input_ids": input_ids, "attention_mask": attention_mask, "token_type_ids": token_type_ids}
        elif isinstance(texts, list):
            input_ids_list = []
            token_type_ids_list = []
            attention_mask_list = []
            for one_text in texts:
                encode_dict_result = tokenizer.encode_plus(one_text, add_special_tokens=True, max_length=max_length,
                                                           pad_to_max_length=True, return_attention_mask=True,
                                                           return_tensors='pt', truncation=True)
                input_ids_list.append(encode_dict_result["input_ids"])
                token_type_ids_list.append(encode_dict_result["token_type_ids"])
                attention_mask_list.append(encode_dict_result["attention_mask"])
                    # [batch_size , 1, seq]
            return {"input_ids": torch.Tensor([item.numpy() for item in input_ids_list]).squeeze(1),
                    "attention_mask": torch.Tensor([item.numpy() for item in token_type_ids_list]).squeeze(1),
                    "token_type_ids": torch.Tensor([item.numpy() for item in attention_mask_list]).squeeze(1)}
    
        return None
    

    在这里可能会出现一个错误:ValueError: only one element tensors can be converted to Python scalar
    那是因为我们的列表中都是Tensor,这时候我们需要将整个列表转换为Tensor,所以应先将Tensor转换为numpy,然后再转换为Tenosr
    因此,如果是torch.Tensor([item for item in input_ids_list])就会报错,
    需要改修为:torch.Tensor([item.numpy() for item in input_ids_list])

    • 然后使用数据
    for index, data in enumerate(sentiment_valid_loader):
        label, text = data['label'], data['text']
        # 在这里将获取的text列表转换为Tensor
        data = convert_text_to_ids(texts=text)
        input_ids, token_type_ids, attention_mask = data["input_ids"], data["token_type_ids"], data["attention_mask"]
    

    模型迁移到GPU问题

    • 需要迁移的包括:整个model的迁移和 输入数据的迁移
    • 先进行设备判断
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    

    模型迁移

    model = MyNet()
    model.to(device)
    

    输入数据迁移

    def model_train(model, iterator, optimizer, criterion, device):
        model.train()
        epoch_loss = 0
        epoch_acc = 0
        for i, batch in enumerate(iterator):
            input_ids, token_type_ids, label = batch["input_ids"], batch["token_type_ids"], batch["label"]
            input_ids, token_type_ids = input_ids.squeeze(1), token_type_ids.squeeze(1)
            # 迁移到GPU
            input_ids, token_type_ids, label = input_ids.to(device), token_type_ids.to(device), label.to(device)
    

    相关文章

      网友评论

          本文标题:Bert中transformers的一些问题记录

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