fastNLP学习笔记——Vocabulary

Vocabulary是包含字或词与index的关系的类,用于将文本转化为index。

教程地址

构建Vocabulary

from fastNLP import Vocabulary

vocab = Vocabulary()
vocab.add_word_lst(['复', '旦', '大', '学'])  # 加入新的字
vocab.add_word('上海')  # `上海`会作为一个整体
vocab.to_index('复')  # 应该会为3
vocab.to_index('我')  # 会输出1,Vocabulary中默认pad的index为0, unk(没有找到的词)的index为1

#  在构建target的Vocabulary时,词表中应该用不上pad和unk,可以通过以下的初始化
vocab = Vocabulary(unknown=None, padding=None)
vocab.add_word_lst(['positive', 'negative'])
vocab.to_index('positive')  # 输出0
vocab.to_index('neutral')  # 会报错,因为没有unk这种情况

除了直接使用一个列表来构建Vocabulary,还可以使用DataSet的某一个Field来构建,然后还能将field的内容转为index。

from fastNLP import Vocabulary
from fastNLP import DataSet

dataset = DataSet({'chars': [
                                ['今', '天', '天', '气', '很', '好', '。'],
                                ['被', '这', '部', '电', '影', '浪', '费', '了', '两', '个', '小', '时', '。']
                            ],
                    'target': ['neutral', 'negative']
})

vocab = Vocabulary()
#  从该dataset中的chars列建立词表
vocab.from_dataset(dataset, field_name='chars')
#  使用vocabulary将chars列转换为index
vocab.index_dataset(dataset, field_name='chars')

target_vocab = Vocabulary(padding=None, unknown=None)
target_vocab.from_dataset(dataset, field_name='target')
target_vocab.index_dataset(dataset, field_name='target')
print(dataset)

输出:

+---------------------------------------------------+--------+
|                       chars                       | target |
+---------------------------------------------------+--------+
|               [4, 2, 2, 5, 6, 7, 3]               |   0    |
| [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 3] |   1    |
+---------------------------------------------------+--------+

一些使用tips

教程中这一部分主要探讨no_create_entry参数的作用。

建议使用的dev集和test集可以设这个参数。这个参数的作用是指定某个集合中的词如果没出现在预训练 embedding 中,会随机 embedding 还是设为 <UNK>

from fastNLP import Vocabulary
from fastNLP import DataSet

tr_data = DataSet({'chars': [
                                ['今', '天', '心', '情', '很', '好', '。'],
                                ['被', '这', '部', '电', '影', '浪', '费', '了', '两', '个', '小', '时', '。']
                            ],
                    'target': ['positive', 'negative']
})
dev_data = DataSet({'chars': [
                                ['住', '宿', '条', '件', '还', '不', '错'],
                                ['糟', '糕', '的', '天', '气', ',', '无', '法', '出', '行', '。']
                            ],
                    'target': ['positive', 'negative']
})

vocab = Vocabulary()
#  将验证集或者测试集在建立词表是放入no_create_entry_dataset这个参数中。
vocab.from_dataset(tr_data, field_name='chars', no_create_entry_dataset=[dev_data])

上面的这个例子就为dev集的词也使用了embedding。

这样做的好处在于一些词没有在与训练的 embedding 中,但是在test集中出现,我们通过 finetune 可以提高对这个词的理解。若test集或dev集中有这个词,可以达到更好的训练效果。如果test或dev集有只在这两个集合中出现,且没有在预训练出现的词,则按照<UNK>处理。

如果一个词出现在了train中,但是没在预训练模型中,embedding会为随机初始化,且它单独的一个vector,如果finetune embedding的话, 这个词在更新之后可能会有更好的表示; 而如果这个词仅出现在了dev或test中,那么就不能为它们单独建立vector,而应该让它指向unk这个vector的 值(当unk的值更新时,这个词也使用的是更新之后的vector)。所以被认为是no_create_entry的token,将首先从预训练的词表中寻找它的表示,如 果找到了,就使用该表示; 如果没有找到,则认为该词的表示应该为unk的表示。

下面这个例子帮助理解这个参数的作用。

import torch
from fastNLP.embeddings import StaticEmbedding
from fastNLP import Vocabulary

vocab = Vocabulary()
vocab.add_word('train')
vocab.add_word('only_in_train')  # 仅在train出现,但肯定在预训练词表中不存在
vocab.add_word('test', no_create_entry=True)  # 该词只在dev或test中出现
vocab.add_word('only_in_test', no_create_entry=True)  # 这个词在预训练的词表中找不到

embed = StaticEmbedding(vocab, model_dir_or_name='en-glove-6b-50d')
print(embed(torch.LongTensor([vocab.to_index('train')])))
print(embed(torch.LongTensor([vocab.to_index('only_in_train')])))
print(embed(torch.LongTensor([vocab.to_index('test')])))
print(embed(torch.LongTensor([vocab.to_index('only_in_test')])))
print(embed(torch.LongTensor([vocab.unknown_idx])))

输出:

tensor([[ 0.9497,  0.3433,  0.8450, -0.8852, ...]], grad_fn=<EmbeddingBackward>)  # train,en-glove-6b-50d,找到了该词
tensor([[ 0.0540, -0.0557, -0.0514, -0.1688, ...]], grad_fn=<EmbeddingBackward>)  # only_in_train,en-glove-6b-50d,使用了随机初始化
tensor([[ 0.1318, -0.2552, -0.0679,  0.2619, ...]], grad_fn=<EmbeddingBackward>)  # test,在en-glove-6b-50d中找到了这个词
tensor([[0., 0., 0., 0., 0., ...]], grad_fn=<EmbeddingBackward>)   # only_in_test, en-glove-6b-50d中找不到这个词,使用unk的vector
tensor([[0., 0., 0., 0., 0., ...]], grad_fn=<EmbeddingBackward>)   # unk,使用zero初始化
一个人没有梦想,和咸鱼有什么区别!
原文地址:https://www.cnblogs.com/TABball/p/12727326.html