pytorch bert测试代码中BertForSequenceClassification函数的输入(一条或多条)输出

代码来源是对huggingface的修改,侵删。链接:https://github.com/huggingface/ 现在更新以后大不同了

从后面贴的源码来看,如果是测试,输入就是那三个tensor.1.input_id   2.token_type_ids  3.attention_mask.  训练的话还包括label。

三个特征的代码:参数example是文本的list:[sentence,sentence,sentence....]这里sentence用的是text_a+text_b,没有分句处理。max_seq_length是最大序列长度。tokenizer是 tokenizer = BertTokenizer.from_pretrained(WORK_DIR)得到的。WORK_DIR是放bert模型的vocab.txt的路径,用来加载tokenizer.

def convert_lines(example, max_seq_length, tokenizer):
    max_seq_length -= 2
    all_tokens = []
    all_segments = []
    all_masks = []
    longer = 0
    for text in tqdm(example):
        tokens_a = tokenizer.tokenize(text)
        if len(tokens_a) > max_seq_length:
            tokens_a = tokens_a[:max_seq_length]
            longer += 1
        one_token = tokenizer.convert_tokens_to_ids(["[CLS]"] + tokens_a + ["[SEP]"]) + [0] * (
                    max_seq_length - len(tokens_a))
        one_segment = [0] * (len(tokens_a) + 2) + [0] * (max_seq_length - len(tokens_a))
        one_mask = [1] * (len(tokens_a) + 2) + [0] * (max_seq_length - len(tokens_a))

        all_tokens.append(one_token)
        all_segments.append(one_segment)
        all_masks.append(one_mask)
    print(longer)
    return np.array(all_tokens), np.array(all_segments), np.array(all_masks)

这个代码是有很多条数据的情况,这个函数的输出是三个np类型的数组。all_tokens装所有句子的input_id,是一个n行,max_seq_length列的二维数组。其他两个也是。

部分main函数,

if __name__ == '__main__':
    test = pd.read_csv("./dataset/3_abstracts.csv", encoding='utf-8')
    test['NAME'] = test['NAME'].fillna("无")
    test['CONTENT'] = test['CONTENT'].fillna("无")
    test['title_content'] = test['NAME'] + test['CONTENT']

    seed_everything()
    #######config
    device = torch.device('cuda')
    WORK_DIR = "./bert_pretrain/"
    #我这里分的三类
    bert_config = BertConfig.from_pretrained(WORK_DIR + 'bert_config.json', num_labels=3)

    tokenizer = BertTokenizer.from_pretrained(WORK_DIR)

    MAX_SEQUENCE_LENGTH = 512
    test_tokens, test_segments, test_masks = convert_lines(test["title_content"],MAX_SEQUENCE_LENGTH,tokenizer)
#把得到的二维数组包装成tensor.内部为tensor([[id,id...][id..]]),用test_features包装这三个tensor

    test_features = [
        torch.tensor(test_tokens, dtype=torch.long),
        torch.tensor(test_segments, dtype=torch.long),
        torch.tensor(test_masks, dtype=torch.long)

    ]
    #pytorch的普遍用法,这个函数把参数处理成一个tensor数据集,是为了后面的loader之类的
    test_dataset = torch.utils.data.TensorDataset(*test_features)
    #调我的预测函数对标签值进行预测
    test_preds = test_model(test_dataset)

 预测函数:

def test_model(test_dataset):
    WORK_DIR = "./bert_pretrain/"
    # WORK_DIR = "./bert_pretrain/"
    output_model_file = WORK_DIR + '423_model.bin' #自己训练好的模型
    model = BertForSequenceClassification.from_pretrained(WORK_DIR, config=bert_config)

    model.load_state_dict(torch.load(output_model_file))
    model.to(device)
    model.eval()
    # for param in model.parameters():
    #     param.requires_grad = False

    test_preds = np.zeros((len(test_dataset), 3))
    #SequentialSampler这里是把测试数据顺序排,还有RandomSampler是随机采样,随机排的
    test_sampler = SequentialSampler(test_dataset)
    #这里加载数据集,主要是设batch是4,也可以设其他,就把刚刚处理过的三兄弟,每个取四个来处理
    test_loader = DataLoader(test_dataset, sampler=test_sampler, batch_size=4)
    #总的数据量除以4
    tk0 = tqdm_notebook(test_loader)
    # x_batch1 是一个tentor数据类型:tensor([[id,id..]]),其他两个也是。侧面说明bert的model的输入需要一个二维tensor.源码里有个 num_choices = input_ids.shape[1]这个好像就是求tensor的第二维的长度,我这里设的512
    for i, (x_batch1, x_batch2, x_batch3,) in enumerate(tk0):
        #注意这里要把数据转到GPU类型,不然会报错
        pred = model(x_batch1.to(device), x_batch2.to(device), x_batch3.to(device))
        test_preds[i * 4:(i + 1) * 4] = pred[0].detach().cpu().numpy()
    return test_preds

