无法将 text_classifier 注册为模型;名称已用于 TextClassifier

问题描述

尝试使用 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 开始使用它。所以这不是你的错;这两个包之间不匹配(至少在它们当前的版本中是这样)。