You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tutorial_2_vocabulary.rst 7.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. ==============================
  2. fastNLP中的Vocabulary
  3. ==============================
  4. :class:`~fastNLP.Vocabulary` 是包含字或词与index关系的类,用于将文本转换为index。
  5. 构建Vocabulary
  6. -----------------------------
  7. .. code-block:: python
  8. from fastNLP import Vocabulary
  9. vocab = Vocabulary()
  10. vocab.add_word_lst(['复', '旦', '大', '学']) # 加入新的字
  11. vocab.add_word('上海') # `上海`会作为一个整体
  12. vocab.to_index('复') # 应该会为3
  13. vocab.to_index('我') # 会输出1,Vocabulary中默认pad的index为0, unk(没有找到的词)的index为1
  14. # 在构建target的Vocabulary时,词表中应该用不上pad和unk,可以通过以下的初始化
  15. vocab = Vocabulary(unknown=None, padding=None)
  16. vocab.add_word_lst(['positive', 'negative'])
  17. vocab.to_index('positive') # 输出0
  18. vocab.to_index('neutral') # 会报错,因为没有unk这种情况
  19. 除了通过以上的方式建立词表,Vocabulary还可以通过使用下面的函数直从 :class:`~fastNLP.DataSet` 中的某一列建立词表以及将该列转换为index
  20. .. code-block:: python
  21. from fastNLP import Vocabulary
  22. from fastNLP import DataSet
  23. dataset = DataSet({'chars': [
  24. ['今', '天', '天', '气', '很', '好', '。'],
  25. ['被', '这', '部', '电', '影', '浪', '费', '了', '两', '个', '小', '时', '。']
  26. ],
  27. 'target': ['neutral', 'negative']
  28. })
  29. vocab = Vocabulary()
  30. vocab.from_dataset(dataset, field_name='chars')
  31. vocab.index_dataset(dataset, field_name='chars')
  32. target_vocab = Vocabulary(padding=None, unknown=None)
  33. target_vocab.from_dataset(dataset, field_name='target')
  34. target_vocab.index_dataset(dataset, field_name='target')
  35. print(dataset)
  36. 输出内容为::
  37. +---------------------------------------------------+--------+
  38. | chars | target |
  39. +---------------------------------------------------+--------+
  40. | [4, 2, 2, 5, 6, 7, 3] | 0 |
  41. | [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 3] | 1 |
  42. +---------------------------------------------------+--------+
  43. 一些使用tips
  44. -----------------------------
  45. 在通过使用from_dataset()函数在DataSet上建立词表时,将测试集和验证集放入参数no_create_entry_dataset中,如下所示
  46. .. code-block:: python
  47. from fastNLP import Vocabulary
  48. from fastNLP import DataSet
  49. tr_data = DataSet({'chars': [
  50. ['今', '天', '心', '情', '很', '好', '。'],
  51. ['被', '这', '部', '电', '影', '浪', '费', '了', '两', '个', '小', '时', '。']
  52. ],
  53. 'target': ['positive', 'negative']
  54. })
  55. dev_data = DataSet({'chars': [
  56. ['住', '宿', '条', '件', '还', '不', '错'],
  57. ['糟', '糕', '的', '天', '气', ',', '无', '法', '出', '行', '。']
  58. ],
  59. 'target': ['positive', 'negative']
  60. })
  61. vocab = Vocabulary()
  62. # 将验证集或者测试集在建立词表是放入no_create_entry_dataset这个参数中。
  63. vocab.from_dataset(tr_data, field_name='chars', no_create_entry_dataset=[dev_data])
  64. :class:`~fastNLP.Vocabulary` 中的 `no_create_entry` , 建议在添加来自于测试集和验证集的词的时候将该参数置为True, 或将验证集和测试集
  65. 传入 `no_create_entry_dataset` 参数。它们的意义是在接下来的模型会使用pretrain的embedding(包括glove, word2vec, elmo与bert)且会finetune的
  66. 情况下,如果仅使用来自于train的数据建立vocabulary,会导致只出现在test与dev中的词语无法充分利用到来自于预训练embedding的信息(因为他们
  67. 会被认为是unk),所以在建立词表的时候将test与dev考虑进来会使得最终的结果更好。
  68. 通过与fastNLP中的各种Embedding配合使用,会有如下的效果,
  69. 如果一个词出现在了train中,但是没在预训练模型中,embedding会为随机初始化,且它单独的一个vector,如果finetune embedding的话,
  70. 这个词在更新之后可能会有更好的表示; 而如果这个词仅出现在了dev或test中,那么就不能为它们单独建立vector,而应该让它指向unk这个vector的
  71. 值(当unk的值更新时,这个词也使用的是更新之后的vector)。所以被认为是no_create_entry的token,将首先从预训练的词表中寻找它的表示,如
  72. 果找到了,就使用该表示; 如果没有找到,则认为该词的表示应该为unk的表示。
  73. 下面我们结合部分 :class:`~fastNLP.embeddings.StaticEmbedding` 的例子来说明下该值造成的影响,如果您对 :class:`~fastNLP.embeddings.StaticEmbedding` 不太了解,您可以先参考 :doc:`使用Embedding模块将文本转成向量 </tutorials/tutorial_3_embedding>` 部分再来阅读该部分
  74. .. code-block:: python
  75. import torch
  76. from fastNLP.embeddings import StaticEmbedding
  77. from fastNLP import Vocabulary
  78. vocab = Vocabulary()
  79. vocab.add_word('train')
  80. vocab.add_word('only_in_train') # 仅在train出现,但肯定在预训练词表中不存在
  81. vocab.add_word('test', no_create_entry=True) # 该词只在dev或test中出现
  82. vocab.add_word('only_in_test', no_create_entry=True) # 这个词在预训练的词表中找不到
  83. embed = StaticEmbedding(vocab, model_dir_or_name='en-glove-6b-50d')
  84. print(embed(torch.LongTensor([vocab.to_index('train')])))
  85. print(embed(torch.LongTensor([vocab.to_index('only_in_train')])))
  86. print(embed(torch.LongTensor([vocab.to_index('test')])))
  87. print(embed(torch.LongTensor([vocab.to_index('only_in_test')])))
  88. print(embed(torch.LongTensor([vocab.unknown_idx])))
  89. 输出结果(只截取了部分vector)::
  90. tensor([[ 0.9497, 0.3433, 0.8450, -0.8852, ...]], grad_fn=<EmbeddingBackward>) # train,en-glove-6b-50d,找到了该词
  91. tensor([[ 0.0540, -0.0557, -0.0514, -0.1688, ...]], grad_fn=<EmbeddingBackward>) # only_in_train,en-glove-6b-50d,使用了随机初始化
  92. tensor([[ 0.1318, -0.2552, -0.0679, 0.2619, ...]], grad_fn=<EmbeddingBackward>) # test,在en-glove-6b-50d中找到了这个词
  93. tensor([[0., 0., 0., 0., 0., ...]], grad_fn=<EmbeddingBackward>) # only_in_test, en-glove-6b-50d中找不到这个词,使用unk的vector
  94. tensor([[0., 0., 0., 0., 0., ...]], grad_fn=<EmbeddingBackward>) # unk,使用zero初始化
  95. 首先train和test都能够从预训练中找到对应的vector,所以它们是各自的vector表示; only_in_train在预训练中找不到,StaticEmbedding为它
  96. 新建了一个entry,所以它有一个单独的vector; 而only_in_test在预训练中找不到改词,因此被指向了unk的值(fastNLP用零向量初始化unk),与最后一行unk的
  97. 表示相同。