预测的结果是一个二元组,第二元大概是什么cuda啥啥的,用第一元就行了pred[0],给它转成cpu的numpy。我这里是三分类,得到的结果中[[小数,小数,小数],[],[]...[]]。写一个for循环取三个小数里最大的的索引,就是最终需要的标签。

    predict = []
    for prediction in test_preds:  # predict is one by one, so the length of probabilities=1
        pred_label = np.argmax(prediction)
        predict.append(pred_label)

下面写写如果只输入一条数据有啥要改的,用来部署接口用:

提取特征就只用得到三兄弟了每个是一个list one_token=[id,id,id] one_segment=[seg][seg][seg]...

def convert_lines(example, max_seq_length, tokenizer):
    max_seq_length -= 2
    longer = 0
    tokens_a = tokenizer.tokenize(example)
    if len(tokens_a) > max_seq_length:
        tokens_a = tokens_a[:max_seq_length]
        longer += 1
    one_token = tokenizer.convert_tokens_to_ids(["[CLS]"] + tokens_a + ["[SEP]"])+\
                [0] * (max_seq_length - len(tokens_a))
    one_segment = [0] * (len(tokens_a) + 2) + [0] * (max_seq_length - len(tokens_a))
    one_mask = [1] * (len(tokens_a) + 2) + [0] * (max_seq_length - len(tokens_a))
    return one_token, one_segment, one_mask

因为模型需要一个二维tensor,所以这里转tensor要多加一个中括号。当然也可以unsqueeze(0)

    test_token = torch.tensor([test_token])
    test_segment = torch.tensor([test_segment])
    test_mask=torch.tensor([test_mask])

然后测试时这样再这样得到结果,这里我没写全,加载模型啥的跟上面是差不多的

    pred = model(test_token.to(device), test_segment.to(device), test_mask.to(device))
    predic = pred[0].detach().cpu().numpy()
    res = np.argmax(predic)

hugging face 的源码:(现在好像更新了封装得更好了)

@add_start_docstrings("""Bert Model transformer with a sequence classification/regression head on top (a linear layer on top of the pooled output) e.g. for GLUE tasks. """,
    BERT_START_DOCSTRING, BERT_INPUTS_DOCSTRING)
