赞
踩
Tokenizing:将任意长的文本转化成数字序列,定义为TokenIds.每一个TokenId是word,subword或者character在词汇表里的索引。
Tokenizing的前提必须要有一张词汇表。
词汇表的学习过程:
1.Standardize:滤出标点符号,将所有大写统一为小写。这个步骤属于可选步骤,可以执行,也可以不执行。
2.split:分词
3.最后便是统计所有出现过的字符,并组成一个词汇表。
英语文本的预处理通常是Tokenizing,而Tokenizing的最小维度分为三种——word(单词),wordpiece(单词块),character(字母)。word的Tokenizing很好处理,因为英文文本单词之间有着天然的空格符,完全可以根据空格符进行Tokenizing。character的Tokenizing也同样好处理,只需将文本里所有字母切分开就行了。但是wordpiece的Tokenizing却显得更复杂,却又更实用。这种方式可以将" unintended "分解成 " un "," intend ", "ed",将" actor "分解成" act "和" or "。显然这种Tonkenizing更符合英语文本的语法分析。以wordpiece建立的词汇表,称之为Bert wordpiece vocabulary。
利用tensorflow_text包可以在英文文本集上学习到一张Bert wordpiece vocabulary。
导包,
from tensorflow_text.tools.wordpiece_vocab import bert_vocab_from_dataset as bert_vocab
利用如下方法即可实现,
- bert_vocab.bert_vocab_from_dataset(
- dataset,
- **bert_vocab_args
- )
该方法的关键源码部分为
- tokenizer = bert_tokenizer.BasicTokenizer(**bert_tokenizer_params)
- words_dataset = dataset.map(tokenizer.tokenize)
- word_counts = learner.count_words(words_dataset)
-
- vocab = learner.learn(word_counts, vocab_size, reserved_tokens,
- **learn_params)
-
- return vocab
从数据集里产生wordpiece vocabulary之前,该方法会先通过类对象BasicTokenizer进行分词。我们可以通过使用它,分析一下该对象的分词原理是什么。
导入包,
from tensorflow_text.python.ops import bert_tokenizer
使用该对象对英文文本分词,
- text_inputs1 = [b'taste the rustisc indiefrost']
- text_inputs2 = [b'tastethe rustiscindiefrost']
- a = bert_tokenizer.BasicTokenizer(lower_case=False, normalization_form='NFC')
- print(a.tokenize(text_inputs1))
- print(a.tokenize(text_inputs2))
-
-
-
- <tf.RaggedTensor [[b'taste', b'the', b'rustisc', b'indiefrost']]>
- <tf.RaggedTensor [[b'tastethe', b'rustiscindiefrost']]>
观察输出结果可知,对英文文本是以空格符作为分词依据的
使用该对象对中文文本分词,
- text_inputs1 = '明天你有时间吗'
- text_inputs2 = '明 天 你 有 时 间 吗'
- a = bert_tokenizer.BasicTokenizer(lower_case=False, normalization_form='NFC')
- print(a.tokenize(text_inputs1))
- for i in a.tokenize(text_inputs1).numpy():
- for j in i:
- print(j.decode('utf-8'))
-
- print(a.tokenize(text_inputs2).numpy())
- for i in a.tokenize(text_inputs2).numpy():
- for j in i:
- print(j.decode('utf-8'))
- <tf.RaggedTensor [[b'\xe6\x98\x8e', b'\xe5\xa4\xa9', b'\xe4\xbd\xa0', b'\xe6\x9c\x89',
- b'\xe6\x97\xb6', b'\xe9\x97\xb4', b'\xe5\x90\x97']]>
- 明
- 天
- 你
- 有
- 时
- 间
- 吗
- [[b'\xe6\x98\x8e' b'\xe5\xa4\xa9' b'\xe4\xbd\xa0' b'\xe6\x9c\x89'
- b'\xe6\x97\xb6' b'\xe9\x97\xb4' b'\xe5\x90\x97']]
- 明
- 天
- 你
- 有
- 时
- 间
- 吗
发现对于中文来说,不管字与字之间是否有空格,都会将一句话分解成一个个字。
A basic tokenizer that tokenizes using some deterministic rules: - For most languages, this tokenizer will split on whitespace. - For Chinese, Japanese, and Korean characters, this tokenizer will split on Unicode characters.
学习词汇表,
- dataset = tf.data.Dataset.from_tensor_slices(tf.constant(['明天你有时间吗']))
- en_vocab = bert_vocab.bert_vocab_from_dataset(
- dataset,
- vocab_size=2,
- # Reserved tokens that must be included in the vocabulary
- reserved_tokens=[],
- # Arguments for `text.BertTokenizer`
- bert_tokenizer_params=dict(lower_case=True),
- # Arguments for `wordpiece_vocab.wordpiece_tokenizer_learner_lib.learn`
- learn_params={}
- )
- print(en_vocab)
['你', '吗', '天', '时', '明', '有', '间', '##你', '##吗', '##天', '##时', '##明', '##有', '##间']
将词汇表写入文件,每一行含一个字。然后以形参的方式传给BertTokenizer对象,
- tokenizers = text.BertTokenizer(vocab_lookup_table='vocab.txt')
- print(tokenizers.tokenize(['明天你']))
- <tf.RaggedTensor [[[5],
- [2],
- [0]]]>
输出的维度是三维的,(batch_size, text_length, subword_num),因为中文没有subword的概念,所以subword_num都是为1。
注意:BertTokenizer里的tokenize方法在Tokenizing之前同样调用了BasicTokenizer进行分词处理。上文已经强调了,BasicTokenizer对于中文的分词原则是根据Unicode字符(一个汉字对应一个Unicode字符单位)来进行处理的,也就是说,无需将中文文本的每个字用空格隔开。但在tf.keras.layers.TextVectorization层里需要用空格隔开,因为该层一律是根据空格来进行分词的。
总结:
- tensorflow_text对于中文,日文,韩文的分词是根据Unicode,而英文,葡萄牙文之类的是依据空格的。
- 在tokenizing之前或者学习wordpiece词汇表之前,首先进行的是分词处理。
加深影响,以英文为例,
- tokenizers = text.BertTokenizer(vocab_lookup_table='vocab.txt', lower_case=True)
- print(tokenizers.tokenize(['I am unintended']))
- print(tokenizers.detokenize(tokenizers.tokenize(['I am unintended'])))
- <tf.RaggedTensor [[[3], [4, 5], [0, 1, 2]]]>
- <tf.RaggedTensor [[[b'i'],
- [b'am'],
- [b'unintended']]]>
##代表充当后缀的subword,无##的subword是位于word首部的。
由上面可知,am被分解为a和##m,unintended分解为un,##intend和##ed。
detokenize就是将索引对应的subword在三维数组中沿着-1轴进行拼接。以无##的subword为首,然后向后拼接有##的subword。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。