代码回顾。AllenNLP词汇表如何为你的文本建立索引
虽然AllenNLP为库中几乎所有的模块提供了一个很好的指南,但我在很多方面仍然对词汇的构建方式感到困惑。具体来说,我们回答以下问题/讨论。
- 构建。token/id对如何被添加到
Vocabulary? - 用于一个文本字段。词汇是如何被用于文本索引的?
Vocabulary用于标签索引?- 任何注意事项
第1节:如何将标记/ID对添加到Vocabulary ?
从实例来看。通常情况下,from_instance 方法可以构建一个 counter: Dict[*str*, Dict[*str*, *int*]]其中外键是为每个命名空间保留的,内部字典存储标记/id对。counter 将被_extend 方法进一步分解为self._token_to_index 和self._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
- 没有
TokenIndexder:LabelField本身包含命名空间(通常硬编码为 "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"),