将 HuggingFace 模型加载到 AllenNLP 中会给出不同的预测

Loading a HuggingFace model into AllenNLP gives different predictions

我有一个使用 transformers 基于 BERT 模型的库训练的自定义分类模型。该模型将文本分为 7 个不同的类别。它使用以下方法保存在目录中:

trainer.save_model(model_name)
tokenizer.save_pretrained(model_name)

我正在尝试使用 allennlp 库加载此类持久模型以进行进一步分析。经过大量工作后,我设法做到了。然而,当 运行 在 allennlp 框架内设置模型时,模型的预测结果与我 运行 使用 transformers 得到的预测结果大不相同,这导致我认为加载的某些部分没有正确完成。推理过程中没有错误,只是预测不匹配。

关于如何加载现有模型的文档很少,所以我想知道以前是否有人遇到过同样的情况。只有一个关于如何使用 ROBERTA 进行 QA 分类的示例,但无法推断出我正在寻找的内容。任何人都知道以下步骤是否正确?

这是我加载训练模型的方式:

transformer_vocab = Vocabulary.from_pretrained_transformer(model_name)
transformer_tokenizer = PretrainedTransformerTokenizer(model_name)
transformer_encoder = BertPooler(model_name)

params = Params(
    {
     "token_embedders": {
        "tokens": {
          "type": "pretrained_transformer",
          "model_name": model_name,
        }
      }
    }
)
token_embedder = BasicTextFieldEmbedder.from_params(vocab=vocab, params=params)
token_indexer = PretrainedTransformerIndexer(model_name)

transformer_model = BasicClassifier(vocab=transformer_vocab,
                                    text_field_embedder=token_embedder, 
                                    seq2vec_encoder=transformer_encoder, 
                                    dropout=0.1, 
                                    num_labels=7)

我还必须按如下方式实现自己的 DatasetReader

class ClassificationTransformerReader(DatasetReader):
    def __init__(
        self,
        tokenizer: Tokenizer,
        token_indexer: TokenIndexer,
        max_tokens: int,
        **kwargs
    ):
        super().__init__(**kwargs)
        self.tokenizer = tokenizer
        self.token_indexers: Dict[str, TokenIndexer] = { "tokens": token_indexer }
        self.max_tokens = max_tokens
        self.vocab = vocab

    def text_to_instance(self, text: str, label: str = None) -> Instance:
        tokens = self.tokenizer.tokenize(text)
        if self.max_tokens:
            tokens = tokens[: self.max_tokens]
        
        inputs = TextField(tokens, self.token_indexers)
        fields: Dict[str, Field] = { "tokens": inputs }
            
        if label:
            fields["label"] = LabelField(label)
            
        return Instance(fields)

实例化如下:

dataset_reader = ClassificationTransformerReader(tokenizer=transformer_tokenizer,
                                                 token_indexer=token_indexer,
                                                 max_tokens=400)

到 运行 模型并测试它是否有效 我正在执行以下操作:

instance = dataset_reader.text_to_instance("some sample text here")
dataset = Batch([instance])
dataset.index_instances(transformer_vocab)
model_input = util.move_to_device(dataset.as_tensor_dict(), 
                                  transformer_model._get_prediction_device())

outputs = transformer_model.make_output_human_readable(transformer_model(**model_input))

这有效并且 returns 概率正确,但与我直接使用变形金刚模型 运行 得到的不匹配。知道发生了什么事吗?

如 GitHub 所述:问题是您正在 BERT 之上构建一个 7 向分类器。尽管 BERT 模型是相同的,但其上的 7 路分类器每次都是随机初始化的。

BERT 本身没有分类器。对于您的数据,那必须是 fine-tuned。

回答原始问题,上面的代码加载了原始 transformer 模型的大部分组件,但分类器层。正如德克提到的,它是随机初始化的。

解决方案是将分类器的权重从 transformers 加载到 AllenNLP 中。以下代码可以解决问题。

from transformers import BertForSequenceClassification

model = BasicClassifier(vocab=transformer_vocab, 
                        text_field_embedder=token_embedder,
                        seq2vec_encoder=transformer_encoder, 
                        dropout=0.1, 
                        num_labels=7)

# Original model loaded using transformers library
classifier = BertForSequenceClassification.from_pretrained(model_name)

transformer_model._classification_layer.weight = classifier.classifier.weight
transformer_model._classification_layer.bias = classifier.classifier.bias