问题描述
尝试使用 https://github.com/allenai/scibert/blob/master/scibert/models/text_classifier.py 共享的文本分类器模型
过去一切正常,突然间我不断收到此错误:无法将 text_classifier 注册为模型;名称已用于 TextClassifier
可能是什么原因?有什么建议吗?
from typing import Dict,Optional,List,Any
import torch
import torch.nn.functional as F
from allennlp.data import Vocabulary
from allennlp.models.model import Model
from allennlp.modules import FeedForward,TextFieldEmbedder,Seq2SeqEncoder
from allennlp.nn import InitializerApplicator,RegularizerApplicator
from allennlp.nn import util
from allennlp.training.metrics import CategoricalAccuracy,F1Measure
from overrides import overrides
@Model.register("text_classifier")
class TextClassifier(Model):
"""
Implements a basic text classifier:
1) Embed tokens using `text_field_embedder`
2) Seq2SeqEncoder,e.g. BiLSTM
3) Append the first and last encoder states
4) Final Feedforward layer
Optimized with CrossEntropyLoss. Evaluated with CategoricalAccuracy & F1.
"""
def __init__(self,vocab: Vocabulary,text_field_embedder: TextFieldEmbedder,text_encoder: Seq2SeqEncoder,classifier_Feedforward: FeedForward,verbose_metrics: False,initializer: InitializerApplicator = InitializerApplicator(),regularizer: Optional[RegularizerApplicator] = None,) -> None:
super(TextClassifier,self).__init__(vocab,regularizer)
self.text_field_embedder = text_field_embedder
self.num_classes = self.vocab.get_vocab_size("labels")
self.text_encoder = text_encoder
self.classifier_Feedforward = classifier_Feedforward
self.prediction_layer = torch.nn.Linear(self.classifier_Feedforward.get_output_dim(),self.num_classes)
self.label_accuracy = CategoricalAccuracy()
self.label_f1_metrics = {}
self.verbose_metrics = verbose_metrics
for i in range(self.num_classes):
self.label_f1_metrics[vocab.get_token_from_index(index=i,namespace="labels")] = F1Measure(positive_label=i)
self.loss = torch.nn.CrossEntropyLoss()
self.pool = lambda text,mask: util.get_final_encoder_states(text,mask,bidirectional=True)
initializer(self)
@overrides
def forward(self,text: Dict[str,torch.LongTensor],label: torch.IntTensor = None,Metadata: List[Dict[str,Any]] = None) -> Dict[str,torch.Tensor]:
"""
Parameters
----------
text : Dict[str,torch.LongTensor]
From a ``TextField``
label : torch.IntTensor,optional (default = None)
From a ``LabelField``
Metadata : ``List[Dict[str,Any]]``,optional,(default = None)
Metadata containing the original tokenization of the premise and
hypothesis with 'premise_tokens' and 'hypothesis_tokens' keys respectively.
Returns
-------
An output dictionary consisting of:
label_logits : torch.FloatTensor
A tensor of shape ``(batch_size,num_labels)`` representing unnormalised log probabilities of the label.
label_probs : torch.FloatTensor
A tensor of shape ``(batch_size,num_labels)`` representing probabilities of the label.
loss : torch.FloatTensor,optional
A scalar loss to be optimised.
"""
embedded_text = self.text_field_embedder(text)
mask = util.get_text_field_mask(text)
encoded_text = self.text_encoder(embedded_text,mask)
pooled = self.pool(encoded_text,mask)
ff_hidden = self.classifier_Feedforward(pooled)
logits = self.prediction_layer(ff_hidden)
class_probs = F.softmax(logits,dim=1)
output_dict = {"logits": logits}
if label is not None:
loss = self.loss(logits,label)
output_dict["loss"] = loss
# compute F1 per label
for i in range(self.num_classes):
metric = self.label_f1_metrics[self.vocab.get_token_from_index(index=i,namespace="labels")]
metric(class_probs,label)
self.label_accuracy(logits,label)
return output_dict
#@overrides
def decode(self,output_dict: Dict[str,torch.Tensor]) -> Dict[str,torch.Tensor]:
class_probabilities = F.softmax(output_dict['logits'],dim=-1)
output_dict['class_probs'] = class_probabilities
return output_dict
def get_metrics(self,reset: bool = False) -> Dict[str,float]:
metric_dict = {}
sum_f1 = 0.0
for name,metric in self.label_f1_metrics.items():
metric_val = metric.get_metric(reset)
if self.verbose_metrics:
metric_dict[name + '_P'] = metric_val[0]
metric_dict[name + '_R'] = metric_val[1]
metric_dict[name + '_F1'] = metric_val[2]
sum_f1 += metric_val[2]
names = list(self.label_f1_metrics.keys())
total_len = len(names)
average_f1 = sum_f1 / total_len
metric_dict['average_F1'] = average_f1
metric_dict['accuracy'] = self.label_accuracy.get_metric(reset)
return metric_dict
解决方法
名称已被占用。 Something that’s already a part of AllenNLP 已使用该名称,因此您需要另选一个。
出于好奇,AllenNLP 创建了一个模型注册表,以便您可以在命令行中选择一个模型。 (这就是装饰器正在做的事情。)这要求名称是唯一的。
名称 text_classifier
仅在您使用的外部包使用它之后才被 AllenNLP 使用。它在 2019 年 5 月工作,当时该文件上次更新。但是 17 个月前,AllenNLP 开始使用它。所以这不是你的错;这两个包之间不匹配(至少在它们当前的版本中是这样)。