代码回顾:如何用AllenNLP词汇表建立文本索引

146 阅读3分钟

代码回顾。AllenNLP词汇表如何为你的文本建立索引

虽然AllenNLP为库中几乎所有的模块提供了一个很好的指南,但我在很多方面仍然对词汇的构建方式感到困惑。具体来说,我们回答以下问题/讨论。

  • 构建。token/id对如何被添加到Vocabulary?
  • 用于一个文本字段。词汇是如何被用于文本索引的?
  • Vocabulary 用于标签索引?
  • 任何注意事项

第1节:如何将标记/ID对添加到Vocabulary

从实例来看。通常情况下,from_instance 方法可以构建一个 counter: Dict[*str*, Dict[*str*, *int*]]其中外键是为每个命名空间保留的,内部字典存储标记/id对。counter 将被_extend 方法进一步分解为self._token_to_indexself._index_to_token 属性。
具体来说,它调用每个Instance 对象的count_vocab_items ,然后再调用每个Field 对象的count_vocab_items ,然后再(再次)调用每个TokenIndexer 对象的count_vocab_items 。因此,计数项目的功能代码确实在每个TokenIndexer 对象中。TokenIndexer 中的这个count_vocab_items 将与counter 的外键名匹配名称空间,以扩展项目或增加项目的计数。下面是SingleIdTokenIndexer 中的代码。

def count_vocab_items(self, token: Token, counter: Dict[str,   Dict[str, int]]):        if self.namespace is not None:            text = self._get_feature_value(token)            if self.lowercase_tokens:                text = text.lower()            counter[self.namespace][text] += 1

第2部分:如何使用词汇表进行文本索引?

Vocabulary 将与TokenIndexer 协调,为Field 对象中的标记编制索引。具体来说,TokenIndexer.tokens_to_indices 方法将接受一个Vocabulary对象作为参数来匹配命名空间和索引标记。

如上所述,功能代码实际上在TokenIndexer 。下面是SingleIdTokenIndexer 的代码。

def tokens_to_indices(        self, tokens: List[Token], vocabulary: Vocabulary    ) -> Dict[str, List[int]]:        indices: List[int] = []    for token in itertools.chain(self._start_tokens, tokens, self._end_tokens):            text = self._get_feature_value(token)            if self.namespace is None:                indices.append(text)  # type: ignore            else:                if self.lowercase_tokens:                    text = text.lower()                indices.append(vocabulary.get_token_index(text,   self.namespace))

tokens_to_indices 方法将是 方法,如下所示。注意下一节讨论的 和 的区别。Textfield.index Textfield.index LabelField.index

def index(self, vocab: Vocabulary):        self._indexed_tokens = {}        for indexer_name, indexer in self.token_indexers.items():            self._indexed_tokens[indexer_name] = indexer.tokens_to_indices(self.tokens, vocab)

第3节:标签索引的词汇表

它在构造和消耗上都与文本索引不同。

  • 在构建过程中没有为填充物和未知标记保留ID
  • 没有TokenIndexderLabelField 本身包含命名空间(通常硬编码为 "labels"),以从标记到索引的字典(即Vocabulary._token_to_index[“labels”] )中提取标签索引,如以下代码所示,LabelField
def index(self, vocab: Vocabulary):        if not self._skip_indexing:            self._label_id = vocab.get_token_index(                self.label, self._label_namespace  # type: ignore            )

第四节:注意事项

忘记应用 **TokenIndexer** **TextField**:这是我们用AllenNLP处理数据时最常见的错误之一,因为从逻辑上讲,Vocabulary中的token/id映射已经足够用于索引TextField 中的tokens。然而,我们有很多原因需要TokenIndexer

  • 一个常见的原因是要添加特殊的标记(开始或结束的标记 )。
  • 另一个原因是,Textfield 中的token可能与Vocabulary中token/id映射的颗粒度不一致。例如,我们将文本标记为单词,但词汇表中包含字符的标记/ID映射。这听起来很奇怪:如果我们想在字符级别上对其进行索引,为什么我们要将文本标记为单词而不是字符。据我所知,我猜测它有利于我们将单词索引(使用SingleIdTokenIndexer )和字符索引(TokenCharacterIndexer )结合起来。

所以,记得应用TokenIndexer 。下面是在一个文本字段中同时使用单词索引和字符索引的代码。

text_field.token_indexers={"tokens":   SingleIdTokenIndexer(namespace="token_vocab"),