首页 > 解决方案 > 如何在预训练的 BERT 模型之上添加多类多标签层?

问题描述

我正在尝试使用来自 huggingface 转换器库的预训练 BERT 模型来执行多任务多类句子分类任务。我尝试从那里使用 BERTForSequenceClassification 模型,但我遇到的问题是我无法将它扩展到多个任务。我将尝试通过此示例使其提供更多信息。

假设我们有四个不同的任务,并且对于每个句子和每个任务,我们都有如下示例中的标签:

  1. A :[ 'a' , 'b' , 'c' , 'd' ]
  2. 乙:['e','f','g','h']
  3. C :[ 'i' , 'j' , 'k' , 'l' ]
  4. D :[ 'm' , 'n' , 'o' , 'p' ]

现在,如果我对这个模型有一个句子,我希望输出为我提供所有四个不同任务(A、B、C、D)的输出。

这就是我之前所做的

   model = BertForSequenceClassification.from_pretrained(
    "bert-base-uncased", # Use the 12-layer BERT model, with an uncased vocab.
    num_labels = 4, # The number of output labels--2 for binary classification.
                    # You can increase this for multi-class tasks.   
    output_attentions = False, # Whether the model returns attentions weights.
    output_hidden_states = False, # Whether the model returns all hidden-states.
)

然后我尝试实现这样的 CustomBERT 模型:

class CustomBERTModel(nn.Module):
    def __init__(self):
          super(CustomBERTModel, self).__init__()
          self.bert = BertModelForSequenceClassification.from_pretrained("bert-base-uncased")
          ### New layers:
          self.linear1 = nn.Linear(768, 256)
          self.linear2 = nn.Linear(256, num_classes) ## num_classes is the number of classes in this example

    def forward(self, ids, mask):
          sequence_output, pooled_output = self.bert(
               ids, 
               attention_mask=mask)

          # sequence_output has the following shape: (batch_size, sequence_length, 768)
          linear1_output = self.linear1(sequence_output[:,0,:].view(-1,768)) 
          linear2_output = self.linear2(linear2_output)

          return linear2_output

我已经完成了与之前提供的类似问题的答案,但似乎没有一个回答我的问题。我已尝试了解所有我认为有助于理解我的问题的要点,并且如果我在解释问题时有任何不一致之处,我会尝试进一步澄清。与此相关的任何答案都将非常有帮助。

标签: deep-learningpytorchbert-language-modelhuggingface-transformerstransfer-learning

解决方案


你应该使用BertModeland not BertModelForSequenceClassification,因为BertModelForSequenceClassification在 BERT 模型之上添加了一个用于分类的线性层,并且使用CrossEntropyLoss,这意味着多类分类。

因此,首先使用BertModel而不是BertModelForSequenceClassification

class CustomBERTModel(nn.Module):
    def __init__(self):
          super(CustomBERTModel, self).__init__()
          self.bert = BertModel.from_pretrained("bert-base-uncased")
          ### New layers:
          self.linear1 = nn.Linear(768, 256)
          self.linear2 = nn.Linear(256, 4) ## as you have 4 classes in the output
          self.sig = nn.functional.sigmoid()

    def forward(self, ids, mask):
          sequence_output, pooled_output = self.bert(
               ids, 
               attention_mask=mask)

          # sequence_output has the following shape: (batch_size, sequence_length, 768)
          linear1_output = self.linear1(sequence_output[:,0,:].view(-1,768)) 
          linear2_output = self.linear2(linear2_output)
          linear2_output = self.sig(linear2_output)

          return linear2_output

接下来,多标签分类使用'Sigmoid'激活而不是'Softmax'(这里在上面的代码中添加了sigmoid层)

此外,对于多标签分类,您需要使用BCELoss而不是CrossEntropyLoss.


推荐阅读