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

Posted

技术标签:

【中文标题】将 HuggingFace 模型加载到 AllenNLP 中会给出不同的预测【英文标题】:Loading a HuggingFace model into AllenNLP gives different predictions 【发布时间】:2021-12-20 21:25:17 【问题描述】:

我有一个使用基于 BERT 模型的 transformers 库训练的自定义分类模型。该模型将文本分为 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))

这可以正常工作并正确返回概率,但与我直接使用转换器运行模型的结果不匹配。知道发生了什么吗?

【问题讨论】:

【参考方案1】:

默认情况下,模型在训练模式下运行,这意味着 dropout 会随机化结果。首先通过运行model.eval() 尝试将两个模型(AllenNLP 和转换器)设置为评估模式。结果应该是一样的。

我认为您的其余代码是正确的,尽管它可能不是让转换器模型在 AllenNLP 中运行的最短方法。

【讨论】:

您能否分享在 AllenNLP 中加载变压器模型的哪种方式更好或更短?找不到更好的方法来加载保存在文件夹中的模型。 我也尝试将模型切换到评估,但还是一样。预测不符。我还使用来自训练数据集的样本(模型应该正确)测试了模型,确实transformers 正确,但allenNLP 给出了不同的答案。所以我认为allenNLP 上没有正确加载某些内容。 您能否在github.com/allenai/allennlp/issues/new/choose 创建一个问题,并使用显示此行为的可执行代码? 感谢您的建议!发表于github.com/allenai/allennlp/issues/5582

以上是关于将 HuggingFace 模型加载到 AllenNLP 中会给出不同的预测的主要内容,如果未能解决你的问题,请参考以下文章

使用 Huggingface Transformers 从磁盘加载预训练模型

下载huggingface-transformers模型至本地,并使用from_pretrained方法加载

HuggingFace - config.json 中的 GPT2 标记器配置

Huggingface AutoTokenizer 无法从本地路径加载

HuggingFace Saving-Loading 模型 (Colab) 进行预测

Huggingface MarianMT 翻译器会丢失内容,具体取决于模型