class BertForSequenceClassification(BertPreTrainedModel):
    r"""
        **labels**: (`optional`) ``torch.LongTensor`` of shape ``(batch_size,)``:
            Labels for computing the sequence classification/regression loss.
            Indices should be in ``[0, ..., config.num_labels - 1]``.
            If ``config.num_labels == 1`` a regression loss is computed (Mean-Square loss),
            If ``config.num_labels > 1`` a classification loss is computed (Cross-Entropy).

    Outputs: `Tuple` comprising various elements depending on the configuration (config) and inputs:
        **loss**: (`optional`, returned when ``labels`` is provided) ``torch.FloatTensor`` of shape ``(1,)``:
            Classification (or regression if config.num_labels==1) loss.
        **logits**: ``torch.FloatTensor`` of shape ``(batch_size, config.num_labels)``
            Classification (or regression if config.num_labels==1) scores (before SoftMax).
        **hidden_states**: (`optional`, returned when ``config.output_hidden_states=True``)
            list of ``torch.FloatTensor`` (one for the output of each layer + the output of the embeddings)
            of shape ``(batch_size, sequence_length, hidden_size)``:
            Hidden-states of the model at the output of each layer plus the initial embedding outputs.
        **attentions**: (`optional`, returned when ``config.output_attentions=True``)
            list of ``torch.FloatTensor`` (one for each layer) of shape ``(batch_size, num_heads, sequence_length, sequence_length)``:
            Attentions weights after the attention softmax, used to compute the weighted average in the self-attention heads.

    Examples:

        tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
        model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
        input_ids = torch.tensor(tokenizer.encode("Hello, my dog is cute")).unsqueeze(0)  # Batch size 1
        labels = torch.tensor([1]).unsqueeze(0)  # Batch size 1
        outputs = model(input_ids, labels=labels)
        loss, logits = outputs[:2]
    """
    def __init__(self, config):
        super(BertForSequenceClassification, self).__init__(config)
        self.num_labels = config.num_labels

        self.bert = BertModel(config)
        self.dropout = nn.Dropout(config.hidden_dropout_prob)
        self.classifier = nn.Linear(config.hidden_size, self.config.num_labels)

        self.init_weights()

    def forward(self, input_ids, token_type_ids=None, attention_mask=None, labels=None,
                position_ids=None, head_mask=None):
        outputs = self.bert(input_ids, position_ids=position_ids, token_type_ids=token_type_ids,
                            attention_mask=attention_mask, head_mask=head_mask)
        pooled_output = outputs[1]

        pooled_output = self.dropout(pooled_output)
        logits = self.classifier(pooled_output)

        outputs = (logits,) + outputs[2:]  # add hidden states and attention if they are here

        if labels is not None:
            if self.num_labels == 1:
                #  We are doing regression
                loss_fct = MSELoss()
                loss = loss_fct(logits.view(-1), labels.view(-1))
            else:
                loss_fct = CrossEntropyLoss()
                loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
            outputs = (loss,) + outputs

        return outputs  # (loss), logits, (hidden_states), (attentions)

 

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: PyTorch-BERT可以用于多标签任务。多标签任务是指一个样本可以同时被分配多个标签,而不是只有一个唯一的标签。PyTorch-BERT可以通过微调(fine-tuning)来处理多标签任务,具体步骤如下: 1. 数据预处理:首先将原始数据转换为特定的输入格式,即将每个样本编码为输入序列。对于文本分类任务,可以使用tokenizer将输入文本转换为BERT模型对应的输入格式。同时,每个样本的标签也需要进行处理,通常使用独热编码或多标签编码的方式表示多个标签。 2. 模型微调:使用经过预训练的BERT模型,将其权重加载到PyTorch模型。然后将加载的模型与多标签分类器(如全连接层)结合,以适应多标签任务的需求。微调的目标是让BERT模型能够更好地适应特定的多标签任务。 3. 训练与评估:使用经过微调的模型对训练数据进行训练,并在验证集上进行评估。在训练过程,通常使用交叉熵损失函数来计算模型的损失,并使用优化算法(如Adam)来更新模型的参数。 4. 预测:在模型训练完成后,可以使用经过微调的模型对新的未标记样本进行预测。模型将输出一个概率分布,表示每个标签是否存在的可能性。可以根据设定的阈值,将概率高于阈值的标签作为模型的预测结果。 总而言之,PyTorch-BERT可以通过微调的方式来处理多标签任务。在微调过程,需要将BERT模型与多标签分类器结合,并进行相应的训练和评估。通过这种方式,PyTorch-BERT可以应用于各种多标签分类任务,如文本分类、图像标注等。 ### 回答2: PyTorch是一个开源的机器学习框架,它提供了一种强大的编程环境,可以用于构建和训练各种深度学习模型。BERT(Bidirectional Encoder Representations from Transformers)是一种预训练的自然语言处理模型,它能够有效地处理各种自然语言任务。 在PyTorch使用BERT进行多标签分类任务,需要进行以下几个步骤: 1. 数据预处理:将文本数据转换为适合BERT模型输入的格式。首先,需要将文本分词并添加特殊标记(如"[CLS]"和"[SEP]")来标记句子的开头和结束。然后,将分词后的文本转换为词向量,可以使用BERT的预训练模型来获取词向量。 2. 构建模型:使用PyTorch构建多标签分类模型。可以使用BERT作为基本模型,然后添加适当的全连接层来实现多标签分类。这些全连接层可以将BERT模型的输出映射到具体的标签。在模型的训练过程,可以使用交叉熵损失函数和梯度下降方法来优化模型的参数。 3. 模型训练:使用标注好的数据集对构建的模型进行训练。可以使用PyTorch提供的优化器(如AdamOptimizer)和内置的训练循环来简化训练过程。 4. 模型评估:使用测试集评估训练得到的模型的性能。可以使用各种指标(如准确率、精确率、召回率和F1分数)来评估模型的多标签分类性能。 总结起来,使用PyTorchBERT进行多标签分类任务,需要进行数据预处理、模型构建、模型训练和模型评估等步骤。通过合理设计模型结构和使用适当的优化算法,可以实现高效准确的多标签分类。 ### 回答3: PyTorch是一个很流行的深度学习框架,而BERT是一个非常强大的预训练模型,可以用于自然语言处理任务。当我们要处理多标签分类问题时,可以使用PyTorchBERT的组合来解决。 多标签分类是指一个样本可以被分配到多个类别,而不仅仅是一个类别。在使用PyTorchBERT进行多标签分类时,我们首先需要对文本数据进行处理。我们可以使用BERT模型的tokenizer将文本转换为对应的token,然后将其转化为PyTorch的张量。 接下来,我们可以使用BERT模型进行特征提取。BERT模型可以将输入的token序列编码成固定长度的向量表示,这样可以保留输入句子的语义信息。通过BERT模型的输出,我们可以获取每个token的向量表示。 对于多标签分类问题,我们可以使用全连接层或者其他一些分类器来预测每个类别的概率。我们可以将BERT模型的输出连接到一个全连接层,然后使用激活函数(如sigmoid函数)将输出的概率限制在0和1之间。 接着,我们可以使用交叉熵损失函数来计算模型的损失,并使用反向传播算法来更新模型的参数。在训练过程,我们可以使用一些评估指标(如精确率、召回率、F1分数等)来评估模型在多标签分类任务上的性能。 为了优化模型的训练,我们可以使用一些技巧,如学习率调整、正则化、批量归一化等。此外,还可以使用数据增强技术来增加训练数据的多样性,从而提升模型的泛化能力。 总结来说,通过使用PyTorchBERT的组合,我们可以很方便地解决多标签分类问题。PyTorch提供了灵活的深度学习框架,而BERT则是一个强大的预训练模型,它们的结合可以帮助我们构建准确度高且性能优良的多标签分类模型。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值