Bert中transformers的一些问题记录

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

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的一些问题记录)