将 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
我有一个使用 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