im钱包安卓版下载
数字资产服务平台

im钱包安卓版下载是全球著名的数字资产交易平台之一,主要面向全球用户提供比特币、莱特币、以太币等数字资产的币币和衍生品交易服务。

比特派app下载安装|tokenizer

时间:2024-03-07 21:29:45

大模型基础组件 - Tokenizer - 知乎

大模型基础组件 - Tokenizer - 知乎首发于AIGC切换模式写文章登录/注册大模型基础组件 - Tokenizernghuyong略懂些NLP|非典型程序员Tokenizer分词算法是NLP大模型最基础的组件,基于Tokenizer可以将文本转换成独立的token列表,进而转换成输入的向量成为计算机可以理解的输入形式。本文将对分词器进行系统梳理,包括分词模型的演化路径,可用的工具,并手推每个tokenizer的具体实现。速览1. 根据不同的切分粒度可以把tokenizer分为: 基于词的切分,基于字的切分和基于subword的切分。 基于subword的切分是目前的主流切分方式。2. subword的切分包括: BPE(/BBPE), WordPiece 和 Unigram三种分词模型。其中WordPiece可以认为是一种特殊的BPE。3. 完整的分词流程包括:文本归一化,预切分,基于分词模型的切分,后处理。4. SentencePiece是一个分词工具,内置BEP等多种分词方法,基于Unicode编码并且将空格视为特殊的token。这是当前大模型的主流分词方案。分词方法典型模型BPEGPT, GPT-2, GPT-J, GPT-Neo, RoBERTa, BART, LLaMA, ChatGLM-6B, BaichuanWordPieceBERT, DistilBERT,MobileBERTUnigramAlBERT, T5, mBART, XLNet1. 基于subword的切分基于subword的切分能很好平衡基于词切分和基于字切分的优缺点,也是目前主流最主流的切分方式。基于词和字的切分都会存在一定的问题,直接应用的效果比较差。基于词的切分,会造成:词表规模过大一定会存在UNK,造成信息丢失不能学习到词缀之间的关系,例如:dog与dogs,happy与unhappy基于字的切分,会造成:每个token的信息密度低序列过长,解码效率很低所以基于词和基于字的切分方式是两个极端,其优缺点也是互补的。而折中的subword就是一种相对平衡的方案。subword的基本切分原则是:高频词依旧切分成完整的整词低频词被切分成有意义的子词,例如 dogs => [dog, ##s]基于subword的切分可以实现:词表规模适中,解码效率较高不存在UNK,信息不丢失能学习到词缀之间的关系基于subword的切分包括:BPE,WordPiece 和 Unigram 三种分词模型。2.切分流程Tokenizer包括训练和推理两个环节。训练阶段指得是从语料中获取一个分词器模型。推理阶段指的是给定一个句子,基于分词模型切分成一连串的token。基本的流程如图所示,包括归一化,预分词,基于分词模型的切分,后处理4个步骤。2.1. 归一化这是最基础的文本清洗,包括删除多余的换行和空格,转小写,移除音调等。例如:input: Héllò hôw are ü?

normalization: hello how are u?HuggingFace tokenizer的实现: https://huggingface.co/docs/tokenizers/api/normalizers2.2. 预分词预分词阶段会把句子切分成更小的“词”单元。可以基于空格或者标点进行切分。 不同的tokenizer的实现细节不一样。例如:input: Hello, how are you?

pre-tokenize:

[BERT]: [('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))]

[GPT2]: [('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)), ('?', (19, 20))]

[t5]: [('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))]

可以看到BERT的tokenizer就是直接基于空格和标点进行切分。 GPT2也是基于空格和标签,但是空格会保留成特殊字符“Ġ”。 T5则只基于空格进行切分,标点不会切分。并且空格会保留成特殊字符"▁",并且句子开头也会添加特殊字符"▁"。预分词的实现: https://huggingface.co/docs/tokenizers/api/pre-tokenizers2.3. 基于分词模型的切分这里指的就是不同分词模型具体的切分方式。分词模型包括:BPE,WordPiece 和 Unigram 三种分词模型。分词模型的实现: https://huggingface.co/docs/tokenizers/api/models2.4. 后处理后处理阶段会包括一些特殊的分词逻辑,例如添加sepcial token:[CLS],[SEP]等。后处理的实现: https://huggingface.co/docs/tokenizers/api/post-processors3.BPEByte-Pair Encoding(BPE)是最广泛采用的subword分词器。训练方法:从字符级的小词表出发,训练产生合并规则以及一个词表编码方法:将文本切分成字符,再应用训练阶段获得的合并规则经典模型:GPT, GPT-2, RoBERTa, BART, LLaMA, ChatGLM等3.1. 训练阶段在训练环节,目标是给定语料,通过训练算法,生成合并规则和词表。 BPE算法是从一个字符级别的词表为基础,合并pair并添加到词表中,逐步形成大词表。合并规则为选择相邻pair词频最大的进行合并。下面我们进行手工的实现。假定训练的语料(已归一化处理)为4个句子。corpus = [

"This is the Hugging Face Course.",

"This chapter is about tokenization.",

"This section shows several tokenizer algorithms.",

"Hopefully, you will be able to understand how they are trained and generate tokens.",

]首先进行预切分处理。这里采用gpt2的预切分逻辑。 具体会按照空格和标点进行切分,并且空格会保留成特殊的字符“Ġ”。from transformers import AutoTokenizer

# init pre tokenize function

gpt2_tokenizer = AutoTokenizer.from_pretrained("gpt2")

pre_tokenize_function = gpt2_tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str

# pre tokenize

pre_tokenized_corpus = [pre_tokenize_str(text) for text in corpus]

获得的pre_tokenized_corpus如下,每个单元分别为[word, (start_index, end_index)][

[('This', (0, 4)), ('Ġis', (4, 7)), ('Ġthe', (7, 11)), ('ĠHugging', (11, 19)), ('ĠFace', (19, 24)), ('ĠCourse', (24, 31)), ('.', (31, 32))],

[('This', (0, 4)), ('Ġchapter', (4, 12)), ('Ġis', (12, 15)), ('Ġabout', (15, 21)), ('Ġtokenization', (21, 34)), ('.', (34, 35))],

[('This', (0, 4)), ('Ġsection', (4, 12)), ('Ġshows', (12, 18)), ('Ġseveral', (18, 26)), ('Ġtokenizer', (26, 36)), ('Ġalgorithms', (36, 47)), ('.', (47, 48))],

[('Hopefully', (0, 9)), (',', (9, 10)), ('Ġyou', (10, 14)), ('Ġwill', (14, 19)), ('Ġbe', (19, 22)), ('Ġable', (22, 27)), ('Ġto', (27, 30)), ('Ġunderstand', (30, 41)), ('Ġhow', (41, 45)), ('Ġthey', (45, 50)), ('Ġare', (50, 54)), ('Ġtrained', (54, 62)), ('Ġand', (62, 66)), ('Ġgenerate', (66, 75)), ('Ġtokens', (75, 82)), ('.', (82, 83))]

]

进一步统计每个整词的词频word2count = defaultdict(int)

for split_text in pre_tokenized_corpus:

for word, _ in split_text:

word2count[word] += 1

获得word2count如下defaultdict(, {'This': 3, 'Ġis': 2, 'Ġthe': 1, 'ĠHugging': 1, 'ĠFace': 1, 'ĠCourse': 1, '.': 4, 'Ġchapter': 1, 'Ġabout': 1, 'Ġtokenization': 1, 'Ġsection': 1, 'Ġshows': 1, 'Ġseveral': 1, 'Ġtokenizer': 1, 'Ġalgorithms': 1, 'Hopefully': 1, ',': 1, 'Ġyou': 1, 'Ġwill': 1, 'Ġbe': 1, 'Ġable': 1, 'Ġto': 1, 'Ġunderstand': 1, 'Ġhow': 1, 'Ġthey': 1, 'Ġare': 1, 'Ġtrained': 1, 'Ġand': 1, 'Ġgenerate': 1, 'Ġtokens': 1})

因为BPE是从字符级别的小词表,逐步合并成大词表,所以需要先获得字符级别的小词表。vocab_set = set()

for word in word2count:

vocab_set.update(list(word))

vocabs = list(vocab_set)

获得的初始小词表vocabs如下:['i', 't', 'p', 'o', 'r', 'm', 'e', ',', 'y', 'v', 'Ġ', 'F', 'a', 'C', 'H', '.', 'f', 'l', 'u', 'c', 'T', 'k', 'h', 'z', 'd', 'g', 'w', 'n', 's', 'b']

基于小词表就可以对每个整词进行切分word2splits = {word: [c for c in word] for word in word2count}

'This': ['T', 'h', 'i', 's'],

'Ġis': ['Ġ', 'i', 's'],

'Ġthe': ['Ġ', 't', 'h', 'e'],

...

'Ġand': ['Ġ', 'a', 'n', 'd'],

'Ġgenerate': ['Ġ', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e'],

'Ġtokens': ['Ġ', 't', 'o', 'k', 'e', 'n', 's']

基于word2splits统计vocabs中相邻两个pair的词频pair2countdef _compute_pair2score(word2splits, word2count):

pair2count = defaultdict(int)

for word, word_count in word2count.items():

split = word2splits[word]

if len(split) == 1:

continue

for i in range(len(split) - 1):

pair = (split[i], split[i + 1])

pair2count[pair] += word_count

return pair2count

获得pair2count如下:defaultdict(, {('T', 'h'): 3, ('h', 'i'): 3, ('i', 's'): 5, ('Ġ', 'i'): 2, ('Ġ', 't'): 7, ('t', 'h'): 3, ..., ('n', 's'): 1})

统计当前频率最高的相邻pairdef _compute_most_score_pair(pair2count):

best_pair = None

max_freq = None

for pair, freq in pair2count.items():

if max_freq is None or max_freq < freq:

best_pair = pair

max_freq = freq

return best_pair

经过统计,当前频率最高的pair为: ('Ġ', 't'), 频率为7次。 将('Ġ', 't')合并成一个词并添加到词表中。同时在合并规则中添加('Ġ', 't')这条合并规则。merge_rules = []

best_pair = self._compute_most_score_pair(pair2score)

vocabs.append(best_pair[0] + best_pair[1])

merge_rules.append(best_pair)

此时的vocab词表更新成:['i', 't', 'p', 'o', 'r', 'm', 'e', ',', 'y', 'v', 'Ġ', 'F', 'a', 'C', 'H', '.', 'f', 'l', 'u', 'c', 'T', 'k', 'h', 'z', 'd', 'g', 'w', 'n', 's', 'b',

'Ġt']

根据更新后的vocab重新对word2count进行切分。具体实现上,可以直接在旧的word2split上应用新的合并规则('Ġ', 't')def _merge_pair(a, b, word2splits):

new_word2splits = dict()

for word, split in word2splits.items():

if len(split) == 1:

new_word2splits[word] = split

continue

i = 0

while i < len(split) - 1:

if split[i] == a and split[i + 1] == b:

split = split[:i] + [a + b] + split[i + 2:]

else:

i += 1

new_word2splits[word] = split

return new_word2splits

从而获得新的word2split{'This': ['T', 'h', 'i', 's'],

'Ġis': ['Ġ', 'i', 's'],

'Ġthe': ['Ġt', 'h', 'e'],

'ĠHugging': ['Ġ', 'H', 'u', 'g', 'g', 'i', 'n', 'g'],

...

'Ġtokens': ['Ġt', 'o', 'k', 'e', 'n', 's']}

可以看到新的word2split中已经包含了新的词"Ġt"。重复上述循环直到整个词表的大小达到预先设定的词表大小。while len(vocabs) < vocab_size:

pair2score = self._compute_pair2score(word2splits, word2count)

best_pair = self._compute_most_score_pair(pair2score)

vocabs.append(best_pair[0] + best_pair[1])

merge_rules.append(best_pair)

word2splits = self._merge_pair(best_pair[0], best_pair[1], word2splits)

假定最终词表的大小为50,经过上述迭代后我们获得的词表和合并规则如下:vocabs = ['i', 't', 'p', 'o', 'r', 'm', 'e', ',', 'y', 'v', 'Ġ', 'F', 'a', 'C', 'H', '.', 'f', 'l', 'u', 'c', 'T', 'k', 'h', 'z', 'd', 'g', 'w', 'n', 's', 'b', 'Ġt', 'is', 'er', 'Ġa', 'Ġto', 'en', 'Th', 'This', 'ou', 'se', 'Ġtok', 'Ġtoken', 'nd', 'Ġis', 'Ġth', 'Ġthe', 'in', 'Ġab', 'Ġtokeni', 'Ġtokeniz']

merge_rules = [('Ġ', 't'), ('i', 's'), ('e', 'r'), ('Ġ', 'a'), ('Ġt', 'o'), ('e', 'n'), ('T', 'h'), ('Th', 'is'), ('o', 'u'), ('s', 'e'), ('Ġto', 'k'), ('Ġtok', 'en'), ('n', 'd'), ('Ġ', 'is'), ('Ġt', 'h'), ('Ġth', 'e'), ('i', 'n'), ('Ġa', 'b'), ('Ġtoken', 'i'), ('Ġtokeni', 'z')]

至此我们就根据给定的语料完成了BPE分词器的训练。3.2. 推理阶段在推理阶段,给定一个句子,我们需要将其切分成一个token的序列。 具体实现上需要先对句子进行预分词并切分成字符级别的序列,然后根据合并规则进行合并。def tokenize(self, text: str) -> List[str]:

# pre tokenize

words = [word for word, _ in self.pre_tokenize_str(text)]

# split into char level

splits = [[c for c in word] for word in words]

# apply merge rules

for merge_rule in self.merge_rules:

for index, split in enumerate(splits):

i = 0

while i < len(split) - 1:

if split[i] == merge_rule[0] and split[i + 1] == merge_rule[1]:

split = split[:i] + ["".join(merge_rule)] + split[i + 2:]

else:

i += 1

splits[index] = split

return sum(splits, [])

例如>>> tokenize("This is not a token.")

>>> ['This', 'Ġis', 'Ġ', 'n', 'o', 't', 'Ġa', 'Ġtoken', '.']

3.3. BBPE2019年提出的Byte-level BPE (BBPE)算法是上面BPE算法的进一步升级。具体参见:Neural Machine Translation with Byte-Level Subwords。 核心思想是用byte来构建最基础的词表而不是字符。首先将文本按照UTF-8进行编码,每个字符在UTF-8的表示中占据1-4个byte。 在byte序列上再使用BPE算法,进行byte level的相邻合并。编码形式如下图所示:通过这种方式可以更好的处理跨语言和不常见字符的特殊问题(例如,颜文字),相比传统的BPE更节省词表空间(同等词表大小效果更好),每个token也能获得更充分的训练。但是在解码阶段,一个byte序列可能解码后不是一个合法的字符序列,这里需要采用动态规划的算法进行解码,使其能解码出尽可能多的合法字符。具体算法如下: 假定f(k)表示字符序列B_{1,k}最大能解码的合法字符数量,f(k)有最优的子结构:f(k) = max_{t=1,2,3,4}{f(k-t) + g(k-t+1, k)}这里如果B_{i,j}为一个合法字符g(i,j) = 1,否则g(i,j) = 0。4. WordPieceWordPiece分词与BPE非常类似,只是在训练阶段合并pair的策略不是pair的频率而是互信息。socre = log(p(ab)) - (log(p(a)) + log(p(b))) = log(p(ab)/p(a)p(b))这里的动机是一个pair的频率很高,但是其中pair的一部分的频率更高,这时候不一定需要进行该pair的合并。 而如果一个pair的频率很高,并且这个pair的两个部分都是只出现在这个pair中,就说明这个pair很值得合并。训练方法:从字符级的小词表出发,训练产生合并规则以及一个词表编码方法:将文本切分成词,对每个词在词表中进行最大前向匹配经典模型:BERT及其系列DistilBERT,MobileBERT等4.1. 训练阶段在训练环节,给定语料,通过训练算法,生成最终的词表。 WordPiece算法也是从一个字符级别的词表为基础,逐步扩充成大词表。合并规则为选择相邻pair互信息最大的进行合并。下面进行具体手工实现。假定训练的语料(已归一化处理)为corpus = [

"This is the Hugging Face Course.",

"This chapter is about tokenization.",

"This section shows several tokenizer algorithms.",

"Hopefully, you will be able to understand how they are trained and generate tokens.",

]

首先进行预切分处理。这里采用BERT的预切分逻辑。具体会按照空格和标点进行切分。from transformers import AutoTokenizer

# init pre tokenize function

bert_tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

pre_tokenize_function = bert_tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str

# pre tokenize

pre_tokenized_corpus = [pre_tokenize_str(text) for text in corpus]

获得的pre_tokenized_corpus如下,每个单元分别为[word, (start_index, end_index)][

[('This', (0, 4)), ('is', (5, 7)), ('the', (8, 11)), ('Hugging', (12, 19)), ('Face', (20, 24)), ('Course', (25, 31)), ('.', (31, 32))],

[('This', (0, 4)), ('chapter', (5, 12)), ('is', (13, 15)), ('about', (16, 21)), ('tokenization', (22, 34)), ('.', (34, 35))],

[('This', (0, 4)), ('section', (5, 12)), ('shows', (13, 18)), ('several', (19, 26)), ('tokenizer', (27, 36)), ('algorithms', (37, 47)), ('.', (47, 48))],

[('Hopefully', (0, 9)), (',', (9, 10)), ('you', (11, 14)), ('will', (15, 19)), ('be', (20, 22)), ('able', (23, 27)), ('to', (28, 30)), ('understand', (31, 41)), ('how', (42, 45)), ('they', (46, 50)), ('are', (51, 54)), ('trained', (55, 62)), ('and', (63, 66)), ('generate', (67, 75)), ('tokens', (76, 82)), ('.', (82, 83))]

]

进一步统计词频word2count = defaultdict(int)

for split_text in pre_tokenized_corpus:

for word, _ in split_text:

word2count[word] += 1

获得word2count如下defaultdict(, {'This': 3, 'is': 2, 'the': 1, 'Hugging': 1, 'Face': 1, 'Course': 1, '.': 4, 'chapter': 1, 'about': 1, 'tokenization': 1, 'section': 1, 'shows': 1, 'several': 1, 'tokenizer': 1, 'algorithms': 1, 'Hopefully': 1, ',': 1, 'you': 1, 'will': 1, 'be': 1, 'able': 1, 'to': 1, 'understand': 1, 'how': 1, 'they': 1, 'are': 1, 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1})

因为WordPiece同样是从字符级别的小词表,逐步合并成大词表,所以先获得字符级别的小词表。注意这里如果字符不是不一个词的开始,需要添加上特殊字符"##"。vocab_set = set()

for word in word2count:

vocab_set.add(word[0])

vocab_set.update(['##' + c for c in word[1:]])

vocabs = list(vocab_set)

获得的初始小词表vocabs如下:['##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', 'w', 'y']

基于小词表对每个词进行切分word2splits = {word: [word[0]] + ['##' + c for c in word[1:]] for word in word2count}

{'This': ['T', '##h', '##i', '##s'],

'is': ['i', '##s'],

'the': ['t', '##h', '##e'],

'Hugging': ['H', '##u', '##g', '##g', '##i', '##n', '##g'],

...

'generate': ['g', '##e', '##n', '##e', '##r', '##a', '##t', '##e'],

'tokens': ['t', '##o', '##k', '##e', '##n', '##s']}

进一步统计vocabs中相邻两个pair的互信息def _compute_pair2score(word2splits, word2count):

"""

计算每个pair的分数

score=(freq_of_pair)/(freq_of_first_element×freq_of_second_element)

:return:

"""

vocab2count = defaultdict(int)

pair2count = defaultdict(int)

for word, word_count in word2count.items():

splits = word2splits[word]

if len(splits) == 1:

vocab2count[splits[0]] += word_count

continue

for i in range(len(splits) - 1):

pair = (splits[i], splits[i + 1])

vocab2count[splits[i]] += word_count

pair2count[pair] += word_count

vocab2count[splits[-1]] += word_count

scores = {

pair: freq / (vocab2count[pair[0]] * vocab2count[pair[1]])

for pair, freq in pair2count.items()

}

return scores

获得每个pair的互信息如下:{('T', '##h'): 0.125,

('##h', '##i'): 0.03409090909090909,

('##i', '##s'): 0.02727272727272727,

('a', '##b'): 0.2,

...

('##n', '##s'): 0.00909090909090909}

统计出互信息最高的相邻pairdef _compute_most_score_pair(pair2score):

best_pair = None

max_score = None

for pair, score in pair2score.items():

if max_score is None or max_score < score:

best_pair = pair

max_score = score

return best_pair

此时互信息最高的pair为: ('a', '##b') 将('a', '##b')合并成一个词'ab'并添加到词表中best_pair = self._compute_most_score_pair(pair2score)

vocabs.append(best_pair[0] + best_pair[1])

这样vocab词表更新成:['##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', 'w', 'y',

'ab']

根据更新的vocab重新对word2count进行切分。def _merge_pair(a, b, word2splits):

new_word2splits = dict()

for word, split in word2splits.items():

if len(split) == 1:

new_word2splits[word] = split

continue

i = 0

while i < len(split) - 1:

if split[i] == a and split[i + 1] == b:

merge = a + b[2:] if b.startswith("##") else a + b

split = split[:i] + [merge] + split[i + 2:]

else:

i += 1

new_word2splits[word] = split

return new_word2splits

获得新的word2split{'This': ['T', '##h', '##i', '##s'],

'is': ['i', '##s'], 'the': ['t', '##h', '##e'],

'Hugging': ['H', '##u', '##g', '##g', '##i', '##n', '##g'],

'about': ['ab', '##o', '##u', '##t'],

'tokens': ['t', '##o', '##k', '##e', '##n', '##s']}

可以看到新的word2split中已经包含了新的词"ab"。重复上述步骤,直到整个词表的大小达到预先设定的词表大小。while len(vocabs) < vocab_size:

pair2score = self._compute_pair2score(word2splits, word2count)

best_pair = self._compute_most_score_pair(pair2score)

word2splits = self._merge_pair(best_pair[0], best_pair[1], word2splits)

new_token = best_pair[0] + best_pair[1][2:] if best_pair[1].startswith('##') else best_pair[1]

vocabs.append(new_token)

假定最终词表的大小为70,经过上述迭代后我们获得的词表如下:vocabs = ['##a', '##b', '##c', '##ct', '##d', '##e', '##f', '##fu', '##ful', '##full', '##fully', '##g', '##h', '##hm', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##thm', '##thms', '##u', '##ut', '##v', '##w', '##y', '##z', '##za', '##zat', ',', '.', 'C', 'F', 'Fa', 'Fac', 'H', 'Hu', 'Hug', 'Hugg', 'T', 'Th', 'a', 'ab', 'b', 'c', 'ch', 'cha', 'chap', 'chapt', 'g', 'h', 'i', 'is', 's', 'sh', 't', 'th', 'u', 'w', 'y', '[CLS]', '[MASK]', '[PAD]', '[SEP]', '[UNK]']

注意词表中添加了特殊的token:[CLS], [MASK], [PAD], [SEP], [UNK] 至此我们就根据给定的语料完成了WordPiece分词器的训练。4.2. 推理阶段在推理阶段,给定一个句子,需要将其切分成一个token的序列。 具体实现上需要先对句子进行预分词,然后对每个词进行在词表中进行最大前向的匹配。如果词表中不存在则为UNK。def _encode_word(self, word):

tokens = []

while len(word) > 0:

i = len(word)

while i > 0 and word[:i] not in self.vocabs:

i -= 1

if i == 0:

return ["[UNK]"]

tokens.append(word[:i])

word = word[i:]

if len(word) > 0:

word = f"##{word}"

return tokens

def tokenize(self, text):

words = [word for word, _ in self.pre_tokenize_str(text)]

encoded_words = [self._encode_word(word) for word in words]

return sum(encoded_words, [])

例如>>> tokenize("This is the Hugging Face course!")

>>> ['Th', '##i', '##s', 'is', 'th', '##e', 'Hugg', '##i', '##n', '##g', 'Fac', '##e', 'c', '##o', '##u', '##r', '##s', '##e', '[UNK]']

5. UnigramUnigram分词与BPE和WordPiece不同,是基于一个大词表逐步裁剪成一个小词表。 通过Unigram语言模型计算删除不同subword造成的损失来衡量subword的重要性,保留重要性较高的子词。训练方法:从包含字符和全部子词的大词表出发,逐步裁剪出一个小词表,并且每个词都有自己的分数。编码方法:将文本切分成词,对每个词基于Viterbi算法求解出最佳解码路径。经典模型:AlBERT, T5, mBART, Big Bird, XLNet5.1. 训练阶段在训练环节,目标是给定语料,通过训练算法,生成最终的词表,并且每个词有自己的概率值。 Unigram算法是从大词表为基础,逐步裁剪成小词表。裁剪规则是根据Unigram语言模型的打分依次裁剪重要度相对较低的词。下面进行具体手工实现。假定训练的语料(已归一化处理)为corpus = [

"This is the Hugging Face Course.",

"This chapter is about tokenization.",

"This section shows several tokenizer algorithms.",

"Hopefully, you will be able to understand how they are trained and generate tokens.",

]

首先进行预切分处理。这里采用xlnet的预切分逻辑。具体会按照空格进行切分,标点不会切分。并且空格会保留成特殊字符"▁",句子开头也会添加特殊字符"▁"。from transformers import AutoTokenizer

# init pre tokenize function

xlnet_tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased")

pre_tokenize_function = xlnet_tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str

# pre tokenize

pre_tokenized_corpus = [pre_tokenize_str(text) for text in corpus]

获得的pre_tokenized_corpus如下,每个单元分别为[word, (start_index, end_index)][

[('▁This', (0, 4)), ('▁is', (5, 7)), ('▁the', (8, 11)), ('▁Hugging', (12, 19)), ('▁Face', (20, 24)), ('▁Course.', (25, 32))],

[('▁This', (0, 4)), ('▁chapter', (5, 12)), ('▁is', (13, 15)), ('▁about', (16, 21)), ('▁tokenization.', (22, 35))],

[('▁This', (0, 4)), ('▁section', (5, 12)), ('▁shows', (13, 18)), ('▁several', (19, 26)), ('▁tokenizer', (27, 36)), ('▁algorithms.', (37, 48))],

[('▁Hopefully,', (0, 10)), ('▁you', (11, 14)), ('▁will', (15, 19)), ('▁be', (20, 22)), ('▁able', (23, 27)), ('▁to', (28, 30)), ('▁understand', (31, 41)), ('▁how', (42, 45)), ('▁they', (46, 50)), ('▁are', (51, 54)), ('▁trained', (55, 62)), ('▁and', (63, 66)), ('▁generate', (67, 75)), ('▁tokens.', (76, 83))]

]

进一步统计词频word2count = defaultdict(int)

for split_text in pre_tokenized_corpus:

for word, _ in split_text:

word2count[word] += 1

获得word2count如下defaultdict(, {'▁This': 3, '▁is': 2, '▁the': 1, '▁Hugging': 1, '▁Face': 1, '▁Course.': 1, '▁chapter': 1, '▁about': 1, '▁tokenization.': 1, '▁section': 1, '▁shows': 1, '▁several': 1, '▁tokenizer': 1, '▁algorithms.': 1, '▁Hopefully,': 1, '▁you': 1, '▁will': 1, '▁be': 1, '▁able': 1, '▁to': 1, '▁understand': 1, '▁how': 1, '▁they': 1, '▁are': 1, '▁trained': 1, '▁and': 1, '▁generate': 1, '▁tokens.': 1})

统计词表的全部子词和词频,取前300个词,构成最初的大词表。为了避免OOV,char级别的词均需要保留。char2count = defaultdict(int)

sub_word2count = defaultdict(int)

for word, count in word2count.items():

for i in range(len(word)):

char2count[word[i]] += count

for j in range(i + 2, len(word) + 1):

sub_word2count[word[i:j]] += count

sorted_sub_words = sorted(sub_word2count.items(), key=lambda x: x[1], reverse=True)

# init a large vocab with 300

tokens = list(char2count.items()) + sorted_sub_words[: 300 - len(char2count)]

获得的初始小词表vocabs如下:[('▁', 31), ('T', 3), ('h', 9), ('i', 13), ('s', 13), ..., ('several', 1)]

进一步统计每个子词的概率,并转换成Unigram里的loss贡献token2count = {token: count for token, count in tokens}

total_count = sum([count for token, count in token2count.items()])

model = {token: -log(count / total_count) for token, count in token2count.items()}

model = {

'▁': 2.952892114877499,

'T': 5.288267030694535,

'h': 4.189654742026425,

...,

'sever': 6.386879319362645,

'severa': 6.386879319362645,

'several': 6.386879319362645

}

基于每个子词的loss以及Viterbi算法就可以求解出,输入的一个词的最佳分词路径。即整体语言模型的loss最小。词的长度为N,解码的时间复杂度为O(N^2)。def _encode_word(word, model):

best_segmentations = [{"start": 0, "score": 1}] + [{"start": None, "score": None} for _ in range(len(word))]

for start_idx in range(len(word)):

# This should be properly filled by the previous steps of the loop

best_score_at_start = best_segmentations[start_idx]["score"]

for end_idx in range(start_idx + 1, len(word) + 1):

token = word[start_idx:end_idx]

if token in model and best_score_at_start is not None:

score = model[token] + best_score_at_start

# If we have found a better segmentation (lower score) ending at end_idx

if (

best_segmentations[end_idx]["score"] is None

or best_segmentations[end_idx]["score"] > score

):

best_segmentations[end_idx] = {"start": start_idx, "score": score}

segmentation = best_segmentations[-1]

if segmentation["score"] is None:

# We did not find a tokenization of the word -> unknown

return [""], None

score = segmentation["score"]

start = segmentation["start"]

end = len(word)

tokens = []

while start != 0:

tokens.insert(0, word[start:end])

next_start = best_segmentations[start]["start"]

end = start

start = next_start

tokens.insert(0, word[start:end])

return tokens, score

例如:>>> tokenize("This")

>>> (['This'], 6.288267030694535)

>>> tokenize("this")

>>>(['t', 'his'], 10.03608902044192)

基于上述的函数,可以获得任一个词的分词路径,以及loss。这样就可以计算整个语料上的loss。def _compute_loss(self, model, word2count):

loss = 0

for word, freq in word2count.items():

_, word_loss = self._encode_word(word, model)

loss += freq * word_loss

return loss

尝试移除model中的一个子词,并计算移除后新的model在全部语料上的loss,从而获得这个子词的score,即删除这个子词使得loss新增的量。def _compute_scores(self, model, word2count):

scores = {}

model_loss = self._compute_loss(model, word2count)

for token, score in model.items():

# We always keep tokens of length 1

if len(token) == 1:

continue

model_without_token = copy.deepcopy(model)

_ = model_without_token.pop(token)

scores[token] = self._compute_loss(model_without_token, word2count) - model_loss

return scores

scores = self._compute_scores(model, word2count)

为了提升迭代效率,批量删除前10%的结果,即让整体loss增量最小的前10%的词。(删除这些词对整体loss的影响不大。)sorted_scores = sorted(scores.items(), key=lambda x: x[1])

# Remove percent_to_remove tokens with the lowest scores.

for i in range(int(len(model) * 0.1)):

_ = token2count.pop(sorted_scores[i][0])

获得新的词表后,重新计算每个词的概率,获得新的模型。并重复以上步骤,直到裁剪到词表大小符合要求。while len(model) > vocab_size:

scores = self._compute_scores(model, word2count)

sorted_scores = sorted(scores.items(), key=lambda x: x[1])

# Remove percent_to_remove tokens with the lowest scores.

for i in range(int(len(model) * percent_to_remove)):

_ = token2count.pop(sorted_scores[i][0])

total_count = sum([freq for token, freq in token2count.items()])

model = {token: -log(count / total_count) for token, count in token2count.items()}

假定预设的词表的大小为100,经过上述迭代后我们获得词表如下:model = {

'▁': 2.318585434340487,

'T': 4.653960350157523,

'h': 3.5553480614894135,

'i': 3.1876232813640963,

...

'seve': 5.752572638825633,

'sever': 5.752572638825633,

'severa': 5.752572638825633,

'several': 5.752572638825633

}

5.2. 推理阶段在推理阶段,给定一个句子,需要将其切分成一个token的序列。 具体实现上先对句子进行预分词,然后对每个词基于Viterbi算法进行解码。def tokenize(self, text):

words = [word for word, _ in self.pre_tokenize_str(text)]

encoded_words = [self._encode_word(word, self.model)[0] for word in words]

return sum(encoded_words, [])

例如>>> tokenize("This is the Hugging Face course!")

>>> ['▁This', '▁is', '▁the', '▁Hugging', '▁Face', '▁', 'c', 'ou', 'r', 's', 'e', '.']

基于Viterbi的切分获得的是最佳切分,基于unigram可以实现一个句子的多种切分方式,并且可以获得每种切分路径的打分。6. SentencePieceSentencePiece是Google出的一个分词工具:内置BPE,Unigram,char和word的分词方法无需预分词,以unicode方式直接编码整个句子,空格会被特殊编码为▁相比传统实现进行优化,分词速度速度更快当前主流的大模型都是基于sentencepiece实现,例如ChatGLM的tokenizer。...

class TextTokenizer:

def __init__(self, model_path):

self.sp = spm.SentencePieceProcessor()

self.sp.Load(model_path)

self.num_tokens = self.sp.vocab_size()

def encode(self, text):

return self.sp.EncodeAsIds(text)

def decode(self, ids: List[int]):

return self.sp.DecodeIds(ids)

...

https://huggingface.co/THUDM/chatglm-6b/blob/main/tokenization_chatglm.py#L216.1. byte回退当SentencePiece在训练BPE的时开启--byte_fallback, 在效果上类似BBPE,遇到UNK会继续按照byte进行进一步的切分。参见:https://github.com/google/sentencepiece/issues/621 具体实现上是将<0x00> ... <0xFF>这256个token添加到词表中。分析ChatGLM的模型,可以发现ChatGLM就是开启了--byte_fallbackfrom sentencepiece import sentencepiece_model_pb2

m = sentencepiece_model_pb2.ModelProto()

with open('chatglm-6b/ice_text.model', 'rb') as f:

m.ParseFromString(f.read())

print('ChatGLM tokenizer\n\n'+str(m.trainer_spec))

output:ChatGLM tokenizer

input: "/root/train_cn_en.json"

model_prefix: "new_ice_unigram"

vocab_size: 130000

character_coverage: 0.9998999834060669

split_digits: true

user_defined_symbols: ""

byte_fallback: true

pad_id: 3

train_extremely_large_corpus: true

可以看到byte_fallback: true同样的方法,可以验证LLaMA, ChatGLM-6B, Baichuan这些大模型都是基于sentencepiece实现的BPE的分词算法,并且采用byte回退。参考HuggingFace tokenizer tutorialgoogle/sentencepieceBPE: Neural Machine Translation of Rare Words with Subword UnitsBBPE: Neural Machine Translation with Byte-Level SubwordsUnigram: Subword Regularization: Improving Neural Network Translation Models with Multiple Subword CandidatesSentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing编辑于 2024-01-17 17:34・IP 属地北京大模型分词​赞同 232​​4 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录AIGCLLM,agen

深度学习文本预处理利器:Tokenizer详解-CSDN博客

>

深度学习文本预处理利器:Tokenizer详解-CSDN博客

深度学习文本预处理利器:Tokenizer详解

智慧医疗探索者

已于 2023-09-21 16:58:13 修改

阅读量3.1k

收藏

13

点赞数

4

分类专栏:

深度学习之pytorch

文章标签:

keras

人工智能

深度学习

词向量

Tokenizer

于 2023-09-21 16:12:46 首次发布

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/lsb2002/article/details/133095184

版权

深度学习之pytorch

专栏收录该内容

23 篇文章

3 订阅

订阅专栏

目录

1 Tokenizer 介绍

1.1 Tokenizer定义

 1.2 Tokenizer方法

 1.3 Tokenizer属性

2 Tokenizer文本向量化

2.1 英文文本向量化

2.2 中文文本向量化

3 总结

1 Tokenizer 介绍

Tokenizer是一个用于向量化文本,将文本转换为序列的类。计算机在处理语言文字时,是无法理解文字含义的,通常会把一个词(中文单个字或者词)转化为一个正整数,将一个文本就变成了一个序列,然后再对序列进行向量化,向量化后的数据送入模型处理。

Tokenizer 允许使用两种方法向量化一个文本语料库: 将每个文本转化为一个整数序列(每个整数都是词典中标记的索引); 或者将其转化为一个向量,其中每个标记的系数可以是二进制值、词频、TF-IDF权重等。

1.1 Tokenizer定义

keras.preprocessing.text.Tokenizer(num_words=None,

filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~ ',

lower=True,

split=' ',

char_level=False,

oov_token=None,

document_count=0)

参数说明:

num_words: 需要保留的最大词数,基于词频。只有最常出现的 num_words 词会被保留。filters: 一个字符串,其中每个元素是一个将从文本中过滤掉的字符。默认值是所有标点符号,加上制表符和换行符,减去 ’ 字符。lower: 布尔值。是否将文本转换为小写。split: 字符串。按该字符串切割文本。char_level: 如果为 True,则每个字符都将被视为标记。oov_token: 如果给出,它将被添加到 word_index 中,并用于在 text_to_sequence 调用期间替换词汇表外的单词。

 1.2 Tokenizer方法

(1)fit_on_texts(texts)

参数 texts:要用以训练的文本列表。返回值:无。

(2)texts_to_sequences(texts)

参数 texts:待转为序列的文本列表。返回值:序列的列表,列表中每个序列对应于一段输入文本。

(3)texts_to_sequences_generator(texts)

本函数是texts_to_sequences的生成器函数版。

参数 texts:待转为序列的文本列表。返回值:每次调用返回对应于一段输入文本的序列。

(4)texts_to_matrix(texts, mode) :

参数 texts:待向量化的文本列表。参数 mode:'binary','count','tfidf','freq' 之一,默认为 'binary'。返回值:形如(len(texts), num_words) 的numpy array。

(5)fit_on_sequences(sequences) :

参数 sequences:要用以训练的序列列表。返回值:无

(5)sequences_to_matrix(sequences) :

参数 sequences:待向量化的序列列表。参数 mode:'binary','count','tfidf','freq' 之一,默认为 'binary'。返回值:形如(len(sequences), num_words) 的 numpy array。

 1.3 Tokenizer属性

(1)word_counts

类型:字典

描述:将单词(字符串)映射为它们在训练期间出现的次数。仅在调用fit_on_texts之后设置。

(2)word_docs

类型:字典

描述:将单词(字符串)映射为它们在训练期间所出现的文档或文本的数量。仅在调用fit_on_texts之后设置。

(3)word_index

类型:字典,

描述:将单词(字符串)映射为它们的排名或者索引。仅在调用fit_on_texts之后设置。

(4)document_count

类型:整数。

描述:分词器被训练的文档(文本或者序列)数量。仅在调用fit_on_texts或fit_on_sequences之后设置。

2 Tokenizer文本向量化

2.1 英文文本向量化

默认情况下,删除所有标点符号,将文本转换为空格分隔的单词序列(单词可能包含 ’ 字符)。 这些序列然后被分割成标记列表。然后它们将被索引或向量化。0是不会被分配给任何单词的保留索引。

from keras.preprocessing.text import Tokenizer

texts = ["Life is a journey, and if you fall in love with the journey, you will be in love forever.",

"Dreams are like stars, you may never touch them, but if you follow them, they will lead you to your destiny.",

"Memories are the heart's treasures, they hold the wisdom and beauty of our past.",

"Nature is the most beautiful artist, its paintings are endless and always breathtaking.",

"True happiness is not about having everything, but about being content with what you have.",

"Wisdom comes with age, but more often with experience.",

"Music has the power to transport us to a different place, a different time.",

"Love is blind, but often sees more than others.",

"Time heals all wounds, but only if you let it.",

"Home is where the heart is, and for many, that is where the memories are."]

tokenizer = Tokenizer(num_words=64, filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',

lower=True, split=' ', char_level=False, oov_token=None,

document_count=0)

# 根据输入的文本列表更新内部字典

tokenizer.fit_on_texts(texts)

print("处理的文档数量,document_count: ", tokenizer.document_count)

print("单词到索引的映射,word_index: \n", tokenizer.word_index)

print("索引到单词的映射,index_word: \n", tokenizer.index_word)

print("每个单词出现的总频次,word_counts: \n", tokenizer.word_counts)

print("出现单词的文档的数量,word_docs: \n", tokenizer.word_docs)

print("单词索引对应的出现单词的文档的数量,index_docs: \n", tokenizer.index_docs)

运行结果显示如下:

处理的文档数量,document_count: 10

单词到索引的映射,word_index:

{'is': 1, 'you': 2, 'the': 3, 'but': 4, 'and': 5, 'with': 6, 'are': 7, 'a': 8, 'if': 9, 'love': 10, 'to': 11, 'journey': 12, 'in': 13, 'will': 14, 'them': 15, 'they': 16, 'memories': 17, 'wisdom': 18, 'about': 19, 'more': 20, 'often': 21, 'different': 22, 'time': 23, 'where': 24, 'life': 25, 'fall': 26, 'be': 27, 'forever': 28, 'dreams': 29, 'like': 30, 'stars': 31, 'may': 32, 'never': 33, 'touch': 34, 'follow': 35, 'lead': 36, 'your': 37, 'destiny': 38, "heart's": 39, 'treasures': 40, 'hold': 41, 'beauty': 42, 'of': 43, 'our': 44, 'past': 45, 'nature': 46, 'most': 47, 'beautiful': 48, 'artist': 49, 'its': 50, 'paintings': 51, 'endless': 52, 'always': 53, 'breathtaking': 54, 'true': 55, 'happiness': 56, 'not': 57, 'having': 58, 'everything': 59, 'being': 60, 'content': 61, 'what': 62, 'have': 63, 'comes': 64, 'age': 65, 'experience': 66, 'music': 67, 'has': 68, 'power': 69, 'transport': 70, 'us': 71, 'place': 72, 'blind': 73, 'sees': 74, 'than': 75, 'others': 76, 'heals': 77, 'all': 78, 'wounds': 79, 'only': 80, 'let': 81, 'it': 82, 'home': 83, 'heart': 84, 'for': 85, 'many': 86, 'that': 87}

索引到单词的映射,index_word:

{1: 'is', 2: 'you', 3: 'the', 4: 'but', 5: 'and', 6: 'with', 7: 'are', 8: 'a', 9: 'if', 10: 'love', 11: 'to', 12: 'journey', 13: 'in', 14: 'will', 15: 'them', 16: 'they', 17: 'memories', 18: 'wisdom', 19: 'about', 20: 'more', 21: 'often', 22: 'different', 23: 'time', 24: 'where', 25: 'life', 26: 'fall', 27: 'be', 28: 'forever', 29: 'dreams', 30: 'like', 31: 'stars', 32: 'may', 33: 'never', 34: 'touch', 35: 'follow', 36: 'lead', 37: 'your', 38: 'destiny', 39: "heart's", 40: 'treasures', 41: 'hold', 42: 'beauty', 43: 'of', 44: 'our', 45: 'past', 46: 'nature', 47: 'most', 48: 'beautiful', 49: 'artist', 50: 'its', 51: 'paintings', 52: 'endless', 53: 'always', 54: 'breathtaking', 55: 'true', 56: 'happiness', 57: 'not', 58: 'having', 59: 'everything', 60: 'being', 61: 'content', 62: 'what', 63: 'have', 64: 'comes', 65: 'age', 66: 'experience', 67: 'music', 68: 'has', 69: 'power', 70: 'transport', 71: 'us', 72: 'place', 73: 'blind', 74: 'sees', 75: 'than', 76: 'others', 77: 'heals', 78: 'all', 79: 'wounds', 80: 'only', 81: 'let', 82: 'it', 83: 'home', 84: 'heart', 85: 'for', 86: 'many', 87: 'that'}

每个单词出现的总频次,word_counts:

OrderedDict([('life', 1), ('is', 7), ('a', 3), ('journey', 2), ('and', 4), ('if', 3), ('you', 7), ('fall', 1), ('in', 2), ('love', 3), ('with', 4), ('the', 7), ('will', 2), ('be', 1), ('forever', 1), ('dreams', 1), ('are', 4), ('like', 1), ('stars', 1), ('may', 1), ('never', 1), ('touch', 1), ('them', 2), ('but', 5), ('follow', 1), ('they', 2), ('lead', 1), ('to', 3), ('your', 1), ('destiny', 1), ('memories', 2), ("heart's", 1), ('treasures', 1), ('hold', 1), ('wisdom', 2), ('beauty', 1), ('of', 1), ('our', 1), ('past', 1), ('nature', 1), ('most', 1), ('beautiful', 1), ('artist', 1), ('its', 1), ('paintings', 1), ('endless', 1), ('always', 1), ('breathtaking', 1), ('true', 1), ('happiness', 1), ('not', 1), ('about', 2), ('having', 1), ('everything', 1), ('being', 1), ('content', 1), ('what', 1), ('have', 1), ('comes', 1), ('age', 1), ('more', 2), ('often', 2), ('experience', 1), ('music', 1), ('has', 1), ('power', 1), ('transport', 1), ('us', 1), ('different', 2), ('place', 1), ('time', 2), ('blind', 1), ('sees', 1), ('than', 1), ('others', 1), ('heals', 1), ('all', 1), ('wounds', 1), ('only', 1), ('let', 1), ('it', 1), ('home', 1), ('where', 2), ('heart', 1), ('for', 1), ('many', 1), ('that', 1)])

出现单词的文档的数量,word_docs:

defaultdict(, {'a': 2, 'journey': 1, 'is': 5, 'if': 3, 'will': 2, 'and': 4, 'forever': 1, 'life': 1, 'love': 2, 'in': 1, 'fall': 1, 'be': 1, 'you': 4, 'the': 5, 'with': 3, 'dreams': 1, 'touch': 1, 'lead': 1, 'stars': 1, 'but': 5, 'your': 1, 'may': 1, 'to': 2, 'never': 1, 'like': 1, 'follow': 1, 'destiny': 1, 'are': 4, 'they': 2, 'them': 1, 'memories': 2, 'treasures': 1, 'of': 1, 'past': 1, 'wisdom': 2, 'hold': 1, 'beauty': 1, 'our': 1, "heart's": 1, 'paintings': 1, 'most': 1, 'breathtaking': 1, 'beautiful': 1, 'nature': 1, 'always': 1, 'endless': 1, 'artist': 1, 'its': 1, 'having': 1, 'not': 1, 'content': 1, 'everything': 1, 'about': 1, 'happiness': 1, 'have': 1, 'being': 1, 'what': 1, 'true': 1, 'comes': 1, 'age': 1, 'more': 2, 'often': 2, 'experience': 1, 'power': 1, 'place': 1, 'us': 1, 'has': 1, 'transport': 1, 'time': 2, 'music': 1, 'different': 1, 'blind': 1, 'others': 1, 'sees': 1, 'than': 1, 'it': 1, 'all': 1, 'only': 1, 'heals': 1, 'let': 1, 'wounds': 1, 'where': 1, 'heart': 1, 'for': 1, 'many': 1, 'that': 1, 'home': 1})

单词索引对应的出现单词的文档的数量,index_docs:

defaultdict(, {8: 2, 12: 1, 1: 5, 9: 3, 14: 2, 5: 4, 28: 1, 25: 1, 10: 2, 13: 1, 26: 1, 27: 1, 2: 4, 3: 5, 6: 3, 29: 1, 34: 1, 36: 1, 31: 1, 4: 5, 37: 1, 32: 1, 11: 2, 33: 1, 30: 1, 35: 1, 38: 1, 7: 4, 16: 2, 15: 1, 17: 2, 40: 1, 43: 1, 45: 1, 18: 2, 41: 1, 42: 1, 44: 1, 39: 1, 51: 1, 47: 1, 54: 1, 48: 1, 46: 1, 53: 1, 52: 1, 49: 1, 50: 1, 58: 1, 57: 1, 61: 1, 59: 1, 19: 1, 56: 1, 63: 1, 60: 1, 62: 1, 55: 1, 64: 1, 65: 1, 20: 2, 21: 2, 66: 1, 69: 1, 72: 1, 71: 1, 68: 1, 70: 1, 23: 2, 67: 1, 22: 1, 73: 1, 76: 1, 74: 1, 75: 1, 82: 1, 78: 1, 80: 1, 77: 1, 81: 1, 79: 1, 24: 1, 84: 1, 85: 1, 86: 1, 87: 1, 83: 1})

对词频进行排序并输出排序结果

sort_fre = sorted(tokenizer.word_counts.items(), key = lambda i:i[1], reverse = True)

print("对词频进行排序, sort_fre:\n", sort_fre)

运行结果显示如下:

对词频进行排序, sort_fre:

[('is', 7), ('you', 7), ('the', 7), ('but', 5), ('and', 4), ('with', 4), ('are', 4), ('a', 3), ('if', 3), ('love', 3), ('to', 3), ('journey', 2), ('in', 2), ('will', 2), ('them', 2), ('they', 2), ('memories', 2), ('wisdom', 2), ('about', 2), ('more', 2), ('often', 2), ('different', 2), ('time', 2), ('where', 2), ('life', 1), ('fall', 1), ('be', 1), ('forever', 1), ('dreams', 1), ('like', 1), ('stars', 1), ('may', 1), ('never', 1), ('touch', 1), ('follow', 1), ('lead', 1), ('your', 1), ('destiny', 1), ("heart's", 1), ('treasures', 1), ('hold', 1), ('beauty', 1), ('of', 1), ('our', 1), ('past', 1), ('nature', 1), ('most', 1), ('beautiful', 1), ('artist', 1), ('its', 1), ('paintings', 1), ('endless', 1), ('always', 1), ('breathtaking', 1), ('true', 1), ('happiness', 1), ('not', 1), ('having', 1), ('everything', 1), ('being', 1), ('content', 1), ('what', 1), ('have', 1), ('comes', 1), ('age', 1), ('experience', 1), ('music', 1), ('has', 1), ('power', 1), ('transport', 1), ('us', 1), ('place', 1), ('blind', 1), ('sees', 1), ('than', 1), ('others', 1), ('heals', 1), ('all', 1), ('wounds', 1), ('only', 1), ('let', 1), ('it', 1), ('home', 1), ('heart', 1), ('for', 1), ('many', 1), ('that', 1)]

将文本转化为sequence

print("将文档列表转换为向量, texts_to_sequences: \n", tokenizer.texts_to_sequences(texts))

print("将文档列表转换为矩阵表示, texts_to_matrix: \n", tokenizer.texts_to_matrix(texts))

 运行结果显示如下:

将文档列表转换为向量, texts_to_sequences:

[[25, 1, 8, 12, 5, 9, 2, 26, 13, 10, 6, 3, 12, 2, 14, 27, 13, 10, 28], [29, 7, 30, 31, 2, 32, 33, 34, 15, 4, 9, 2, 35, 15, 16, 14, 36, 2, 11, 37, 38], [17, 7, 3, 39, 40, 16, 41, 3, 18, 5, 42, 43, 44, 45], [46, 1, 3, 47, 48, 49, 50, 51, 7, 52, 5, 53, 54], [55, 56, 1, 57, 19, 58, 59, 4, 19, 60, 61, 6, 62, 2, 63], [18, 6, 4, 20, 21, 6], [3, 11, 11, 8, 22, 8, 22, 23], [10, 1, 4, 21, 20], [23, 4, 9, 2], [1, 24, 3, 1, 5, 1, 24, 3, 17, 7]]

将文档列表转换为矩阵表示, texts_to_matrix:

[[0. 1. 1. 1. 0. 1. 1. 0. 1. 1. 1. 0. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 0. 1. 0. 1. 0. 0. 1. 0. 1. 0. 1. 0. 0. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 0. 0. 1. 0. 1. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 1. 0. 1. 0. 1. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1.

1. 1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 1. 1. 0. 1. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

[0. 0. 0. 0. 1. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 1. 1. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 0. 0. 1. 0. 0. 0. 0. 1. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 1. 0. 0. 1. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 0. 1. 0. 1. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

[0. 1. 0. 1. 0. 1. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.

1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.

0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

 pad_sequences填充数据

tokens = tokenizer.texts_to_sequences(texts)

print("将文档列表转换为向量, texts_to_sequences: \n", tokens)

tokens_pad = sequence.pad_sequences(tokens, maxlen=32, padding='post', truncating='pre')

print("tokens_pad: \n", tokens_pad)

 运行结果显示如下:

将文档列表转换为向量, texts_to_sequences:

[[25, 1, 8, 12, 5, 9, 2, 26, 13, 10, 6, 3, 12, 2, 14, 27, 13, 10, 28],

[29, 7, 30, 31, 2, 32, 33, 34, 15, 4, 9, 2, 35, 15, 16, 14, 36, 2, 11, 37, 38],

[17, 7, 3, 39, 40, 16, 41, 3, 18, 5, 42, 43, 44, 45],

[46, 1, 3, 47, 48, 49, 50, 51, 7, 52, 5, 53, 54],

[55, 56, 1, 57, 19, 58, 59, 4, 19, 60, 61, 6, 62, 2, 63],

[18, 6, 4, 20, 21, 6], [3, 11, 11, 8, 22, 8, 22, 23],

[10, 1, 4, 21, 20], [23, 4, 9, 2], [1, 24, 3, 1, 5, 1, 24, 3, 17, 7]]

tokens_pad:

[[25 1 8 12 5 9 2 26 13 10 6 3 12 2 14 27 13 10 28 0 0 0 0 0

0 0 0 0 0 0 0 0]

[29 7 30 31 2 32 33 34 15 4 9 2 35 15 16 14 36 2 11 37 38 0 0 0

0 0 0 0 0 0 0 0]

[17 7 3 39 40 16 41 3 18 5 42 43 44 45 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[46 1 3 47 48 49 50 51 7 52 5 53 54 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[55 56 1 57 19 58 59 4 19 60 61 6 62 2 63 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[18 6 4 20 21 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[ 3 11 11 8 22 8 22 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[10 1 4 21 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[23 4 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[ 1 24 3 1 5 1 24 3 17 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]]

2.2 中文文本向量化

中文文本向量化,首先使用jieba分词,对文本进行分词处理,然后将词语在转化为数据序列。

import jieba

from keras.preprocessing.text import Tokenizer

from keras.preprocessing import sequence

def cut_text(text):

seg_list = jieba.cut(text)

return ' '.join(seg_list)

texts = ["生活就像一场旅行,如果你爱上了这场旅行,你将永远充满爱。",

"梦想就像天上的星星,你可能永远无法触及,但如果你追随它们,它们将引领你走向你的命运。",

"真正的幸福不在于拥有一切,而在于满足于你所拥有的。",

"记忆是心灵的宝藏,它们蕴含着我们过去的智慧和美丽。",

"大自然是最美丽的艺术家,它的画作无边无际,总是令人叹为观止。",

"智慧往往随着年龄的增长而增加,但更多时候是随着经验的积累而到来。",

"音乐有能力将我们带到一个不同的地方、一个不同的时间。",

"爱是盲目的,但往往比别人看得更清楚。",

"时间可以治愈一切伤痛,但前提是你必须让它过去。",

"家是心灵的归宿,对许多人来说,也是记忆的所在。"]

tokenizer = Tokenizer(num_words=64, filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n,。',)

tokenizer.fit_on_texts([cut_text(text) for text in texts])

print("处理的文档数量,document_count: ", tokenizer.document_count)

print("词语到索引的映射,word_index: \n", tokenizer.word_index)

print("索引到词语的映射,index_word: \n", tokenizer.index_word)

print("每个词语出现的总频次,word_counts: \n", tokenizer.word_counts)

print("出现词语的文档的数量,word_docs: \n", tokenizer.word_docs)

print("词语索引对应的出现词语的文档的数量,index_docs: \n", tokenizer.index_docs)

splits = [cut_text(text) for text in texts]

tokens = tokenizer.texts_to_sequences(splits)

tokens_pad = sequence.pad_sequences(tokens, maxlen=32, padding='post', truncating='pre')

print("splits:\n", splits)

print("tokens:\n", tokens)

print("tokens_pad:\n", tokens_pad)

运行结果显示如下:

处理的文档数量,document_count: 10

词语到索引的映射,word_index:

{'的': 1, '你': 2, '是': 3, '但': 4, '将': 5, '它们': 6, '而': 7, '就': 8, '像': 9, '旅行': 10, '如果': 11, '爱': 12, '永远': 13, '在于': 14, '拥有': 15, '一切': 16, '记忆': 17, '心灵': 18, '我们': 19, '过去': 20, '智慧': 21, '美丽': 22, '它': 23, '往往': 24, '随着': 25, '更': 26, '一个': 27, '不同': 28, '时间': 29, '生活': 30, '一场': 31, '上': 32, '了': 33, '这场': 34, '充满': 35, '梦想': 36, '天上': 37, '星星': 38, '可能': 39, '无法': 40, '触及': 41, '追随': 42, '引领': 43, '走向': 44, '命运': 45, '真正': 46, '幸福': 47, '不': 48, '满足': 49, '于': 50, '所': 51, '宝藏': 52, '蕴含着': 53, '和': 54, '大自然': 55, '最': 56, '艺术家': 57, '画作': 58, '无边无际': 59, '总是': 60, '令人': 61, '叹为观止': 62, '年龄': 63, '增长': 64, '增加': 65, '多': 66, '时候': 67, '经验': 68, '积累': 69, '到来': 70, '音乐': 71, '有': 72, '能力': 73, '带到': 74, '地方': 75, '、': 76, '爱是': 77, '盲目': 78, '比': 79, '别人': 80, '看得': 81, '清楚': 82, '可以': 83, '治愈': 84, '伤痛': 85, '前提': 86, '必须': 87, '让': 88, '家': 89, '归宿': 90, '对': 91, '许多': 92, '人': 93, '来说': 94, '也': 95, '所在': 96}

索引到词语的映射,index_word:

{1: '的', 2: '你', 3: '是', 4: '但', 5: '将', 6: '它们', 7: '而', 8: '就', 9: '像', 10: '旅行', 11: '如果', 12: '爱', 13: '永远', 14: '在于', 15: '拥有', 16: '一切', 17: '记忆', 18: '心灵', 19: '我们', 20: '过去', 21: '智慧', 22: '美丽', 23: '它', 24: '往往', 25: '随着', 26: '更', 27: '一个', 28: '不同', 29: '时间', 30: '生活', 31: '一场', 32: '上', 33: '了', 34: '这场', 35: '充满', 36: '梦想', 37: '天上', 38: '星星', 39: '可能', 40: '无法', 41: '触及', 42: '追随', 43: '引领', 44: '走向', 45: '命运', 46: '真正', 47: '幸福', 48: '不', 49: '满足', 50: '于', 51: '所', 52: '宝藏', 53: '蕴含着', 54: '和', 55: '大自然', 56: '最', 57: '艺术家', 58: '画作', 59: '无边无际', 60: '总是', 61: '令人', 62: '叹为观止', 63: '年龄', 64: '增长', 65: '增加', 66: '多', 67: '时候', 68: '经验', 69: '积累', 70: '到来', 71: '音乐', 72: '有', 73: '能力', 74: '带到', 75: '地方', 76: '、', 77: '爱是', 78: '盲目', 79: '比', 80: '别人', 81: '看得', 82: '清楚', 83: '可以', 84: '治愈', 85: '伤痛', 86: '前提', 87: '必须', 88: '让', 89: '家', 90: '归宿', 91: '对', 92: '许多', 93: '人', 94: '来说', 95: '也', 96: '所在'}

每个词语出现的总频次,word_counts:

OrderedDict([('生活', 1), ('就', 2), ('像', 2), ('一场', 1), ('旅行', 2), ('如果', 2), ('你', 8), ('爱', 2), ('上', 1), ('了', 1), ('这场', 1), ('将', 3), ('永远', 2), ('充满', 1), ('梦想', 1), ('天上', 1), ('的', 15), ('星星', 1), ('可能', 1), ('无法', 1), ('触及', 1), ('但', 4), ('追随', 1), ('它们', 3), ('引领', 1), ('走向', 1), ('命运', 1), ('真正', 1), ('幸福', 1), ('不', 1), ('在于', 2), ('拥有', 2), ('一切', 2), ('而', 3), ('满足', 1), ('于', 1), ('所', 1), ('记忆', 2), ('是', 6), ('心灵', 2), ('宝藏', 1), ('蕴含着', 1), ('我们', 2), ('过去', 2), ('智慧', 2), ('和', 1), ('美丽', 2), ('大自然', 1), ('最', 1), ('艺术家', 1), ('它', 2), ('画作', 1), ('无边无际', 1), ('总是', 1), ('令人', 1), ('叹为观止', 1), ('往往', 2), ('随着', 2), ('年龄', 1), ('增长', 1), ('增加', 1), ('更', 2), ('多', 1), ('时候', 1), ('经验', 1), ('积累', 1), ('到来', 1), ('音乐', 1), ('有', 1), ('能力', 1), ('带到', 1), ('一个', 2), ('不同', 2), ('地方', 1), ('、', 1), ('时间', 2), ('爱是', 1), ('盲目', 1), ('比', 1), ('别人', 1), ('看得', 1), ('清楚', 1), ('可以', 1), ('治愈', 1), ('伤痛', 1), ('前提', 1), ('必须', 1), ('让', 1), ('家', 1), ('归宿', 1), ('对', 1), ('许多', 1), ('人', 1), ('来说', 1), ('也', 1), ('所在', 1)])

出现词语的文档的数量,word_docs:

defaultdict(, {'这场': 1, '旅行': 1, '一场': 1, '将': 3, '爱': 1, '充满': 1, '了': 1, '像': 2, '如果': 2, '生活': 1, '永远': 2, '上': 1, '你': 4, '就': 2, '梦想': 1, '但': 4, '天上': 1, '它们': 2, '追随': 1, '的': 8, '可能': 1, '无法': 1, '引领': 1, '走向': 1, '星星': 1, '命运': 1, '触及': 1, '一切': 2, '而': 2, '真正': 1, '拥有': 1, '在于': 1, '幸福': 1, '于': 1, '不': 1, '满足': 1, '所': 1, '记忆': 2, '和': 1, '是': 5, '智慧': 2, '我们': 2, '美丽': 2, '蕴含着': 1, '心灵': 2, '过去': 2, '宝藏': 1, '它': 2, '无边无际': 1, '叹为观止': 1, '令人': 1, '最': 1, '总是': 1, '大自然': 1, '艺术家': 1, '画作': 1, '经验': 1, '往往': 2, '随着': 1, '时候': 1, '更': 2, '增加': 1, '年龄': 1, '多': 1, '积累': 1, '增长': 1, '到来': 1, '、': 1, '带到': 1, '一个': 1, '地方': 1, '音乐': 1, '有': 1, '不同': 1, '能力': 1, '时间': 2, '看得': 1, '比': 1, '盲目': 1, '别人': 1, '清楚': 1, '爱是': 1, '可以': 1, '前提': 1, '治愈': 1, '伤痛': 1, '必须': 1, '让': 1, '对': 1, '也': 1, '许多': 1, '归宿': 1, '来说': 1, '所在': 1, '家': 1, '人': 1})

词语索引对应的出现词语的文档的数量,index_docs:

defaultdict(, {34: 1, 10: 1, 31: 1, 5: 3, 12: 1, 35: 1, 33: 1, 9: 2, 11: 2, 30: 1, 13: 2, 32: 1, 2: 4, 8: 2, 36: 1, 4: 4, 37: 1, 6: 2, 42: 1, 1: 8, 39: 1, 40: 1, 43: 1, 44: 1, 38: 1, 45: 1, 41: 1, 16: 2, 7: 2, 46: 1, 15: 1, 14: 1, 47: 1, 50: 1, 48: 1, 49: 1, 51: 1, 17: 2, 54: 1, 3: 5, 21: 2, 19: 2, 22: 2, 53: 1, 18: 2, 20: 2, 52: 1, 23: 2, 59: 1, 62: 1, 61: 1, 56: 1, 60: 1, 55: 1, 57: 1, 58: 1, 68: 1, 24: 2, 25: 1, 67: 1, 26: 2, 65: 1, 63: 1, 66: 1, 69: 1, 64: 1, 70: 1, 76: 1, 74: 1, 27: 1, 75: 1, 71: 1, 72: 1, 28: 1, 73: 1, 29: 2, 81: 1, 79: 1, 78: 1, 80: 1, 82: 1, 77: 1, 83: 1, 86: 1, 84: 1, 85: 1, 87: 1, 88: 1, 91: 1, 95: 1, 92: 1, 90: 1, 94: 1, 96: 1, 89: 1, 93: 1})

splits:

['生活 就 像 一场 旅行 , 如果 你 爱 上 了 这场 旅行 , 你 将 永远 充满 爱 。', '梦想 就 像 天上 的 星星 , 你 可能 永远 无法 触及 , 但 如果 你 追随 它们 , 它们 将 引领 你 走向 你 的 命运 。', '真正 的 幸福 不 在于 拥有 一切 , 而 在于 满足 于 你 所 拥有 的 。', '记忆 是 心灵 的 宝藏 , 它们 蕴含着 我们 过去 的 智慧 和 美丽 。', '大自然 是 最 美丽 的 艺术家 , 它 的 画作 无边无际 , 总是 令人 叹为观止 。', '智慧 往往 随着 年龄 的 增长 而 增加 , 但 更 多 时候 是 随着 经验 的 积累 而 到来 。', '音乐 有 能力 将 我们 带到 一个 不同 的 地方 、 一个 不同 的 时间 。', '爱是 盲目 的 , 但 往往 比 别人 看得 更 清楚 。', '时间 可以 治愈 一切 伤痛 , 但 前提 是 你 必须 让 它 过去 。', '家 是 心灵 的 归宿 , 对 许多 人 来说 , 也 是 记忆 的 所在 。']

tokens:

[[30, 8, 9, 31, 10, 11, 2, 12, 32, 33, 34, 10, 2, 5, 13, 35, 12], [36, 8, 9, 37, 1, 38, 2, 39, 13, 40, 41, 4, 11, 2, 42, 6, 6, 5, 43, 2, 44, 2, 1, 45], [46, 1, 47, 48, 14, 15, 16, 7, 14, 49, 50, 2, 51, 15, 1], [17, 3, 18, 1, 52, 6, 53, 19, 20, 1, 21, 54, 22], [55, 3, 56, 22, 1, 57, 23, 1, 58, 59, 60, 61, 62], [21, 24, 25, 63, 1, 7, 4, 26, 3, 25, 1, 7], [5, 19, 27, 28, 1, 27, 28, 1, 29], [1, 4, 24, 26], [29, 16, 4, 3, 2, 23, 20], [3, 18, 1, 3, 17, 1]]

tokens_pad:

[[30 8 9 31 10 11 2 12 32 33 34 10 2 5 13 35 12 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[36 8 9 37 1 38 2 39 13 40 41 4 11 2 42 6 6 5 43 2 44 2 1 45

0 0 0 0 0 0 0 0]

[46 1 47 48 14 15 16 7 14 49 50 2 51 15 1 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[17 3 18 1 52 6 53 19 20 1 21 54 22 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[55 3 56 22 1 57 23 1 58 59 60 61 62 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[21 24 25 63 1 7 4 26 3 25 1 7 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[ 5 19 27 28 1 27 28 1 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[ 1 4 24 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[29 16 4 3 2 23 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]

[ 3 18 1 3 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0]]

3 总结

文本向量化是自然语言处理必不可少的操作,本文通过实际例子,分别介绍了使用Tokenizer对中文、英文文本预处理方法,处理后输出的向量化数据,作为深度神经网络模型的输入进行训练和推理。

优惠劵

智慧医疗探索者

关注

关注

4

点赞

13

收藏

觉得还不错?

一键收藏

打赏

知道了

0

评论

深度学习文本预处理利器:Tokenizer详解

Tokenizer是一个用于向量化文本,将文本转换为序列的类。计算机在处理语言文字时,是无法理解文字含义的,通常会把一个词(中文单个字或者词)转化为一个正整数,将一个文本就变成了一个序列,然后再对序列进行向量化,向量化后的数据送入模型处理。

复制链接

扫一扫

专栏目录

tokenizer:一个简单的中文分词算法,可用于网游脏词过滤、搜索引擎文档解析、自然语言处理等需要中文分词的场合

04-27

洋文单词以空格天然分词,相比较而言因为一句中文是由连贯的字组成的,分词就麻烦一些。最困难的情况是对二义性句子的分割问题。比如“搜索引擎”这四个字,可以拆成“搜索”和“引擎”,但“索引”也是一个中文词汇。在脏词过滤的逻辑中最简单的做法是不使用分词,用所有脏词和一句话匹配,如果任意一个脏词是这句话的子串就认定为脏句,这种做法虽然避免了漏网之鱼,但是会因过于严格而让正常的句子变成脏句,分词可以改善这种问题。本项目提供一种简单的中文分词算法,并用近乎伪代码的 Python 编写。期待有人写出更好的版本:比如对效率的优化;在分词过程中引入词性的判定,进而过滤掉在词法上有效但语法上无效的节点等。

目前算法支持二义性划分,如词典里有“喜”,“欢”,“喜欢”三个词,则“喜欢”会拆成[喜欢]和[喜, 欢]两种划分;还支持新词划分,对于未知的词汇,会分割成单字。详见代码本身示例。

超详细Tokenizer——文本训练数据预处理

halo的博客

10-31

570

Tokenizer是Keras库中的一个文本处理工具,它用于将文本分词并构建词汇表,同时将文本映射到整数序列。这对于自然语言处理任务非常有用,例如文本分类、情感分析、机器翻译等。

参与评论

您还未登录,请先

登录

后发表或查看评论

python函数——Keras分词器Tokenizer

Congying-Wang的博客

12-11

2万+

文章目录0. 前言

python函数 系列目录:python函数——目录

0. 前言

通俗易懂讲解大模型:Tokenizer

2301_78285120的博客

09-03

1961

我们不是合并频繁的字节对,而是合并频繁的字符或字符序列。这里通过将前缀添加到单词内的每个字符来拆分的,单词的首字符不添加前缀。找到词表中能够匹配到的最长的子词,然后对单词进行拆分。现在的问题是,给定一个训练语料库 D ,如何获得词表 V 以及每个子词出现的概率 p(x)。的物理意义为:通过将 t1,t2 合并为 t1,2 之后,语料库的对数似然的增量最大化。然而这又因语言而异,例如,在中文中每个字符比拉丁语言中的每个字符包含更多的信息。注意,在更大的语料库中这样的相等的情况很少见。

怎么理解token,tokenize,tokenizer.

热门推荐

feng98ren的专栏

06-29

3万+

1、一种解释token:令牌tokenize:令牌化tokenizer:令牌解析器2、另一种翻译是:token可以翻译为“标记”,tokenize可以翻译为“标记解析”或“解析标记”,tokenizer可以翻译为“标记解析器”。在编写词法分析器(Lexer)或语法分析器(Parser)的时候,除了Lexer和Parser这两个词会经常使用外,tokenize和tokenizer也会经常出现,基本上...

tokenizer简介

芳樽里的歌的博客

12-08

2万+

本文介绍了现代NLP中有关tokenizer的内容

Tokenizer总结

choose_c的博客

08-02

9764

Introduciton

transformer类型的预训练模型层出不穷,其中的tokenizer方法作为一个非常重要的模块也出现了一些方法。本文对tokenizer方法做一些总结。参考来自hunggingface。

tokenizer在中文中叫做分词器,就是将句子分成一个个小的词块(token),生成一个词表,并通过模型学习到更好的表示。其中词表的大小和token的长短是很关键的因素,两者需要进行权衡,token太长,则它的表示也能更容易学习到,相应的词表也会变小;to...

1.5.3 什么是Tokenizer-分词

weixin_30532837的博客

02-27

607

什么是Tokenizer-分词

  分词器的工作就是分解文本流成词(tokens).在这个文本中,每一个token都是这些字符的一个子序列.一个分析器(analyzer)必须知道它所配置的字段,但是tokenizer不需要,分词器(tokenizer)从一个字符流(reader)读取数据,生成一个Token对象(TokenStream)的序列.

  输入流中的一些字符可能会被丢弃,如空格和一...

NLP——Tokenizer

行者无疆的博客

11-20

7502

1.什么是Tokenizer

  使用文本的第一步就是将其拆分为单词。单词称为标记(token),将文本拆分为标记的过程称为标记化(tokenization),而标记化用到的模型或工具称为tokenizer。Keras提供了Tokenizer类,用于为深度学习文本文档的预处理。

2.创建Tokenizer实例

from keras.preprocessing.text import Tokenizer

tok = Tokenizer()

3.学习文本字典

##假设文本数据为:

docs = ['good

tokenizers Tokenizer类

weixin_49346755的博客

06-03

4111

函数说明

Tokenizer函数构造一个分词器对象。分词方式主要有word-level、subword-level、char-level三种,其中,subword-level分词方式又有三种不同实现的方法:BPE、Unigram、WordPiece。参数model表示分词器使用的分词方式,接受一个Model对象,这里主要实现了word-level的分词方式以及subword-level的分词方式。Tokenizer类主要的方法有:1、from_file(path):从指定文件加载Tokenizer对象。2、

llt-tokenizer:标记化拉丁文(和希腊文)文本

05-30

LLT::Tokenizer

用于标记拉丁文本的灵活服务。

安装

将此行添加到应用程序的 Gemfile 中:

gem 'llt-tokenizer'

然后执行:

$ bundle

或者自己安装:

$ gem install llt-tokenizer

用法

LLT的Tokenizer使用主干字典。 有关如何设置,请参阅。

require 'llt/tokenizer'

t = LLT :: Tokenizer . new

tokens = t . tokenize ( 'Arma virumque cano.' )

tokens . map ( & :to_s )

# => ["Arma", "-que", "virum", "cano", "."]

Tokenizer 在创建或调用 #tokenize 时有几个选项:

# shifting d

bert情感分类中用tokenizer实现文本预处理

01-03

在pytoch中,实现利用预训练BertTokenizer对影评数据集IMDB进行预处理,得到Bert模型所需输入样本特征。利用torch.utils.data将预处理结果打包为数据集,并利用pickle将数据集序列化保存至本地文件中。

DeepLearningSmells:使用深度学习闻到气味

05-08

使用深度学习检测气味 概述 下图提供了该实验的概述。 我们从GitHub下载1,072个C#和100个Java存储库。 我们分别使用Designite和DesigniteJava来分析C#和Java代码。 我们使用CodeSplit将每个方法和类定义提取到C#...

tokenizer:源代码标记器

05-06

$ tokenizer = new Nette \ Tokenizer \ Tokenizer ([ T_DNUMBER => '\d+' , T_WHITESPACE => '\s+' , T_STRING => '\w+' , ]); 提示:如果您想知道T_常量来自何处,它们是用于解析代码的。 它们涵盖了我们通常...

tokenizer:使用Go语言编写的NLP令牌生成器

05-29

tokenizer是一个雄心勃勃的目标(与和一起)的一部分,为Gophers 带来更多AI/深度学习工具,以便他们能够坚持使用他们喜欢的语言并在生产中构建更快的软件。 特征 tokenizer内置于子包中的模块中。 归一化器 预...

AI技术在室内定位的应用

jgtx8888的博客

03-01

1201

通过在室内布置信标节点,用户携带的移动设备可以接收到信标信号并计算出与信标的距离,进而确定自身位置。同时,一些新型的机器学习算法还可以处理复杂环境下的干扰问题,提高定位系统的鲁棒性。其中,AI技术在室内定位领域的应用越来越广泛,为我们的生活和工作带来了诸多便利。(2)提高鲁棒性:随着物联网技术的不断发展,室内定位系统将面临越来越多的干扰和挑战。随着AI技术的不断发展和普及,其在室内定位领域的应用将越来越广泛。(2)复杂环境下的定位精度:在复杂环境下,AI技术可能难以保证高精度的定位效果。

什么是生成式人工智能?

人邮异步社区

02-28

1721

就生成式人工智能在图像生成领域的应用来说,最早且最著名的示例之一是由 Ian Goodfellow 等人在 2014 年发表的文章“Generative Adversarial Networks”中介绍的生成对 抗网络(Generative Adversarial Network,GAN)架构,这一架构能生成难以与真实图像 区分的逼真图像。这一技术背后包含我们刚 提到的许多其他领域的模型—用于提示的语言理解模型、用于图像生成的图像和 运动生成模型,以及由人工智能作曲助手制作的背景音乐。

《Decoupling Representation and Classifier for Long-Tailed Recognition》阅读笔记

AncilunKiang的博客

02-28

1596

视觉世界的长尾分布对基于深度学习的分类模型如何处理类不平衡问题提出了巨大的挑战。现有的解决方案通常涉及类平衡策略(class-balancing strategies)例如通过损失重加权、数据重采样,或者从头部类别到尾部类别的迁移学习,但它们大多数遵循共同学习表示和分类器的方案。在这项工作中,我们**将学习过程解耦(decouple)为表示学习和分类(representation learning and classification),并系统地探索不同的平衡策略如何影响长尾识别。

pytorch基础2-数据集与归一化

最新发布

qq_33345365的博客

03-02

1468

Dataset逐个样本检索数据集的特征和标签。在训练模型时,通常希望以“minibatch”的形式传递样本,在每个周期重混洗(reshuffle)数据以减少模型过拟合,并使用Python的多进程加速数据检索。在机器学习中,需要指定数据集中的特征和标签。**特征(Feature)**是输入,**标签(label)**是输出。我们训练特征,然后训练模型以预测标签。特征是图像像素中的模式。标签是10个类别类型:T恤,凉鞋,连衣裙等。DataLoader是一个可迭代对象,用简单的API抽象了这种复杂性。

tokenizer c++

08-20

tokenizer c 是一个用于分词的字符串处理库。它接受三个模板类型参数:TokenizerFunc、Iterator和Type。TokenizerFunc是分词函数的类型,默认为char_delimiters_separator;Iterator是待分词字符串的迭代器类型,默认为std::string::const_iterator;Type是分词结果的类型,默认为std::string。这个库可以方便地将一个字符串分解成若干个单词,比如像Java里的StringTokenizer。要使用tokenizer库,需要包含头文件#include 123

#### 引用[.reference_title]

- *1* *3* [C++ Boost库:分词处理库 tokenizer](https://blog.csdn.net/u014779536/article/details/116398471)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"]

- *2* [C++ Tokenizer](https://download.csdn.net/download/yaochenlan/3323707)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"]

[ .reference_list ]

“相关推荐”对你有帮助么?

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

智慧医疗探索者

CSDN认证博客专家

CSDN认证企业博客

码龄18年

华为技术有限公司

278

原创

5065

周排名

3601

总排名

51万+

访问

等级

7255

积分

3933

粉丝

3802

获赞

236

评论

4178

收藏

私信

关注

热门文章

OpenAI的人工智能语音识别模型Whisper详解及使用

14375

机器学习之支持向量机(SVM)

9866

openai多模态大模型:clip详解及实战

7928

AIGC:文生图模型Stable Diffusion

7585

centos 7下mysql5.7 主从数据库同步配置

7159

分类专栏

AI数字人技术

22篇

AI运行环境

46篇

深度学习模型

18篇

人工智能初探

48篇

深度学习之pytorch

23篇

人工智能项目实战

5篇

AIGC

18篇

计算机视觉

25篇

经典机器学习算法

12篇

音视频处理

24篇

物联网技术

5篇

最新评论

AIGC:语音克隆模型Bert-VITS2-2.3部署与实战

CSDN-Ada助手:

恭喜你这篇博客进入【CSDN每天值得看】榜单,全部的排名请看 https://bbs.csdn.net/topics/618168326。

机器学习之随机森林(Random forest)

kricu:

感谢您的解答

为AI而生的数据库:Milvus详解及实战

deep_shf:

期待多出一些实际场景的例子做讲解 比如embedding过程 r

机器学习之随机森林(Random forest)

kricu:

老师您好,我想请问一下就是这个位置的双月图是作为训练集存在的吗,下面那个随机森林的结果是通过这个训练集得到的模型去处理测试集的结果吗

基于OpenAI的Whisper构建的高效语音识别模型:faster-whisper

yuanyuan_666:

您好 问题已经解决了,是faster_whisper版本的问题 我降低为 0.10.1就可以用了 谢谢

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

AIGC:语音克隆模型Bert-VITS2-2.3部署与实战

使用ffmpeg实现视频片段截取并保持清晰度

MiniCPM:揭示端侧大语言模型的无限潜力

2024

03月

1篇

02月

5篇

01月

44篇

2023年184篇

2019年6篇

2018年7篇

2017年24篇

2016年7篇

目录

目录

分类专栏

AI数字人技术

22篇

AI运行环境

46篇

深度学习模型

18篇

人工智能初探

48篇

深度学习之pytorch

23篇

人工智能项目实战

5篇

AIGC

18篇

计算机视觉

25篇

经典机器学习算法

12篇

音视频处理

24篇

物联网技术

5篇

目录

评论

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

打赏作者

智慧医疗探索者

你的鼓励将是我创作的最大动力

¥1

¥2

¥4

¥6

¥10

¥20

扫码支付:¥1

获取中

扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

3-3 Transformers Tokenizer API 的使用 - 知乎

3-3 Transformers Tokenizer API 的使用 - 知乎首发于transformers 教程切换模式写文章登录/注册3-3 Transformers Tokenizer API 的使用sergio一个脱离了低级趣味的人Transformers Tokenizer 的使用Tokenizer 分词器,在NLP任务中起到很重要的任务,其主要的任务是将文本输入转化为模型可以接受的输入,因为模型只能输入数字,所以 tokenizer 会将文本输入转化为数值型的输入,下面将具体讲解 tokenization pipeline.Tokenizer 类别例如我们的输入为: Let's do tokenization! 不同的tokenization 策略可以有不同的结果,常用的策略包含如下: - word base:按照词进行分词 - character base:按照单词进行分词 - subword tokenization:按照subword进行分词 等Word-based我们如果需要根据 word base 进行 tokenization 的话,有两种方式,一种是根据 whitespace 进行分割,一种是根据标点符号进行分割,然后再做数字的映射。每个 word 都被赋予一个ID,这个 ID 的范围是从0到 vocabulary size,这种方式有一种问题,就是很容易出现例如,dog 和 dogs,虽然是相近的词,但是被分配了完全不同的无关的id。对于不在vocabulary 库里面的词,我们会分配 [UNK],代表未知词。Character baseChar base的 tokenization 方式,就是用char,而不是word。 这种方式的好处在于:vocabulary size 很小比较少机会出现 out of vocabulary 的问题。但是这种方式的硬伤也很重,因为这种方式会导致文本无意义,每个character 都是无意义的,只有组成了单词才是有意义的,对于character 进行embedding无法满足文本的语义要求。当然这种问题主要出现在英文中或者拉丁语系中,中文的话,每个字的意思就丰富多了,所以也常用这种方式。此外,对于英文,一个单词可以分为N个字母,这就导致了每个模型都需要处理多个token,导致模型速度慢,可以输入的文本长度变小。Subword tokenization为了平衡上述两者的问题,聪明的科学家想出了使用 subword tokenization 的方式进行分词。subword tokenization 依赖的原则是:常见词不应该分成subword,不常见的词应该分为更有意义的subword例如:tokenization 代表不常见的词,可以被分为:token和ization,annoyingly 被分为 annoying 和 ly,这对于英文来说是很有意义的,因为英文本来就是由于词根和词缀组成的。下面可以看看 “Let’s do tokenization!“ 在经过subword tokenization 后的情况: 其他的方式还有很多常见的方式例如: Byte-level BPE, as used in GPT-2 WordPiece, as used in BERT SentencePiece or Unigram, as used in several multilingual modelsload 和 savetokenizer 的加载和保存和 models 的方式一致,都是使用方法:from_pretrained, save_pretrained. 这个方法会加载和保存tokenizer使用的模型结构(例如sentence piece就有自己的模型结构),以及字典。下面是一个使用的example:from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained("bert-base-cased", use_fast=True) # 可以使用use fast加速和 AutoModel 类似,也有 AutoTokenizer这种class,它可以根据传入的 checkpoint,找到适当的 tokenizer class,并且加载 checkpoint:from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")在加载完模型之后,我们可以直接使用tokenzer对文本进行tokenizer pipeline:tokenizer("Using a Transformer network is simple")

{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],

'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],

'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}并且可以进行保存:tokenizer.save_pretrained("directory_on_my_computer")Encoding将文本转化为数字的过程成为 encoding,encoding 主要包含了两个步骤: - 1. tokenization: 对文本进行分词 - 2. convert_tokens_to_ids:将分词后的token 映射为数字TokenizationTokenization 的过程是通过 tokenize 的方法实现的:from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

sequence = "Using a Transformer network is simple"

tokens = tokenizer.tokenize(sequence)

print(tokens)

>>>

['Using', 'a', 'transform', '##er', 'network', 'is', 'simple']这边使用的是wordpiece 的分词器,它将 transformer 分为了 transform 和 ##erconvert_tokens_to_ids分完词之后,需要将每个token映射为 id, 这边是使用 convert_tokens_to_ids 的方法进行:ids = tokenizer.convert_tokens_to_ids(tokens)

print(ids)

>>>

[7993, 170, 11303, 1200, 2443, 1110, 3014]DecodingDecoding 的作用是将输出的 ids 转化为文本,这可以使用 tokenizer 的 decode 方法:decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])

print(decoded_string)

>>>

'Using a Transformer network is simple'Handling multiple sequences我们在使用 tokenizer 的时候,可能会出现一些问题: - 对于batch的输入,如果我们输入了多个长度的句子,我们将如何处理? - 只输入 tokens 对应id 是不是就足够了? - 如果文本长度过长,怎么处理?模型只支持batch 的输入我们可以看下面的例子:import torch

from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"

tokenizer = AutoTokenizer.from_pretrained(checkpoint)

model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)

ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = torch.tensor(ids) # model 只支持 tensor

# This line will fail.

model(input_ids)可以看到,爆了如下的错误:IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)这是因为,模型需要传入的输入是 [batch_size, sequence_length] 的 tensor。于是我们需要,对上面代码进行修改:import torch

from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"

tokenizer = AutoTokenizer.from_pretrained(checkpoint)

model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize([sequence]) # 变成batch size = 1

ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = torch.tensor([ids])

print("Input IDs:", input_ids)

output = model(input_ids)

print("Logits:", output.logits)

>>>

Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]]

Logits: [[-2.7276, 2.8789]]batch 内的 ids 需要 padding我们都知道 model 只接受 tensor 作为输入,不能接受 list of lists,而tensor 必须保证每个vector 都有相同的长度: 所以下面的数组是不能转华为 tensor 的。batched_ids = [

[200, 200, 200],

[200, 200]

]为了解决这个问题,我们往往需要对输入进行 padding,使得每个输入的 vector 都具有相同的长度,如果我们有2个句子,其中一个句子只有3个字,一个句子2个字,我们为了导出为tensor,可以将其他的句子都进行padding,然后得到两个3个字的句子。padding_id = 100

batched_ids = [

[200, 200, 200],

[200, 200, padding_id]

]在 tokenizer 中,我们可以通过 tokenizer.pad_token_id 确认 padding id。model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]

sequence2_ids = [[200, 200]]

batched_ids = [[200, 200, 200], [200, 200, tokenizer.pad_token_id]]

print(model(torch.tensor(sequence1_ids)).logits)

print(model(torch.tensor(sequence2_ids)).logits)

print(model(torch.tensor(batched_ids)).logits)

>>>

tensor([[ 1.5694, -1.3895]], grad_fn=)

tensor([[ 0.5803, -0.4125]], grad_fn=)

tensor([[ 1.5694, -1.3895],

[ 1.3373, -1.2163]], grad_fn=)上面我们注意到,同样输入 [200, 200] 和 [200, 200, tokenizer.pad_token_id], 我们在经过模型的时候,得到的结果是完全不同的。 这是因为我们的模型在做句子表征的时候,也将padding token id 进行了考虑,导致每个词对应的输出不同,为了告诉模型我们的输入中,某些词是不需要考虑的,我们需要传入 attention mask。Attention masksAttention masks 和输入的 input ids 具有完全一样的shape,其中1 代表了这个id需要attention,0代表这个id不需要attention。batched_ids = [

[200, 200, 200],

[200, 200, tokenizer.pad_token_id]

]

attention_mask = [

[1, 1, 1],

[1, 1, 0]

]

outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask))

print(outputs.logits)

>>>

tensor([[ 1.5694, -1.3895],

[ 0.5803, -0.4125]], grad_fn=)Longer sequences 长句子每个预训练的语言模型在模型定义的时候,都限定了最长的输入长度,例如 BERT-base 为512, BERT-large 为1024 个tokens。 - 所以如果文本 tokenized 后的长度超过模型可以处理的长度,我们需要进行截断(truncate)。 - 或者选用可以处理更长文本的模型,例如 Longformer,LED,或者 Big Bird我们可以指定,max_sequence_length 参数对文本进行截断:sequence = sequence[:max_sequence_length]Tokenizer 的封装我们了解了 tokenize,conver to ids, padding, attention mask,以及truncate 后,我们发现,对于文本的输入,我们需要进行一些列的 pipeline 才能得到模型的输入。这时候我们是否可以有封装的方法可以直接使用,而不用一次又一次地调用完整的步骤?其实可以的,我们可以直接使用 tokenizer(text(s)) 就可以直接获得所有的模型的输入。而且它支持输入单句子或者句子list。from transformers import AutoTokenizer

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"

tokenizer = AutoTokenizer.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

model_inputs = tokenizer(sequence)或者直接输入句子串:sequences = [

"I've been waiting for a HuggingFace course my whole life.",

"So have I!"

]

model_inputs = tokenizer(sequences)对于文本长度的限定,我们可以通过指定 padding,以及 max_length。 - padding = 'longest': padding 到batch 中句子最长的长度 - padding = 'max_length': padding 到模型最大的输入长度,如果指定了 max_length, 则padding 到 max_length# Will pad the sequences up to the maximum sequence length

model_inputs = tokenizer(sequences, padding="longest")

# Will pad the sequences up to the model max length

# (512 for BERT or DistilBERT)

model_inputs = tokenizer(sequences, padding="max_length")

# Will pad the sequences up to the specified max length

model_inputs = tokenizer(sequences, padding="max_length", max_length=8)同样,如果文本太长,可以设定 truncation=Truesequences = [

"I've been waiting for a HuggingFace course my whole life.",

"So have I!"

]

# Will truncate the sequences that are longer than the model max length

# (512 for BERT or DistilBERT)

model_inputs = tokenizer(sequences, truncation=True)

# Will truncate the sequences that are longer than the specified max length

model_inputs = tokenizer(sequences, max_length=8, truncation=True)tokenizer 默认返回的结果是np,但是模型的输入必须是tensor: - "np" returns NumPy arrays: - "pt" returns PyTorch tensors - "tf" returns TensorFlow tensors所以需要传入参数 return_tensorssequences = [

"I've been waiting for a HuggingFace course my whole life.",

"So have I!"

]

# Returns PyTorch tensors

model_inputs = tokenizer(sequences, padding=True, return_tensors="pt")

# Returns TensorFlow tensors

model_inputs = tokenizer(sequences, padding=True, return_tensors="tf")

# Returns NumPy arrays

model_inputs = tokenizer(sequences, padding=True, return_tensors="np")特殊的字符如果我们查看 tokenizer 的返回结果:model_inputs["input_ids"] 我们可以查看到,文本的输出和之前的输出不太一样。sequence = "I've been waiting for a HuggingFace course my whole life."

model_inputs = tokenizer(sequence)

print(model_inputs["input_ids"])

tokens = tokenizer.tokenize(sequence)

ids = tokenizer.convert_tokens_to_ids(tokens)

print(ids)

>>>

[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102]

[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]我们对输出ids 进行decode ,可以得到如下的结果:print(tokenizer.decode(model_inputs["input_ids"]))

print(tokenizer.decode(ids))

>>>

"[CLS] i've been waiting for a huggingface course my whole life. [SEP]"

"i've been waiting for a huggingface course my whole life."我们可以看到模型的输入增加了特殊的字符 [CLS] 和 [SEP], 这是因为,bert 模型训练的时候,也增加了这些特殊字符,为了保证训练和预测一致,其tokenizer也对输入进行了改造。不同的model在训练的时候,新增特殊的字符也不一样,例如 roberta 加的 字符为 和 。所以我们尽量可以直接使用 tokenizer 对模型进行embedding 的构造,可以减少很多数据的处理流程。除此之外,模型还需要很多其他输入,例如BERT 需要输入 token type ids,代表文本的类型,具体每个模型都有点差异。Wrapping up: From tokenizer to model所以我们可以发现,tokenizer 帮我们处理了所有, 对文本进行特殊字符的添加 padding truncation encoding (tokenize,convert_tokens_to_ids) 转化为tensor 输出 model 需要的attention mask (optional) 以及输出 token type idsimport torch

from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"

tokenizer = AutoTokenizer.from_pretrained(checkpoint)

model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequences = [

"I've been waiting for a HuggingFace course my whole life.",

"So have I!"

]

tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")

output = model(**tokens)编辑于 2022-04-25 23:24BERT NLP自然语言处理Transformers(书籍)​赞同 149​​14 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录transformers 教程NLP 库 transformers

Huggingface详细教程之Tokenizer库 - 知乎

Huggingface详细教程之Tokenizer库 - 知乎首发于NLP成长之路切换模式写文章登录/注册Huggingface详细教程之Tokenizer库基本粒子10年+汽车研发及数字化经验,关注机器学习,知识图谱技术等前段时间工作非常的忙,勤劳的我又开始更新啦。这里是huggingface系列入门教程的第二篇,系统为大家介绍tokenizer库。教程来自于huggingface官方教程,我做了一定的顺序调整和解释,以便于新手理解。tokenizer库其实就是接收原始数据集中的语料,然后按照一定的规则分开。分词的目的只有一个,那就是为后来的embeding做准备。对于中文来说,这些大规模预训练模型基本都是在字符级别,也就是到单个字,没有到词。本篇文章也就以英文示例了,英文一般是到subword级别。我们先看看bert是怎么做的:先处理文本,变成列表,丢到模型里面。subword分词出来,再加上各种标签。这种输出就可以用与做embeding了。常用的subword分词算法有如下图三种,其中BERT使用的是WordPiece,而GPT-2使用的则是BPE算法的变种,能够更好的解决混编语言的问题。这三种算法的区别可自行查阅下表。如果你想知道huggingface支持哪些模型,以及如何调用这些模型,可用参考这里huggingface的transform库包含三个核心的类:configuration,models 和tokenizer 。之前在huggingface的入门超简单教程中介绍过。本次主要介绍tokenizer类。这个类对中文处理没啥太大帮助。当我们微调模型时,我们使用的肯定是与预训练模型相同的tokenizer,因为这些预训练模型学习了大量的语料中的语义关系,所以才能快速的通过微调提升我们的模型精度。如果你是某个专业的领域的nlp使用者,那么靠这些通用的语料是远远不够的,你还需要自己本专业的语料来提升模型的精度,这一篇将会花费一定的篇幅来介绍,如何快速训练自己的tokenizer。Tok过程及常见方法在开始使用模型之前,还是再根据图1的流程把内容过一遍。当然如果你不是高度定制化的,huggingface一个函数就已经帮你干完这些事情了,这里假设你要对中间的某个地方进行自己定制化的处理,我这里逐一介绍其中的模块和常用函数。Normalization 标准化这里是处理文本,huggingface提供了一个bertnormalizer,如果你不满意,当然也可以另配自己的,详细见代码中的注释和例子。from tokenizers import (

decoders,

models,

normalizers,

pre_tokenizers,

processors,

trainers,

Tokenizer,

)

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased",cache_dir='D:\\temp\\huggingface\\chen\\datasets')

example = "My name is Sylvain and I work at Hugging Face in Brooklyn也就是布鲁克林, Héllò hôw are ü? "

# 这里用bertnormalizer,它自动配好了几个参数

tokenizer.normalizer = normalizers.BertNormalizer(clean_text=True,lowercase=True,handle_chinese_chars=True)

# 除了lowercase外还有其他参数,handle_chinese_chars (bool, optional, defaults to True)是否把汉字用空格分出来

# clean_text (bool, optional, defaults to True) 是否成立控制字符和替换标准空格

encoding = tokenizer.normalizer.normalize_str(example)

print(encoding)

# 当然你也可以自己配置自己的normalizer,如下按顺序加入想要处理的函数就可以,这里演示了先NFD,再小写,再去除音标

tokenizer.normalizer = normalizers.Sequence(

[normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()]

)

encoding = tokenizer.normalizer.normalize_str(example)

print(encoding)

# 让我们来看看自动的bert的标准化处理和我们自己搭建的有什么不同

# my name is sylvain and i work at hugging face in brooklyn 也 就 是 布 鲁 克 林 , hello how are u?

# my name is sylvain and i work at hugging face in brooklyn也就是布鲁克林, hello how are u?支持Unicode的正则化(NFD/NFC/NFKD/NFKC)具体介绍这代表什么,可以参考这里normalizer的全部函数介绍看这里Pre-tokenization 预标记化 上面看到处理完之后没有进行分词,然后下一步是分词,再进行subword分词之前,要先对句子进行预处理,也就是按照一定的标记进行初步的分词,对于英文来说其实就是按照空格分一分。这里要用到pre-tokenization。他跟标准化一样,有huggingface提供的bert的预标准化以及sequence功能,让你把他的函数组合起来形成新的预标记功能,函数说明再这里。其代码与上一节中类似,也可以使用sequence排列自己的预标记化处理函数。model(本文核心)huggingface支持bytepair,wordpiece,unigram三种不同的subword算法,限于篇幅和能力,我节选了wordpiece算法。wordpiece算法是BPE算法的变种,来自于论文《Japanese and Korean Voice Search (Schuster et al., 2012) 》, WordPiece 只保存最终词汇,而不是学习的合并规则。wordpiece算法操作的主要步骤如下: 准备足够大的语料 设定期望的subword词表,也就是vocab的size,其是根据他来分割句子的,最后模型训练得到的结果就是它。 计算语料中所有的单词出现的频率(前面已经作了normalization 和pre-tok) 将单词拆分为字符序列;这里就是最简单的vocab了,他的size会随着下面训练循环不断扩大。 基于第4步数据训练语言模型,也就是获取vocab; 从所有可能的subword单元中选择 加入vocab后能够最大程度地增加训练数据概率的单元 作为新的单元。 重复第5步直到达到第2步设定的vocab词表大小或者概率增量低于某一个阈值其中的关键是第5步训练,那wordpiece是如何训练的呢?我们已知的是所有单词出现的频率,比如【about,10】,10表示about出现10次,vocab初始是字符序列,所有的第一个字母是不带##的,其他的就变成了##b,##0,##u,##t等等。然后下一步就是根据这个来计算出一个score,计算公示如下:score=(freq_of_pair)/(freq_of_first_element×freq_of_second_element)这个公示是非常抽象啊,那我们以huggingface上的例子来介绍是如何运行的:1.假设我们有如下的一个语料库统计结果:("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)2.那按照第一步字符切分则为:("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5)3.得到最初的词汇表vocab: ["b", "h", "p", "##g", "##n", "##s", "##u"] 对应的出现的次数是:4,15,17,20,16,5,364.我们以##u和##g为例,这一对在所有的语料中接连出现了20次,##u出现了36次,##g出现了20次 socre为:20/(36*20) = 1/36 这个分数很低,如果想选出高的分数,那么需要降低这两个出现的次数,我们5. 可以看到##g,##s的分数为:5/(20*5) = 1/20,这个对的分数高,所以这个对应该合并成##gs6. 此时vocab更新为: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"]7. 根据vovab就可以统计语料为:("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5)8. 这样又可以循环一遍找到哪两个对应该合并,直到vocab size达到我们想要的需求,或者分数到达一个阈值。wordpiece的底层算法google从未公开过,huggingface是根据他们对论文的理解实现的该算法。具体的实现代码可以参考这里:https://huggingface.co/course/zh-CN/chapter6/6?fw=ptpostprocesser这里是后面加[sep]等字符的操作,之前在bert里面都介绍了,这里不赘述。从旧的tokenizer训练新的介绍完了tokenizer的主要过程,以及常用的算法,本章是介绍如何训练一个新的分词器。训练tokenizer与训练模型不同!模型训练使用随机梯度下降,使每个批次的损失稍微小一些。它是自然随机化的(这意味着在两次进行相同的训练时,必须设置一些种子以获得相同的结果)。训练tokenizer是一个统计过程,它试图识别给定语料库中最适合选择的子词,用于选择它们的确切规则取决于标记化算法。它是确定性的,这意味着在同一语料库上使用相同的算法进行训练时,总是得到相同的结果。huggingface有一个可以训练与现有标记器相同特征的新标记器的转换器:AutoTokenizer.train_new_from_iterator()。训练数据我们继续使用上一篇中使用的cail2018数据集来做案例。首先是加载数据集,数据集喂入模型计算,分词模型也可以保存下来供下次调用,计算时间也是非常快的。from datasets import load_dataset , Dataset,list_datasets

# 设置一下下载的临时路径,要不然每次下载在C盘,空间受不了

datasets = load_dataset("code_search_net", "python", cache_dir='D:\\temp\\huggingface\\chen\\datasets')

# 下面是读取数据的过程

# huggingface推荐建立一个迭代器函数,迭代器的好处是只在使用时加载,节省内存

# 由于迭代器只能使用一次,所以最好是新建一个迭代器函数

def GetSampleData():

return (

datasets["train"][i : i + 1000]["whole_func_string"]

for i in range(0, len(datasets["train"]), 1000)

)

datasets_sample = GetSampleData()

from transformers import AutoTokenizer

old_tokenizer = AutoTokenizer.from_pretrained('gpt2',cache_dir='D:\\temp\\huggingface\\chen\\model')

example = '''def add_numbers(a, b):

"""Add the two numbers `a` and `b`."""

return a + b'''

tokens = old_tokenizer.tokenize(example)

# 这里打印出来可以看到,空格和Tab都被一个个的分开了

# print(tokens)

# 重新训练一个分词器吧

tokenizer = old_tokenizer.train_new_from_iterator(datasets_sample, 52000)

tokens = tokenizer.tokenize(example)

# 打印出来看看,略有不同

print(tokens)

#新训练的分词器可以保存起来,注意这里用的是AutoTokenizer

tokenizer.save_pretrained( "code-search-net-tokenizer" )Tokenizer的其他功能第一个是编码相关的功能,以BERT为例如下,涉及到的常用方法见代码,后面不一一赘述。from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased",cache_dir='D:\\temp\\huggingface\\chen\\datasets')

example = "My name is Sylvain and I work at Hugging Face in Brooklyn."

encoding = tokenizer(example)

print(type(encoding))

print(encoding)打印出来效果是这样:第一可以看到,encoding是一个字典子类,可以用字典的相关方法,也可以用batchencoding的相关方法来互相转换。第二注意到,这句话已经被分词了,而且加上了[sep]这种符号,sep在词典里面对应的是101,在input_ids里可以看到。此外还加了token_type_ids,这是区分bert中是第一句话还是第二句话。以及attention_mask 注意力掩码,如果是句子超出或者不足最大词(一般是512)就会自动补码 {'input_ids': [101, 1422, 1271, 1110, 156, 7777, 2497, 1394, 1105, 146, 1250, 1120, 20164, 10932, 10289, 1107, 6010, 119, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}再把tokens和word_ids打印出来看看。可以看到单次和符号是按照subword区分的并加上了相应的分隔符。word-ids是一个id可能对应多个token,比如三号词Sylvain对应了4个token。print(encoding.tokens())

print(encoding.word_ids())

# 输出如下:

# ['[CLS]', 'My', 'name', 'is', 'S', '##yl', '##va', '##in', 'and', 'I', 'work', 'at', 'Hu', '##gging', 'Face', 'in', 'Brooklyn', '.', '[SEP]']

# [None, 0, 1, 2, 3, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, None]word_to_chars() , token_to_chars() ,char_to_word() ,char_to_token()等四个方法可以让你随便的在这些内容中转来转去,比如你知道word_ids的number就可以专为对应的单词,这些功能似乎不是很常用。发布于 2022-12-12 22:12・IP 属地浙江深度学习(Deep Learning)Python 库​赞同 63​​6 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录NLP成长之路NLP从零入

GitHub - huggingface/tokenizers: Fast State-of-the-Art Tokenizers optimized for Research and Production

GitHub - huggingface/tokenizers: Fast State-of-the-Art Tokenizers optimized for Research and Production

Skip to content

Toggle navigation

Sign in

Product

Actions

Automate any workflow

Packages

Host and manage packages

Security

Find and fix vulnerabilities

Codespaces

Instant dev environments

Copilot

Write better code with AI

Code review

Manage code changes

Issues

Plan and track work

Discussions

Collaborate outside of code

Explore

All features

Documentation

GitHub Skills

Blog

Solutions

For

Enterprise

Teams

Startups

Education

By Solution

CI/CD & Automation

DevOps

DevSecOps

Resources

Learning Pathways

White papers, Ebooks, Webinars

Customer Stories

Partners

Open Source

GitHub Sponsors

Fund open source developers

The ReadME Project

GitHub community articles

Repositories

Topics

Trending

Collections

Pricing

Search or jump to...

Search code, repositories, users, issues, pull requests...

Search

Clear

Search syntax tips

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

Sign up

You signed in with another tab or window. Reload to refresh your session.

You signed out in another tab or window. Reload to refresh your session.

You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

huggingface

/

tokenizers

Public

Notifications

Fork

683

Star

8.2k

Fast State-of-the-Art Tokenizers optimized for Research and Production

huggingface.co/docs/tokenizers

License

Apache-2.0 license

8.2k

stars

683

forks

Branches

Tags

Activity

Star

Notifications

Code

Issues

150

Pull requests

13

Actions

Projects

0

Security

Insights

Additional navigation options

Code

Issues

Pull requests

Actions

Projects

Security

Insights

huggingface/tokenizers

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

 mainBranchesTagsGo to fileCodeFolders and filesNameNameLast commit messageLast commit dateLatest commit History1,759 Commits.github.github  bindingsbindings  docsdocs  tokenizerstokenizers  .gitignore.gitignore  CITATION.cffCITATION.cff  LICENSELICENSE  README.mdREADME.md  RELEASE.mdRELEASE.md  View all filesRepository files navigationREADMEApache-2.0 license

Provides an implementation of today's most used tokenizers, with a focus on performance and

versatility.

Main features:

Train new vocabularies and tokenize, using today's most used tokenizers.

Extremely fast (both training and tokenization), thanks to the Rust implementation. Takes

less than 20 seconds to tokenize a GB of text on a server's CPU.

Easy to use, but also extremely versatile.

Designed for research and production.

Normalization comes with alignments tracking. It's always possible to get the part of the

original sentence that corresponds to a given token.

Does all the pre-processing: Truncate, Pad, add the special tokens your model needs.

Bindings

We provide bindings to the following languages (more to come!):

Rust (Original implementation)

Python

Node.js

Ruby (Contributed by @ankane, external repo)

Quick example using Python:

Choose your model between Byte-Pair Encoding, WordPiece or Unigram and instantiate a tokenizer:

from tokenizers import Tokenizer

from tokenizers.models import BPE

tokenizer = Tokenizer(BPE())

You can customize how pre-tokenization (e.g., splitting into words) is done:

from tokenizers.pre_tokenizers import Whitespace

tokenizer.pre_tokenizer = Whitespace()

Then training your tokenizer on a set of files just takes two lines of codes:

from tokenizers.trainers import BpeTrainer

trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])

tokenizer.train(files=["wiki.train.raw", "wiki.valid.raw", "wiki.test.raw"], trainer=trainer)

Once your tokenizer is trained, encode any text with just one line:

output = tokenizer.encode("Hello, y'all! How are you ?")

print(output.tokens)

# ["Hello", ",", "y", "'", "all", "!", "How", "are", "you", "[UNK]", "?"]

Check the documentation

or the quicktour to learn more!

About

Fast State-of-the-Art Tokenizers optimized for Research and Production

huggingface.co/docs/tokenizers

Topics

nlp

natural-language-processing

transformers

gpt

language-model

bert

natural-language-understanding

Resources

Readme

License

Apache-2.0 license

Activity

Custom properties

Stars

8.2k

stars

Watchers

121

watching

Forks

683

forks

Report repository

Releases

84

v0.15.2

Latest

Feb 12, 2024

+ 83 releases

Packages

0

No packages published

Used by 63.2k

+ 63,150

Contributors

92

+ 78 contributors

Languages

Rust

71.0%

Python

20.5%

Jupyter Notebook

4.9%

TypeScript

2.5%

JavaScript

0.5%

CSS

0.3%

Other

0.3%

Footer

© 2024 GitHub, Inc.

Footer navigation

Terms

Privacy

Security

Status

Docs

Contact

Manage cookies

Do not share my personal information

You can’t perform that action at this time.

超详细Tokenizer——文本训练数据预处理_tokenizer的fit_on_texts-CSDN博客

>

超详细Tokenizer——文本训练数据预处理_tokenizer的fit_on_texts-CSDN博客

超详细Tokenizer——文本训练数据预处理

halo0416

于 2023-10-31 23:06:01 发布

阅读量570

收藏

1

点赞数

文章标签:

python

机器学习

人工智能

深度学习

自然语言处理

sklearn

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/m0_74053536/article/details/134151336

版权

当使用自然语言处理(NLP)技术进行文本处理时,Tokenizer是一个非常有用的工具,它可以将文本分词(tokenize)并将文本转化为整数序列,从而便于用于机器学习模型的训练和处理。在这篇博客中,我们将详细介绍Tokenizer的用法,并使用一个小例子来演示如何将文本转化为整数序列。

什么是Tokenizer?

Tokenizer是Keras库中的一个文本处理工具,它用于将文本分词并构建词汇表,同时将文本映射到整数序列。这对于自然语言处理任务非常有用,例如文本分类、情感分析、机器翻译等。

步骤一:初始化Tokenizer

首先,我们需要初始化一个Tokenizer对象。这个对象将用于训练和处理文本数据。

from keras.preprocessing.text import Tokenizer

tokenizer = Tokenizer()

步骤二:训练Tokenizer

接下来,我们需要使用fit_on_texts方法来训练Tokenizer。训练过程将语料库中的文本数据分词并构建词汇表。

lines = ["a quick brown fox", "jumps over the lazy dog"]

tokenizer.fit_on_texts(lines)

 步骤三:文本向量化

一旦Tokenizer被训练,你可以使用它将文本转化为整数序列。例如,我们有一个测试句子:"in street racer armor be examine the tire",我们可以将它向量化如下:

test_line = "in street racer armor be examine the tire"

sequences = tokenizer.texts_to_sequences([test_line])

此时,sequences将包含文本的整数序列,每个整数代表词汇表中的一个单词。在你的示例中,输出的整数序列是[4, 73, 711, 4558, 497, 2782, 5, 465]。

完整示例

下面是一个完整的示例,展示如何初始化Tokenizer、训练它,并将文本向量化:

from keras.preprocessing.text import Tokenizer

# 初始化Tokenizer

tokenizer = Tokenizer()

# 训练Tokenizer

lines = ["a quick brown fox", "jumps over the lazy dog"]

tokenizer.fit_on_texts(lines)

# 测试文本

test_line = "in street racer armor be examine the tire"

sequences = tokenizer.texts_to_sequences([test_line])

# 打印向量化结果

print(sequences)

通过这个博客,你可以了解如何使用Tokenizer来将文本数据转化为整数序列,这是NLP任务中的一个重要步骤。你可以将这个整数序列用于训练机器学习模型,进行文本分类或其他文本相关任务。

打印结果为:

[[4, 73, 711, 4558, 497, 2782, 5, 465]]

优惠劵

halo0416

关注

关注

0

点赞

1

收藏

觉得还不错?

一键收藏

知道了

1

评论

超详细Tokenizer——文本训练数据预处理

Tokenizer是Keras库中的一个文本处理工具,它用于将文本分词并构建词汇表,同时将文本映射到整数序列。这对于自然语言处理任务非常有用,例如文本分类、情感分析、机器翻译等。

复制链接

扫一扫

bert情感分类中用tokenizer实现文本预处理

01-03

在pytoch中,实现利用预训练BertTokenizer对影评数据集IMDB进行预处理,得到Bert模型所需输入样本特征。利用torch.utils.data将预处理结果打包为数据集,并利用pickle将数据集序列化保存至本地文件中。

Keras---text.Tokenizer:文本与序列预处理

热门推荐

图特摩斯科技-博客

08-30

4万+

keras中文文档:http://keras-cn.readthedocs.io/en/latest/preprocessing/text/

1 简介

在进行自然语言处理之前,需要对文本进行处理。

本文介绍keras提供的预处理包keras.preproceing下的text与序列处理模块sequence模块

2 text模块提供的方法

text_to_wo

1 条评论

您还未登录,请先

登录

后发表或查看评论

Keras Tokenizer的使用

censorship的博客

01-08

1081

Keras Tokenizer是一个方便的分词工具。

要使用Tokenizer首先需要引入

from keras.preprocessing.text import Tokenizer

Tokenizer.fit_on_texts(text)根据text创建一个词汇表。其顺序依照词汇在文本中出现的频率。在下例中,我们创建一个词汇表,并打印。出现频率高的即靠前,频率低的即靠后。

text1='To be or not to be'

tk = Tokenizer(num_words=None)

tk.fit_

LLaMA Tokenizer

最新发布

02-09

LLaMA原生Tokenizer,词表大小为32000。

chatgptGPT3训练-gpt文本生成模型

04-01

下面是一个基于TensorFlow 2.0的-2中文训练教程,帮助您训练出自己的中文GPT-2模型。请注意,该教程需要一定程度的Python编程经验和机器学习知识。

.

准备工作

.

在开始训练之前,需要准备以下工具和库:

TensorFlow 2.0或更高版本

Python 3.6或更高版本

BPE中文分词库

huggingface/transformers库

.

数据预处理

.

在开始训练之前,需要准备中文文本数据,并进行预处理。对于中文数据,需要对其进行分词和编码,常见的方法是使用BPE算法进行分词,将分词后的词汇转换为数字索引。下面是一个基本的数据预处理过程,使用BPE中文分词库和Python编写:

from tokenizers import ByteLevelBPETokenizertokenizer = ByteLevelBPETokenizer()# 训练分词器tokenizer.train(files=['data.txt'], vocab_size=32000, min_frequency=2, special_tokens=[

深度学习文本预处理利器:Tokenizer详解

十年以上架构设计经验,专注于软件架构和人工智能领域,对机器视觉、NLP、音视频等领域都有涉猎

09-21

3181

Tokenizer是一个用于向量化文本,将文本转换为序列的类。计算机在处理语言文字时,是无法理解文字含义的,通常会把一个词(中文单个字或者词)转化为一个正整数,将一个文本就变成了一个序列,然后再对序列进行向量化,向量化后的数据送入模型处理。

文本处理学习----预处理第一步 Tokenizer分词

Sweet12_03的博客

07-05

1210

是一个用于向量化文本,或将文本转换为序列的类。是用来文本预处理的第一步:分词

Keras的Tokenizer分词器

AlanxZhang的博客

10-08

2058

Tokenizer类

keras.preprocessing.text.Tokenizer(

num_words=None,

filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~ ',

lower=True,

split=' ',

char_level=Fals

1.5.3 什么是Tokenizer-分词

weixin_30532837的博客

02-27

607

什么是Tokenizer-分词

  分词器的工作就是分解文本流成词(tokens).在这个文本中,每一个token都是这些字符的一个子序列.一个分析器(analyzer)必须知道它所配置的字段,但是tokenizer不需要,分词器(tokenizer)从一个字符流(reader)读取数据,生成一个Token对象(TokenStream)的序列.

  输入流中的一些字符可能会被丢弃,如空格和一...

大模型:如何利用旧的tokenizer训练出一个新的来?

duzm200542901104的专栏

09-19

605

如果我们需要的语言中没有可用的大语言模型,或者我们要预测的数据集与我们选择的大语言模型训练的数据集非常不同,我们就需要使用适合我们的数据的tokenizer从头开始重新训练模型,训练tokenizer可以不必从头开始

nlp-tokenizer

04-30

用法 :

在lib文件夹中运行以下命令:

对于Linux: java -classpath args4j-2.0.6.jar:jmdn-base.jar:tokenizer.jar main.Main -filename ../data/sample.txt

对于Windows: java -classpath args4j-2.0.6.jar;jmdn-base.jar;tokenizer.jar main.Main -filename ..\data\sample.txt

注意:此项目是在Java 1.7中构建的

贡献者:

Nguyen Thac Thong-K57CA

潘宣天-K57CA

阮东林-K57CA

阮宣南-K57CA

Truong Quoc Tuan-K57CA

Le Van Giap-K57CA

阮范贾普-K57CA

阮团防-K57CA

string_tokenizer_unittest.rar_tokenizer

09-21

String Tokenizer Test Source Code for Linux.

[Python深度学习](五)深度学习用于文本和序列

gdtop的个人笔记

12-16

1818

本文为《Python深度学习》的学习笔记。

第6章 深度学习用于文本和序列

本章将使用深度学习模型处理文本、时间序列和一般的序列数据。

6.1 处理文本数据

深度学习模型不会接受原始文本作为输入,它只能处理数值张量。将文本分解成的单元叫做标记(token),将文本分解成标记的过程叫做分词(tokenization)。本节介绍两种主要方法,对标记one-hot编码与标记嵌入(词嵌入word ...

如何科学地使用keras的Tokenizer进行文本预处理

兔角与禅

03-05

2万+

如何科学地使用keras的Tokenizer进行文本预处理

缘起

之前提到用keras的Tokenizer进行文本预处理,序列化,向量化等,然后进入一个simple的LSTM模型中跑。但是发现用Tokenizer对象自带的 texts_to_matrix 得到的向量用LSTM训练不出理想的结果,反倒是换成Dense以后效果更好。后来实验了一下发现是对这个向量化函数的理解出现了偏差。鉴于网上...

keras.preprocessing.text.Tokenizer

rouge_eradiction的博客

09-07

621

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入keras.preprocessing.text.Tokenizerpad_sequences

欢迎使用Markdown编辑器

【自己创建分词器tokenizer】(3)——Unigram tokenizer

qq_46634315的博客

08-12

290

我们完成了这个分词器!我们可以像之前一样保存分词器,并且如果想要在Transformers中使用它,可以将其包装在PreTrainedTokenizerFast或XLNetTokenizerFast中。其他部分,比如保存与加载等,和之前WordPiece tokenizer是一样的,本文没有赘述。end。

Boost库基础-字符串与文本处理(tokenizer)

希望能帮助大家,希望大家多多支持,你们的支持是我前进的动力。

03-28

625

tokenizer

tokenizer库是一个专门用于分词的字符串处理库,它与string_algo库的分割算法很类似,但有更多的变化,需要包含以下头文件。

#include

using namespace boost;

类tokenizer是tokenizer库的核心,类摘要如下:

tokenizer接受三个模板类型参数:...

bert第三篇:tokenizer

iterate7的博客

10-08

3万+

文章目录tokenizer基本含义bert里涉及的tokenizerBasicTokenzerwordpiecetokenizerFullTokenzierPretrainTokenizer关系图实操如何训练训练自己中文的tokenizer总结引用

tokenizer基本含义

tokenizer就是分词器; 只不过在bert里和我们理解的中文分词不太一样,主要不是分词方法的问题,bert里基本都是最大匹配方法。

最大的不同在于“词”的理解和定义。 比如:中文基本是字为单位。

英文则是subword的概念,例

tokenizer的生成及padding

lawenliu的专栏

05-22

3999

我们在做embedding的时候,通常会先做下tokenizer,然后再做word embedding,我们下面看看怎么来生成tokenizer。

1. 可以先搞一批raw data,可以从网上爬下来,也可以从已有的collection下载。

2. 做下分词,中文可以用结巴,英文用空格和特殊符号

3. 分词生成的terms,我们保存下来,每句话可以保存一行,每行多个terms,用空格分隔

4. 用分词的term生成tokenizer,并做下padding。我们这里只关注这个部分,其他部分可以参考其他

spark dataframe 数据预处理

07-27

可以使用Spark的内置特征转换器(如`Tokenizer`、`VectorAssembler`等)进行文本分词、向量化等操作。 6. 数据规范化:对数据进行规范化处理,使得不同特征处于同一尺度上。可以使用Spark的内置特征转换器(如`...

“相关推荐”对你有帮助么?

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

halo0416

CSDN认证博客专家

CSDN认证企业博客

码龄1年

暂无认证

39

原创

115万+

周排名

6万+

总排名

2万+

访问

等级

606

积分

186

粉丝

202

获赞

28

评论

101

收藏

私信

关注

热门文章

【自然语言处理(NLP)实战】LSTM网络实现中文文本情感分析(手把手与教学超详细)

3022

Python实现汉诺塔问题的递归算法

1932

Pycharm安装中文语言包

1873

OpenCV实现图像风格迁移(梵高星空)

1117

C/C++利用递归思想求解斐波那契数列

1112

最新评论

解决任务管理器中关闭了某些进程,导致电脑白屏或操作系统崩溃

m0_65762703:

真的感谢

yolov5报错信息:tensorflow.python.framework.errors_impl.FailedPreconditionError: runs is not a directory

吃亿口mcu:

tensorflow.python.framework.errors_impl.FailedPreconditionError: 、 is not a directory,我这个文件夹一直存在,但他就是报错

【自然语言处理(NLP)实战】LSTM网络实现中文文本情感分析(手把手与教学超详细)

m0_74674276:

请问去除停用词的txt文件怎么生成啊

PCA(主成分分析)数据降维技术代码详解

winner069:

pca降维,那为什么输入是二维,输出还是二维呢?

【自然语言处理(NLP)实战】LSTM网络实现中文文本情感分析(手把手与教学超详细)

芝麻街干麻:

请问这个数据集的来源是什么,是作者您自己整理的吗

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

python中Thread实现多线程任务

YOLO免费数据集网站收集

YOLOv8中训练参数中文解释

2023年39篇

目录

目录

最新文章

python中Thread实现多线程任务

YOLO免费数据集网站收集

YOLOv8中训练参数中文解释

2023年39篇

目录

评论 1

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

tokenizer简介-CSDN博客

>

tokenizer简介-CSDN博客

tokenizer简介

最新推荐文章于 2024-03-04 16:01:55 发布

芳樽里的歌

最新推荐文章于 2024-03-04 16:01:55 发布

阅读量2.2w

收藏

147

点赞数

49

分类专栏:

NLP

文章标签:

自然语言处理

原文链接:https://huggingface.co/docs/transformers/master/en/tokenizer_summary

版权

NLP

专栏收录该内容

8 篇文章

8 订阅

订阅专栏

原文链接:https://huggingface.co/docs/transformers/master/en/tokenizer_summary

1、前言

众所周知,在NLP任务中,原始文本需要处理成数值型字符才能够被计算机处理,我们熟悉的one-hot编码就是一种转换方式。但这种方式有两个弊端:向量维度太高,且丢失了语义信息。后来人们发明了词向量(或称之为词嵌入,word embedding),它在一定程度了解决了one-hot的上述两个问题。

从「词向量」这个名字上就可以看出,其基本单元是词。因此,要想得到词向量,首先要对句子进行分词,所以,我们需要一个分词工具,简称之为“分词器”。在现代自然语言中,分词器的作用不再是仅仅将句子分成单词,更进一步的,它还需要将单词转化成一个唯一的编码,以便下一步在词向量矩阵中查找其对应的词向量。本文主要介绍一下现代NLP是如何将句子切分为词的。

在中文里,一般将tokenizer直接译为“分词器”,但正如上文所述,这其实只翻译出了其第一层含义。因此,我认为将其翻译为“符化器”——将句子分词并转化为唯一编码——更能体现其作用。本文不对该单词进行翻译。

2、引例

分词的任务看似简单,实际上却大有文章。首先,给一个例句:Don’t you love Transformers? We sure do.

一种最简单的分词方式,就是按照空格来对这个句子进行分词,可以得到如下内容:

["Don't", "you", "love", "", "Transformers?", "We", "sure", "do."]

分词成功。但是,我们注意到,对于"Transformers?" 和"do.",标点符号与单词分到了一起。这其实并不好,因为如果采用这种方式,那么对每一种标点与单词的组合,模型都要学习到一种向量表示,这无疑会增加模型训练的复杂度。因此,我们可以对上述分词方法进行优化,把标点单独分出来:

["Don", "'", "t", "you", "love", "", "Transformers", "?", "We", "sure", "do", "."]

尽管“?”和“.”被成功分离出来,但是,缩写单词"Don’t"也被拆分了。我们知道,"Don’t"是"do not"的缩写,因此,将其分为["Do", "n't"]显然更合理一些。

到这里,事情开始变得复杂起来,不同的模型对于上述情况的处理采用了不同的方式。也就是说,即使是对于同一段文本,由于采用的切分规则不同,我们也可能得到不同的输出。因此,要想正确地使用一个预训练模型,首先需要注意的就是,模型输入所用的切分规则,必须与模型的训练数据所采用的切分规则相同。换句话说,一个预训练模型,对应一个与之匹配的tokenizer。

spaCy和Moses是两个比较流行的基于规则的tokenizer。将其应用于上述例句,输出如下:

["Do", "n't", "you", "love", "", "Transformers", "?", "We", "sure", "do", "."]

可以看出,句子被基于空格、标点和缩写词规则进行了切分。这种直观的分词方式非常易于理解,但在面对海量文本语料的场景时,会出现一些问题。在这些场景里,基于空格和标点的切分方式通常会生成非常大的词表(词表指对所有单词和标点去重后得到的集合)。例如,TransformerXL使用这种方式进行分词,生成的词表的规模为267,735!

如此规模的词表,将迫使模型维护一个极其庞大的词向量矩阵,这将会导致运算中的时间复杂度和内存占用的上升。实际上,transformers 模型的词汇量很少超过 50,000,尤其是当它们仅在一种语言上进行预训练时。

既然这种符合直觉的简单分词方式并不令人满意,那为何不将句子直接拆分为字母(字符级)呢?

虽然将句子直接拆分为字母非常简单并且会大大减少内存占用和时间复杂度,但它使模型学习有意义的输入表示变得更加困难。例如,对于字母"t" ,学习它的上下文无关且有意义的向量表示比学习单词"today"的向量表示要难得多。这也就是说,直接字母表示通常会导致性能下降。

既然如此,为了两全其美,transformers 模型使用了词级切分和字符级切分的混合,称为子词(subword)切分。

3、子词切分

子词切分算法依赖这样一种原则:常用词不应该被切分;罕见词应该被切分为更有意义的子词。例如,单词"annoyingly"是一个罕见词,因此,可以被切分为"annoying"和"ly"——"annoying"和"ly"更加常见,且"annoyingly"的含义可以由"annoying"和"ly"组合生成。

子词切分允许模型保持一个规模相对合理的词汇量,同时能够学习有意义的上下文无关表示。此外,子词切分还可以使模型能够处理它以前从未见过的词,将它们分解为已知的子词。例如,使用BertTokenizer来切分句子"I have a new GPU!",其结果如下:

>>> from transformers import BertTokenizer

>>> tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")

>>> tokenizer.tokenize("I have a new GPU!")

["i", "have", "a", "new", "gp", "##u", "!"]

由于使用了不区分大小写的模型,因此,句子中的字母都被处理成了小写。从结果中可以看出,[“i”, “have”, “a”, “new”]出现在tokenizer的词表中,但是"gpu"并不在词表中。因此,tokenizer将"gpu"切分成了两个存在于词表中的子词:[“gp”, “##u”]。 "##"表示该token的剩余部分应该直接连接到上一个token上(这将会被用于解码层)。

另外一个例子,我们使用XLNetTokenizer:

>>> from transformers import XLNetTokenizer

>>> tokenizer = XLNetTokenizer.from_pretrained("xlnet-base-cased")

>>> tokenizer.tokenize("Don't you love Transformers? We sure do.")

["▁Don", "'", "t", "▁you", "▁love", "▁", "", "▁", "Transform", "ers", "?", "▁We", "▁sure", "▁do", "."]

有关其中的"_ “的含义,在下面讲SentencePiece时再进行说明。如你所见,不常见的单词"Transformers"已经被切分为两个更常见的子词"Transform"和"ers”。

现在,让我们看看不同的子词切分算法是如何工作的。请注意,所有这些切分算法都依赖于某种形式的训练,这些训练使用的语料一般情况下和训练与之对应的pretrained model所使用的语料相同。

3.1 字节对编码(Byte-Pair Encoding, BPE)

BPE首次在论文Neural Machine Translation of Rare Words with Subword Units(Sennrich et al., 2015)中被提出。BPE首先需要依赖一个可以预先将训练数据切分成单词的tokenizer,它们可以一些简单的基于空格的tokenizer,如GPT-2,Roberta等;也可以是一些更加复杂的、增加了一些规则的tokenizer,如XLM、FlauBERT。

在使用了这些tokenizer后,我们可以得到一个在训练数据中出现过的单词的集合以及它们对应的频数。下一步,BPE使用这个集合中的所有符号(将单词拆分为字母)创建一个基本词表,然后学习合并规则以将基本词表的两个符号形成一个新符号,从而实现对基本词表的更新。它将持续这一操作,直到词表的大小达到了预置的规模。值得注意的是,这个预置的词表大小是一个超参数,需要提前指定。

举个例子,假设经过预先切分后,单词及对应的频数如下:

("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)

因此,基本词表的内容为[“b”, “g”, “h”, “n”, “p”, “s”, “u”]。对应的,将所有的单词按照基本词表中的字母拆分,得到:

("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5)

接下来,BPE计算任意两个字母(符号)拼接到一起时,出现在语料中的频数,然后选择频数最大的字母(符号)对。接上例,"hu"组合的频数为15("hug"出现了10次,“hugs"中出现了5次)。在上面的例子中,频数最高的符号对是"ug”,一共有20次。因此,tokenizer学习到的第一个合并规则就是将所有的"ug"合并到一起。于是,基本词表变为:

("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5)

应用相同的算法,下一个频数最高的组合是"un",出现了16次,于是"un"被添加到词表中;接下来是"hug",即"h"与第一步得到的"ug"组合的频数最高,共有15次,于是"hug"被添加到了词表中。

此时,词表的内容为[“b”, “g”, “h”, “n”, “p”, “s”, “u”, “ug”, “un”, “hug”],原始的单词按照词表拆分后的内容如下:

("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5)

假定BPE的训练到这一步就停止,接下来就是利用它学习到的这些规则来切分新的单词(只要新单词中没有超出基本词表之外的符号)。例如,单词"bug"将会被切分为[“b”, “ug”],但是单词"mug"将会被切分为["", “ug”]——这是因为"m"不在词表中。

正如之前提到的,词表的规模——也就是基本词表的大小加上合并后的单词的数量——是一个超参数。例如,对于GPT而言,其词表的大小为40,478,其中,基本字符一共有478个,合并后的词有40,000个。

字节级的BPE

一个包含所有基本字符的词表也可以非常的大,例如,如果将所有的unicode字符视为基本字符。针对这一问题,GPT-2使用字节来作为基本词表,这种方法保证了所有的基本字符都包含在了词表中,且基本词表的大小被限定为256。再加上一些用于处理标点的规则,GPT2的tokenizer可以切分任何英文句子,而不必引入符号。GPT-2的词表大小为50,257,包含了256个字节级的基本词表,一个用于标识句子结尾的特殊字符,以及学习到的50,000个合并单词。

3.2 WordPiece

WordPiece是一种被应用于BERT,DistilBERT和Electra中的子词切分算法,它与BPE算法非常像。首先,它初始化一个包含所有出现在训练数据中的字符的词表,然后递归地学习一些合并规则。与BPE不同的是,WordPiece并不选择出现的频数最高的组合,而是选择可以最大化训练数据可能性的组合。

仍然拿上面的例子来说明。最大化训练数据的可能性就等同于找到这样的符号对,它的概率除以其第一个符号的概率与其第二个符号的概率的乘积,所得的值是所有可能的符号对中最大的。例如,如果"ug"的概率除以"u"的概率再除以"g"的概率得到的结果比其他任何一种组合的结果都大,那么就将"ug"组合起来。从直觉上说,WordPiece在合并两个符号前,评估了一下这种合并所带来的损失(合并后的概率除以合并前的概率),以确保这种合并是有价值的。

3.3 Unigram

论文Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates提出了基于子词的Unigram的切分方法。与BPE和WordPiece不同的是,Unigram以一个大规模的符号库作为其初始词表,然后采用迭代的方式来不断降低词表的规模。例如,初始词表可以是一个包含所有的预先切分的单词和所有常见子词的集合。

在每一个训练步中,Unigram算法在给定当前词表和一元语言模型的情况下定义了训练数据的损失函数(通常为对数似然函数)。然后,对于词表中的每一个符号,算法都会计算出如果将该符号从词表中移除,全局损失会增加多少。随后,Unigram会移除一定百分比(通常是10%或20%)的那些使损失增加最少的符号。

重复上述训练过程,直到词表达到预定的规模。由于Unigram总是保留基本字符,因此它可以切分任何单词。

由于Unigram并不像BPE和WordPiece那样依赖合并规则,所以,经过训练的Unigram在切分文本时可能会有多种选择。假设一个Unigram tokenizer的词表如下:

["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"],

单词"hugs"可以被切分为[“hug”, “s”]、[“h”, “ug”, “s”]或[“h”, “u”, “g”, “s”]。那么,究竟该选择哪一种呢?Unigram在保存词表的基础上,也保存了训练语料库中每个token的概率,以便在训练后计算每一种可能的切分的概率。Unigram在实践中只是简单地选择概率最大的切分作为最终结果,但也提供了根据概率对可能的切分进行采样的能力。

3.4 SentencePiece

上文介绍了所有的切分算法都有一个共同的问题:它们都假定输入的文本使用空格进行单词划分。然而,并不是所有的语言都是这样的。针对这一点,一种解决方案是,使用基于特定语言的tokenizer进行预先分词,例如,XLM使用了针对中文、日文和泰文的tokenizer。一个更一般的解决方案,在论文SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing(Kudo et al., 2018)中被提出。这种方法将输入的文本视为元输入流,进而将空格包含在要使用的字符集中。然后,它再使用BPE或Unigram算法来构建一个合适的词表。

XLNetTokenizer使用了SentencePiece,这也就是为什么在上面的例子中,"_ “出现在其切分结果中。基于SentencePiece的解码非常容易:将各个token拼接起来,把”_ "替换为空格即可。

优惠劵

芳樽里的歌

关注

关注

49

点赞

147

收藏

觉得还不错?

一键收藏

知道了

3

评论

tokenizer简介

本文介绍了现代NLP中有关tokenizer的内容

复制链接

扫一扫

专栏目录

ac_website:面向AC承包商的808biz免费ci4简介网站

05-20

ac_website

关于带有Ci4和用户管理系统的808biz Business Builder

使用CodeIgniter 4为A / C承包商提供一个简单而免费的介绍性网站

好处:

预制仪表板页面

预设帐户页面

预设的个人资料页面

预设设置页面

用户登录,用户注册,找回密码功能

用户访问日志以进行跟踪

用户管理:注册,修改和删除用户

带有Ci4的808biz Business Builder提供了完整的基本身份验证系统,帐户查看,配置文件编辑和仪表板查看。

入门

系统要求

PHP > = 7.1.3

MySQL 5.x或更高版本

Nginx或Apache (推荐)http服务器

必需PHP扩展: OpenSSL , PDO , Mbstring , Tokenizer , Ctype , JSON

如果您正在本地开发上运行,我们建议使用VSCODE或XAMPP堆栈,该堆栈具有

EssayKiller_V2:基于开源GPT2.0的初代创作型人工智能|可扩展,可进化

03-16

随笔杀手

通用型议论文创作人工智能框架,仅限交流与科普。

Bilibili视频地址: :

项目简介

EssayKiller是基于OCR,NLP领域的最新模型所构建的生成式文本创作AI框架,当前第一版finetune模型针对高考作文(主要是议论文),可以有效生成符合人类认知的文章,大量文章经过测试可以达到正常高中生及格作文水平。

项目作者

主页1

主页2

主页3

图灵的猫

致谢

感谢@作者提供GPT-2中文预训练框架与数据支持。感谢, , , , , , , , 的参与和支持

框架说明

基于EAST,CRNN,Bert和GPT-2语言模型的高考作文生成AI

支持bert tokenizer,当前版本基于clue vocab

17亿个参数多模块非深度神经网络,超2亿条预训练数据

线上点击即用的文本生成效果demo:

端到端生成,从试卷识别到答题卡输出一条龙服务

Colab线上作

3 条评论

您还未登录,请先

登录

后发表或查看评论

udpipe:基于UDPipe自然语言处理工具包的R软件包,用于标记化,语音标记,词法化和依存性分析

02-03

udpipe-基于UDPipe的用于标记化,标记,合法化和依赖性解析的R包

该存储库包含的R包是绕UDPipe C ++库的RCPP包装物( , )。

UDPipe提供了与语言无关的标记,标记,词条化以及原始文本的依赖项解析,这是自然语言处理中必不可少的部分。

所使用的技术在论文中进行了详细说明:“使用UDPipe进行令牌化,POS标记,解密和解析UD 2.0”,可从以下网址获得: //ufal.mff.cuni.cz/~straka/papers/2017-conll_udpipe.pdf 。 在该论文中,您还将发现不同语言和流程速度的精确度(以每秒字数为单位)。

一般

在围绕UD

[SentencePiece]论文解读:SentencePiece: A simple and language independent subword tokenizer...

bigcrab的博客

12-07

856

SentencePiece不应该看作一个分词算法,现有的分词算法貌似只有两种,BPE和Unigram,WordPiece和SentencePiece一样,其不过是做了一些改良;

tokenizer:一个简单的中文分词算法,可用于网游脏词过滤、搜索引擎文档解析、自然语言处理等需要中文分词的场合

04-27

洋文单词以空格天然分词,相比较而言因为一句中文是由连贯的字组成的,分词就麻烦一些。最困难的情况是对二义性句子的分割问题。比如“搜索引擎”这四个字,可以拆成“搜索”和“引擎”,但“索引”也是一个中文词汇。在脏词过滤的逻辑中最简单的做法是不使用分词,用所有脏词和一句话匹配,如果任意一个脏词是这句话的子串就认定为脏句,这种做法虽然避免了漏网之鱼,但是会因过于严格而让正常的句子变成脏句,分词可以改善这种问题。本项目提供一种简单的中文分词算法,并用近乎伪代码的 Python 编写。期待有人写出更好的版本:比如对效率的优化;在分词过程中引入词性的判定,进而过滤掉在词法上有效但语法上无效的节点等。

目前算法支持二义性划分,如词典里有“喜”,“欢”,“喜欢”三个词,则“喜欢”会拆成[喜欢]和[喜, 欢]两种划分;还支持新词划分,对于未知的词汇,会分割成单字。详见代码本身示例。

通用型高考作文题目预测模型.zip

09-20

项目简介

EssayTopicPredict是基于无监督学习、模式识别与NLP领域的最新模型所构建的生成式AIGC考试题预测框架,目前第一版finetune模型针对高考作文,可以有效生成符合人类认知的文章题目。

框架说明

基于哈工大RoBerta-WWM-EXT、Bertopic、GAN模型的高考题目预测AI

支持bert tokenizer,当前版本基于clue chinese vocab

17亿参数多模块异构深度神经网络,超2亿条预训练数据

可结合作文生成器一起使用:17亿参数作文杀手

端到端生成,从试卷识别到答题卡输出一条龙服务

通过GPT-4模型进行命题指导与判断,同时也可以写/优化范文

本地环境

Ubuntu 18.04.2/ Windows10 x86

Pandas 0.24.2

Regex 2019.4.14

一站式掌握elastic search基础与实战视频资源-百度云链接

08-26

视频资源太大,这里提供百度云链接: 资源包括项目源码和所需的数据:

01-1 _课程导学~1.mp4

01-2 说明和建议~1.mp4

02-1 -术语介绍 .mp4

02-2 Document介绍.mp4

02-3 index介绍 .mp4

02-4 -restapi介绍 .mp4

02-5 -index_api .mp4

02-6 -document_api.mp4

03-01 -书的目录与索引.mp4

03-02 -正排与倒排索引简介.mp4

03-03 -倒排索引详解.mp4

03-04 -分词介绍.mp4

03-05 -analyze_api .mp4

03-06 -自带分词器.mp4

03-07 -中文分词.mp4

03-08 -自定义分词之CharacterFilter .mp4

03-09 自定义分词之Tokenizer .mp4

03-10 -自定义分词之 TokenFilter .mp4

03-11 -自定义分词.mp4

03-12 -分词使用说明 .mp4

03-13 -官方文档说明.mp4

04-01 -mapping简介.avi

04-02 -自定义 mapping .avi

04-03 -mapping演示.avi

04-04 -copy_to参数说明.avi

04-05 -index参数说明.avi

04-06 -index_options参数说明.avi

04-07 -mapping文档说明.avi

04-08 -数据类型.avi

04-09 -dynamic-mapping简介.avi

04-10 -dynamic日期与数字识别.avi

04-11 -dynamic-template简介.avi

04-12 -自定义mapping的建议.avi

04-13 -索引模板.mp4.avi

05-01 -SearchAPI概览.avi

05-02 -URISearch详解与演示.avi

05-03 -QueryDSL简介.avi

05-04 -字段类查询简介及match-query.avi

05-05 -相关性算分.mp4.avi

05-06 -match-phrase-query_音频.mp4.avi

05-07 -query-string-query.avi

05-08 -simple-query-string-query.avi

05-09 -term-terms-query.avi

05-10 -range-query.avi

05-11 -复合查询介绍及ConstantScore.avi

05-12 -bool-query.avi

05-13 -count-and-source-filtering.avi

06-01 -分布式介绍及cerebro.avi

06-02 -构建集群.avi

06-03 -副本与分片.avi

06-04 -两个问题.avi

06-05 -集群状态.avi

06-06 -故障转移.mp4.avi

06-07 -文档分布式存储.avi

06-08 -脑裂问题.avi

06-09 -shard详解.avi

07-1 -Query-Then-Fetch.avi

07-2 -相关性算分.avi

07-3 -sorting-doc-values-fielddata.avi

07-4 -分页与遍历-fromsize.avi

07-5 分页与遍历.avi

07-6 分页与遍历-search_after.avi

07-7 文档说明.mp4.avi

08-1 -聚合分析简介.avi

08-2 -metric聚合分析.avi

08-3 -bucket聚合分析.avi

08-4 -bucket和metric聚合分析.avi

08-5 -pipeline聚合分析.avi

08-6 -作用范围.avi

08-7 -排序.avi

08-8 -原理与精准度问题.avi

08-9 -文档说明.avi

09-1 -数据建模简介.avi

09-2 -ES数据建模配置相关介绍.avi

09-3 -ES数据建模实例.mp4.avi

09-4 -Nested_Object.avi

09-5 -Parent_Child.avi

09-6 -nested_vs_parent_child.avi

09-7 -reindex.avi

09-8 其他建议.avi

10-1 生产环境部署建议.avi

10-2 写性能优化.avi

10-3 读性能优化.avi

10-4 如何设定shard数.avi

10-5 xpack监控功能介绍.avi

11-1 入门及架构简介.avi

11-2 -Life_of_an_Event.avi

11-3 -queue简介.avi

11-4 -线程简介.avi

11-5 配置简介.avi

11-6 多实例运行.avi

11-7 pipeline配置简介.avi

12-01 input插件详解及glob讲解.avi

12-02 -codec插件详解.avi

12-03 filter插件简介及date插件讲解.avi

12-04 filter插件之grok简介(上).avi

12-05 filter插件之grok简介(下).avi

12-06 filter插件之dissect讲解.avi

12-07 filter插件之mutate 讲解.avi

12-08 filter插件之 json讲解.avi

12-09 filter 插件之geoip和ruby 讲解.avi

12-10 output插件简介.avi

12-11 文档说明.avi

123.bat

13-1 -Logstash实战建议.avi

13-2 -实战之apacheLogs(上).avi

13-3 实战之apacheLogs(下).avi

13-4 实战之csv.avi

13-5 监控运维建议.avi

14-1 beats简介.avi

14-2 Filebeat_Demo.avi

14-3 Filebeat 简介及流程介绍.avi

14-4 Filebeat常见架构及ingest_node介绍.avi

14-5 Filebeat_Module简介.avi

15-1 -简介.avi

15-2 -Module简介.avi

15-3 -实战.mp4.avi

16-1 1-简介(1).avi

16-1 1-简介(1).avi.baiduyun.downloading

16-1 1-简介.avi

16-2 2-实战.avi

17-1 1-Heartbeat.avi

17-2 2-Community_beats.avi

18-1 -配置与线上部署建议.avi

18-2 -Index_Pattern_Objects_Settings使用.avi

19-1 -导入数据.avi

19-2 -Discover实战.avi

20-1 -可视化简介.avi

20-2 -Basic_Charts_介绍.avi

20-3 -Basic_Charts_其他说明.avi

20-4 -Data图表介绍.avi

20-5 -Map图表介绍.avi

20-6 -Timelion介绍.avi

20-7 -VisualBuilder介绍.avi

20-8 -other图表介绍.avi

20-9 -Dashboard介绍.avi

21-1 -项目介绍.avi

21-2 项目实战.avi

22-1 介绍和数据导入.avi

22-2 -实战.avi

23-1 项目简介.avi

23-2 实战(上).avi

23-3 实战(下).avi

24-1 课程总结.avi

codes.zip

project.zip

文件树.txt

Tokenizer总结

choose_c的博客

08-02

9764

Introduciton

transformer类型的预训练模型层出不穷,其中的tokenizer方法作为一个非常重要的模块也出现了一些方法。本文对tokenizer方法做一些总结。参考来自hunggingface。

tokenizer在中文中叫做分词器,就是将句子分成一个个小的词块(token),生成一个词表,并通过模型学习到更好的表示。其中词表的大小和token的长短是很关键的因素,两者需要进行权衡,token太长,则它的表示也能更容易学习到,相应的词表也会变小;to...

深度学习文本预处理利器:Tokenizer详解

十年以上架构设计经验,专注于软件架构和人工智能领域,对机器视觉、NLP、音视频等领域都有涉猎

09-21

3180

Tokenizer是一个用于向量化文本,将文本转换为序列的类。计算机在处理语言文字时,是无法理解文字含义的,通常会把一个词(中文单个字或者词)转化为一个正整数,将一个文本就变成了一个序列,然后再对序列进行向量化,向量化后的数据送入模型处理。

1.5.3 什么是Tokenizer-分词

weixin_30532837的博客

02-27

607

什么是Tokenizer-分词

  分词器的工作就是分解文本流成词(tokens).在这个文本中,每一个token都是这些字符的一个子序列.一个分析器(analyzer)必须知道它所配置的字段,但是tokenizer不需要,分词器(tokenizer)从一个字符流(reader)读取数据,生成一个Token对象(TokenStream)的序列.

  输入流中的一些字符可能会被丢弃,如空格和一...

python函数——Keras分词器Tokenizer

热门推荐

Congying-Wang的博客

12-11

2万+

文章目录0. 前言

python函数 系列目录:python函数——目录

0. 前言

NLP——Tokenizer

行者无疆的博客

11-20

7502

1.什么是Tokenizer

  使用文本的第一步就是将其拆分为单词。单词称为标记(token),将文本拆分为标记的过程称为标记化(tokenization),而标记化用到的模型或工具称为tokenizer。Keras提供了Tokenizer类,用于为深度学习文本文档的预处理。

2.创建Tokenizer实例

from keras.preprocessing.text import Tokenizer

tok = Tokenizer()

3.学习文本字典

##假设文本数据为:

docs = ['good

JavaScript编译器:编译器教程,使用TypeScript实现一个简单JavaScript编译器

01-30

JavaScript-compiler项目简介:

编译原理比较复杂,我们不求写出一个完整的编译器,但掌握基本原理还是很有必要的。核心内容:自动机,其他无关文法,自顶向下语法分析,中序转换为后序算法解决语法优先级问题,中间代码生成,内存分配,运行时分析,opcode生成等。理解不到位的地方还望斧正。

目录

原始目录结构:

src

├─common 公共库

├─demo

│ │─tokenizer.ts 词法解析器demo

│ │─parser.ts 语法解析器demo

│ ├─ILGen.ts 中间码生成demo

│ └─opcodeCompiler.ts 机器码生成demo

├─parse 语法分析

│ ├─expression.ts 表达式

│ ├─exprParser.ts 表达式解析器

│ │─parser.ts 语法解析器

│ ├─statement.ts 陈述语句

│ └─terminal.ts 终结符

├─tokenizer 词法分析

laravel诗词博客-匠心编程,热爱生活。喜欢就Star吧

02-03

Laravel诗词博客-匠心编程,热爱生活。

感谢各位朋友的支持,很开心和你分享我的代码,希望大家也能多写博客,提高自己能力的同时又能以后回顾所学的知识。饮水思源,你的星就是对我最好的支持。

如果您在安装过程中遇到了问题,请提交Issue ,我将会为你提供帮助。

简介

采用Laravel5.8版本框架构建

前端使用Bootstrap4框架,适配移动,PC

管理后台使用Laravel-admin1.73版本

使用Pjax初步无刷新加载

各个板块可自定义,扩展性强,专注细节,性能优秀

写作支持MarkDown语法编辑器,Simditor编辑器

完美支持音乐播放,专辑管理,视频播放

支持邮箱订阅,发布文章,任意邮件通知

支持多种Live2D看板娘动画

支持七牛云对象存储文件上传

可能是世界上最漂亮的博客之一

服务器要求

安装Nginx / Apache

安装MySQL

安装PHP> = 7.1.3【推荐版本7.2】

PHP必要扩展

DOM PHP 扩展

OpenSSL PHP 拓展

PDO PHP 拓展

Mbstring PHP 拓展

Tokenizer PHP 拓展

XML

tensorflow-ml-nlp:텐서플로우와로머신러닝으리(로지스틱회귀부터스트랜지)

02-03

와로2머신러닝으로자연어처리책이나왔습니다。 。기링크를다。

링크https: :

NLPBOOK

(로우와로머신러닝으리(로지스틱회귀회귀부터스포머지)

소개(简介)

。리처제들을리파지토리입니다。

。파토활용하여활용하여활용하여되실겁니되실겁니되실겁니되실겁니되실겁니되실겁니되실겁니。

u이브러리들(需求)

Python3

Tensorflow == 1.10

麻木

大熊猫

Matplot

설치방법(环境)

pip install -r requirements.txt

python 3.6的最新版本。

conda install python=3.6

GPU的照片C

ik对应的7.x分词器

10-23

一、简介

solr7以前的版本对于中文分词支持不好,通常会用IK分词器。对于solr7,可以直接使用提供的分词器。

二、solr7中文分词器使用步骤

1、复制lucene-analyzers-smartcn-7.2.0.jar(在contrib/analysis-extras/lucene-libs目录下)到server/solr-webapp/webapp/WEB-INF/lib目录下

2、在managed-schema(在server/solr/stu/conf目录下,这里选的自定义core即stu)文件中添加新分词器

---------------------

作者:panda-star

来源:CSDN

原文:https://blog.csdn.net/chinabestchina/article/details/79079026

版权声明:本文为博主原创文章,转载请附上博文链接!

Bert Encoder和Transformer Encoder有什么不同

最新发布

Carl_changxin的博客

03-04

999

前言:本篇文章主要从代码实现角度研究 Bert Encoder和Transformer Encoder 有什么不同?应该可以帮助你:

深入了解Bert Encoder 的结构实现

深入了解Transformer Encoder的结构实现

本篇文章不涉及对注意力机制实现的代码研究。

注:本篇文章所得出的结论和其它文章略有不同,有可能是本人代码理解上存在问题,但是又没有找到更多的文章加以验证,并且代码也检查过多遍。

观点不太一致的文章:bert-pytorch版源码详细解读_bert pyto

P1540 [NOIP2010 提高组] 机器翻译题解

m0_72674633的博客

02-29

420

队列的相关知识

从第一原理看大语言模型

u013308709的博客

03-03

494

大模型基础框架

大模型幻觉问题

大模型能力

思维链模式

思维链模式激发的是大模型的推理能力

LLM知识能力RAG

tokenizer c++

08-20

tokenizer c 是一个用于分词的字符串处理库。它接受三个模板类型参数:TokenizerFunc、Iterator和Type。TokenizerFunc是分词函数的类型,默认为char_delimiters_separator;Iterator是待分词字符串的迭代器类型,默认为std::string::const_iterator;Type是分词结果的类型,默认为std::string。这个库可以方便地将一个字符串分解成若干个单词,比如像Java里的StringTokenizer。要使用tokenizer库,需要包含头文件#include 123

#### 引用[.reference_title]

- *1* *3* [C++ Boost库:分词处理库 tokenizer](https://blog.csdn.net/u014779536/article/details/116398471)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"]

- *2* [C++ Tokenizer](https://download.csdn.net/download/yaochenlan/3323707)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"]

[ .reference_list ]

“相关推荐”对你有帮助么?

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

芳樽里的歌

博客等级

码龄7年

75

原创

396

点赞

1634

收藏

204

粉丝

关注

私信

热门文章

统计学中的Bootstrap方法介绍及其应用

72157

BiLSTM之一:模型理解

56639

tokenizer简介

22167

理解时间序列的ACF与PACF

16432

【小技巧】如何获取Finalshell中保存的密码

10818

分类专栏

python

42篇

SQLAlchemy

4篇

时间序列

1篇

数据库

2篇

信号处理

2篇

dash

2篇

机器学习

8篇

新能源

1篇

光伏

1篇

光伏发电

LeetCode

3篇

搜索引擎

1篇

其他

11篇

随笔与感想

2篇

低质量博客

4篇

NLP

8篇

概率与统计

3篇

知识图谱

3篇

数据结构与算法

5篇

最新评论

第二篇:傅里叶变换与短时傅里叶变换

芳樽里的歌:

搜索引擎里呗

第二篇:傅里叶变换与短时傅里叶变换

sixueh:

楼主讲得挺好的,一般都是在哪里学到这些知识的

理解时间序列的ACF与PACF

lincong07:

为什么在置信区间里,表明不能代表真实相关性啊

读取微信聊天记录并制作词云图

Over Watcher:

成功了,你们将IMEI替换为1234567890ABCDEF就可以了,不要用模拟器随机的那个

读取微信聊天记录并制作词云图

Over Watcher:

成功了,你们将IMEI替换为1234567890ABCDEF就可以了,不要用模拟器随机的那个

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

「才得吹嘘身渐稳」,也来谈谈大模型

在python中如何使用argparse更好地传入布尔值

【与ChatGPT的对话】python多线程

2023年8篇

2022年16篇

2021年24篇

2020年12篇

2019年11篇

2018年12篇

目录

目录

分类专栏

python

42篇

SQLAlchemy

4篇

时间序列

1篇

数据库

2篇

信号处理

2篇

dash

2篇

机器学习

8篇

新能源

1篇

光伏

1篇

光伏发电

LeetCode

3篇

搜索引擎

1篇

其他

11篇

随笔与感想

2篇

低质量博客

4篇

NLP

8篇

概率与统计

3篇

知识图谱

3篇

数据结构与算法

5篇

目录

评论 3

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

NLP BERT GPT等模型中 tokenizer 类别说明详解-腾讯云开发者社区-腾讯云

BERT GPT等模型中 tokenizer 类别说明详解-腾讯云开发者社区-腾讯云大鹅NLP BERT GPT等模型中 tokenizer 类别说明详解原创关注作者腾讯云开发者社区文档建议反馈控制台首页学习活动专区工具TVP最新优惠活动文章/答案/技术大牛搜索搜索关闭发布登录/注册首页学习活动专区工具TVP最新优惠活动返回腾讯云官网大鹅首页学习活动专区工具TVP最新优惠活动返回腾讯云官网社区首页 >专栏 >NLP BERT GPT等模型中 tokenizer 类别说明详解NLP BERT GPT等模型中 tokenizer 类别说明详解原创大鹅关注修改于 2021-08-20 21:03:4514.5K0修改于 2021-08-20 21:03:45举报文章被收录于专栏:大鹅专栏:大数据到机器学习大鹅专栏:大数据到机器学习1. 背景与基础在使用GPT BERT模型输入词语常常会先进行tokenize ,tokenize具体目标与粒度是什么呢?tokenize也有许多类别及优缺点,这篇文章总结一下各个方法及实际案例。tokenize的目标是把输入的文本流,切分成一个个子串,每个子串相对有完整的语义,便于学习embedding表达和后续模型的使用。tokenize有三种粒度:word/subword/charword词,是最自然的语言单元。对于英文等自然语言来说,存在着天然的分隔符,比如说空格,或者是一些标点符号,对词的切分相对容易。但是对于一些东亚文字包括中文来说,就需要某种分词算法才行。顺便说一下,Tokenizers库中,基于规则切分部分,采用了spaCy和Moses两个库。如果基于词来做词汇表,由于长尾现象的存在,这个词汇表可能会超大。像Transformer XL库就用到了一个26.7万个单词的词汇表。这需要极大的embedding matrix才能存得下。embedding matrix是用于查找取用token的embedding vector的。这对于内存或者显存都是极大的挑战。常规的词汇表,一般大小不超过5万。char/字符, 也就是说,我们的词汇表里只有最基本的字符。而一般来讲,字符的数量是少量有限的。这样做的问题是,由于字符数量太小,我们在为每个字符学习嵌入向量的时候,每个向量就容纳了太多的语义在内,学习起来非常困难。subword子词级,它介于字符和单词之间。比如说Transformers可能会被分成Transform和ers两个部分。这个方案平衡了词汇量和语义独立性,是相对较优的方案。它的处理原则是,常用词应该保持原状,生僻词应该拆分成子词以共享token压缩空间。2. 常用tokenize算法最常用的三种tokenize算法:BPE(Byte-Pair Encoding),WordPiece和SentencePiece2.1 Byte-Pair Encoding (BPE) / Byte-level BPE2.1.1 BPE首先,它依赖于一种预分词器pretokenizer来完成初步的切分。pretokenizer可以是简单基于空格的,也可以是基于规则的;分词之后,统计每个词出现的频次供后续计算使用。例如,我们统计到了5个词的词频("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)建立基础词汇表,包括所有的字符,即:["b", "g", "h", "n", "p", "s", "u"]根据规则,我们分别考察2-gram,3-gram的基本字符组合,把高频的ngram组合依次加入到词汇表当中,直到词汇表达到预定大小停止。比如,我们计算出ug/un/hug三种组合出现频次分别为20,16和15,加入到词汇表中。最终词汇表的大小 = 基础字符词汇表大小 + 合并串的数量,比如像GPT,它的词汇表大小 40478 = 478(基础字符) + 40000(merges)。添加完后,我们词汇表变成:["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"]实际使用中,如果遇到未知字符用代表。2.1.2 Byte-level BPEBPE的一个问题是,如果遇到了unicode,基本字符集可能会很大。一种处理方法是我们以一个字节为一种“字符”,不管实际字符集用了几个字节来表示一个字符。这样的话,基础字符集的大小就锁定在了256。例如,像GPT-2的词汇表大小为50257 = 256 + + 50000 mergers,是句子结尾的特殊标记。2.2 WordPieceWordPiece,从名字好理解,它是一种子词粒度的tokenize算法subword tokenization algorithm,很多著名的Transformers模型,比如BERT/DistilBERT/Electra都使用了它。它的原理非常接近BPE,不同之处在于,它在做合并的时候,并不是每次找最高频的组合,而是找能够最大化训练集数据似然的merge,即它每次合并的两个字符串A和B,应该具有最大的 \frac{P(AB)}{P(A)P(B)} 值。合并AB之后,所有原来切成A+B两个tokens的就只保留AB一个token,整个训练集上最大似然变化量与 \frac{P(AB)}{P(A)P(B)} 成正比。2.3 Unigram与BPE或者WordPiece不同,Unigram的算法思想是从一个巨大的词汇表出发,再逐渐删除trim down其中的词汇,直到size满足预定义。初始的词汇表可以采用所有预分词器分出来的词,再加上所有高频的子串。每次从词汇表中删除词汇的原则是使预定义的损失最小。训练时,计算loss的公式为: Loss=-\sum_{i=1}^Nlog(\sum_{x\in S(x_i)}p(x)) 假设训练文档中的所有词分别为 x_1;x_2...x_N ,而每个词tokenize的方法是一个集合 S(x_i) 。当一个词汇表确定时,每个词tokenize的方法集合 S(x_i) 就是确定的,而每种方法对应着一个概率p(x)。如果从词汇表中删除部分词,则某些词的tokenize的种类集合就会变少,log(*)中的求和项就会减少,从而增加整体loss。Unigram算法每次会从词汇表中挑出使得loss增长最小的10%~20%的词汇来删除。一般Unigram算法会与SentencePiece算法连用。2.4 SentencePieceSentencePiece,顾名思义,它是把一个句子看作一个整体,再拆成片段,而没有保留天然的词语的概念。一般地,它把空格space也当作一种特殊字符来处理,再用BPE或者Unigram算法来构造词汇表。比如,XLNetTokenizer就采用了_来代替空格,解码的时候会再用空格替换回来。目前,Tokenizers库中,所有使用了SentencePiece的都是与Unigram算法联合使用的,比如ALBERT、XLNet、Marian和T5.3. 切分实例与代码分析3.1 BertTokenizer / WordPiece先试一个BertTokenizer,它基于WordPiece算法,base版本的词汇表大小为21128.from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')

tokens = t.encode(...).tokens复制切分效果为:Tokenizer:

Text: The problems of your past are your business. The problems of your future are my privilege.

Tokens: [UNK],pro,##ble,##ms,of,your,pa,##st,are,your,business,.,[UNK],pro,##ble,##ms,of,your,future,are,my,pr,##i,##vi,##le,##ge,.

Text: 你的过去我不愿过问,那是你的事情。你的未来我希望参与,这是我的荣幸。

Tokens: 你,的,过,去,我,不,愿,过,问,,,那,是,你,的,事,情,。,你,的,未,来,我,希,望,参,与,,,这,是,我,的,荣,幸,。

Text: Don’t make the user feel stupid.

Tokens: [UNK],[UNK],t,make,the,user,feel,st,##up,##id,.

Text: 中国语言研究院正式宣布,“笔画最多的汉字”的桂冠属于“龖(dá)”字!

Tokens: 中,国,语,言,研,究,院,正,式,宣,布,,,[UNK],笔,画,最,多,的,汉,字,[UNK],的,桂,冠,属,于,[UNK],[UNK],(,[UNK],),[UNK],字,!其中,BertTokenizer中,用##符号表示非开头的子词,比如第1句中的problems被拆分成了三部分,pro/##ble/##ms;标点符号、生僻字等未出现的token被[UNK]代替中文基本拆分成了字的形式,并没有看到多字词的形式分词流程与代码分析如下:BertTokenizer类关系如下在代码中查看主要做了两件事情:根据参数控制来对输入文本做基础分词(basic_tokenizer)对于切分出来的单个词,再切分(wordpiece_tokenizer)basic_tokenizer 是把句子切分成词,仍然可以对着代码看一下:特别要注意的在 401 行:如果 tokenize_chinese_chars 参数为 True,那么所有的中文词都会被切成字符级别!!!参数传来的 never_split 并不会让这些中文词不被切分。wordpiece_tokenizer 则是将词切成字符级别,例如 doing->['do', '###ing']。这里的做法就是把一个词送入 BERT 中做最大匹配(类似于 Jieba 分词的正向最大匹配算法),如果前面已经有匹配,则后面的词都会加 ’##‘。而中文,因为已经在上一步被切分成字符级别,所以不会有任何改变。3.2 T5Tokenizer / SentencePieceT5模型是基于SentencePiece的,我们看看它的切分效果。我用的这个版本词汇表大小是250112。Tokenizer:

Text: The problems of your past are your business. The problems of your future are my privilege.

Tokens: ▁The,▁problems,▁of,▁your,▁past,▁are,▁your,▁business,.,▁The,▁problems,▁of,▁your,▁future,▁are,▁my,▁,privilege,.

Text: 你的过去我不愿过问,那是你的事情。你的未来我希望参与,这是我的荣幸。

Tokens: ▁,你的,过去,我不,愿,过,问,,,那是,你,的事情,。,你的,未来,我,希望,参与,,,这是,我的,荣,幸,。

Text: Don’t make the user feel stupid.

Tokens: ▁Don,’,t,▁make,▁the,▁user,▁feel,▁stupid,.

Text: 中国语言研究院正式宣布,“笔画最多的汉字”的桂冠属于“龖(dá)”字!

Tokens: ▁,中国,语言,研究院,正式,宣布,,“,笔,画,最多,的,汉,字,”,的,桂,冠,属于,“,<0xE9>,<0xBE>,<0x96>,(,dá,),”,字,!其中,最明显的,可以看到下划线被引入,代替了空格和句子开头特殊符号中文可以看到一些多字词,比如“未来”,“研究院”等,但有些词其实不符合一般的分词习惯,比如“的事情”、“我不”等等生僻字龖被拆成了三个基础字节形式的tokenRefhttps://zhuanlan.zhihu.com/p/371300063https://blog.csdn.net/iterate7/article/details/108959082https://zhuanlan.zhihu.com/p/268515387https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/37842.pdfstatic.googleusercontent.com/media/research.google.com/ja//pubs/archive/37842.pdfhttps://arxiv.org/pdf/1804.10959.pdf​arxiv.org/pdf/1804.10959.pdf原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。如有侵权,请联系 cloudcommunity@tencent.com 删除。机器学习机器学习平台深度学习中文分词NLP 服务原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。如有侵权,请联系 cloudcommunity@tencent.com 删除。机器学习机器学习平台深度学习中文分词NLP 服务#BERT#NLP#GPT#tokenize#ML评论登录后参与评论0 条评论热度最新登录 后参与评论推荐阅读LV.关注文章0获赞0目录2. 常用tokenize算法2.1 Byte-Pair Encoding (BPE) / Byte-level BPE2.1.1 BPE2.1.2 Byte-level BPE2.2 WordPiece2.3 Unigram2.4 SentencePiece3. 切分实例与代码分析3.1 BertTokenizer / WordPiece3.2 T5Tokenizer / SentencePieceRef相关产品与服务NLP 服务NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。产品介绍产品文档2024新春采购节领券社区专栏文章阅读清单互动问答技术沙龙技术视频团队主页腾讯云TI平台活动自媒体分享计划邀请作者入驻自荐上首页技术竞赛资源技术周刊社区标签开发者手册开发者实验室关于社区规范免责声明联系我们友情链接腾讯云开发者扫码关注腾讯云开发者领取腾讯云代金券热门产品域名注册云服务器区块链服务消息队列网络加速云数据库域名解析云存储视频直播热门推荐人脸识别腾讯会议企业云CDN加速视频通话图像分析MySQL 数据库SSL 证书语音识别更多推荐数据安全负载均衡短信文字识别云点播商标注册小程序开发网站监控数据迁移Copyright © 2013 - 2024 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有 深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569腾讯云计算(北京)有限责任公司 京ICP证150476号 |  京ICP备11018762号 | 京公网安备号11010802020287问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档Copyright © 2013 - 2024 Tencent Cloud.All Rights Reserved. 腾讯云 版权所有登录 后参与评论00

【LLM系列之Tokenizer】如何科学地训练一个LLM分词器-腾讯云开发者社区-腾讯云

系列之Tokenizer】如何科学地训练一个LLM分词器-腾讯云开发者社区-腾讯云致Great【LLM系列之Tokenizer】如何科学地训练一个LLM分词器关注作者腾讯云开发者社区文档建议反馈控制台首页学习活动专区工具TVP最新优惠活动文章/答案/技术大牛搜索搜索关闭发布登录/注册首页学习活动专区工具TVP最新优惠活动返回腾讯云官网致Great首页学习活动专区工具TVP最新优惠活动返回腾讯云官网社区首页 >专栏 >【LLM系列之Tokenizer】如何科学地训练一个LLM分词器【LLM系列之Tokenizer】如何科学地训练一个LLM分词器致Great关注发布于 2023-08-25 14:53:131.1K0发布于 2023-08-25 14:53:13举报文章被收录于专栏:程序生活程序生活1 背景与基础1.1 为什么需要分词对于人而言,在我们学会阅读之前,仍然可以理解语言。比如当你开始上学时,即使你不知道名词和动词之间的区别,但是你已经可以和你的同学交谈了,比如“我喜欢吃香蕉”,孩子对于这些虽然不清楚,但是知道是什么意思的。在此刻,我们学会了把语音/语言变成一种书面语言,这样你就可以读写了。一旦你学会了将文本转换为声音,你就可以回忆使用之前学过的词义库。 计算机(即语言模型 (LM) 或查找程序 (WordNet))在学习阅读之前不会学习说话,因此它们无法依赖以前学习过的词义记忆库。他们需要找到另一种发现词义的方法。机器没有这种语音先机。在对语言一无所知的情况下,我们需要开发系统,使它们能够处理文本,而无需像人类那样已经能够将声音与单词的含义联系起来的能力。这是经典的“先有鸡还是先有蛋”的问题:如果机器对语法、声音、单词或句子一无所知,它们如何开始处理文本?您可以创建规则来告诉机器处理文本,按照词典库对查找所需要的词。但是,在这种情况下,机器不会学习任何东西,您需要有一个静态数据集,其中包含每个可能的单词组合及其所有语法变体。我们不是训练机器查找固定的词典,而是要教机器识别和“阅读”文本,使其可以从这个动作本身中学习。换句话说,它读得越多,学得越多。人类通过利用他们以前学习语音的方式来做到这一点。机器不具备可利用的这些知识,因此需要告知它们如何将文本分解为标准单元以进行处理。他们使用一种称为“标记化”的系统来做到这一点,在该系统中,文本序列被分成更小的部分或“Token”,然后作为输入输入到像 BERT 这样的 DL NLP 模型中。但是,在我们查看我们可以对文本进行分词的不同方式之前,让我们首先看看我们是否真的需要使用分词。为了训练像 BERT 或GPT-2这样的 DL 模型在 NLP 任务中表现出色,我们需要为其提供大量文本。希望通过架构的特定设计,模型将学习一定程度的句法或语义理解。关于这些模型学习的语义理解水平仍然是一个活跃的研究领域。人们认为他们在神经网络的较低级别学习句法知识,然后在他们开始研究更具体的语言领域信号(例如医学与技术培训文本)时在较高级别学习语义知识。使用的特定架构类型将对模型可以处理的任务、学习的速度以及执行情况产生重大影响。例如,GPT2 使用解码器架构,因为它的任务是预测序列中的下一个单词。相比之下,BERT 使用编码器类型的架构,因为它经过训练可用于更大范围的 NLP 任务,例如下一句预测、问答检索和分类。不管它们是如何设计的,它们都需要通过输入层输入文本才能执行任何类型的学习。

一种简单的方法是简单地输入训练数据集中出现的文本。这听起来很容易,但有一个问题。我们需要找到一种方法来以数学方式表示单词,以便神经网络对其进行处理。请记住,这些模型没有语言知识。因此,如果他们对语言结构一无所知,就无法从文本中学习。它对模型来说就像是乱码,它不会学到任何东西。它不会理解一个词从哪里开始,另一个词从哪里结束。它甚至不知道什么是单词。我们通过首先学习理解口头语言然后学习将语音与书面文本联系起来来解决这个问题。所以我们需要找到一种方法来做两件事,以便能够将我们的文本训练数据输入到我们的 DL 模型中,下面就是我们为什么需要分词的主要原因:将输入分成更小的块:模型对语言结构一无所知,因此我们需要在将其输入模型之前将其分成块或标记。将输入表示为向量:我们希望模型学习句子或文本序列中单词之间的关系。我们不想将语法规则编码到模型中,因为它们会受到限制并且需要专业的语言知识。相反,我们希望模型学习关系本身并发现某种理解语言的方法。为此,我们需要将标记编码为向量,其中模型可以在这些向量的任何维度中编码含义。它们可以用作输出,因为它们代表单词的上下文参考。或者,它们可以作为更高级别

NLP 任务(例如文本分类)的输入或用于迁移学习而馈送到其他层。1.2 分词粒度介绍在使用GPT BERT模型输入词语常常会先进行tokenize ,tokenize具体目标与粒度是什么呢?tokenize也有许多类别及优缺点,这篇文章总结一下各个方法及实际案例。tokenize的目标是把输入的文本流,切分成一个个子串,每个子串相对有完整的语义,便于学习embedding表达和后续模型的使用。tokenize有三种粒度:word/subword/charword级别word/词,词,是最自然的语言单元。对于英文等自然语言来说,存在着天然的分隔符,如空格或一些标点符号等,对词的切分相对容易。但是对于一些东亚文字包括中文来说,就需要某种分词算法才行。顺便说一下,Tokenizers库中,基于规则切分部分,采用了spaCy和Moses两个库。如果基于词来做词汇表,由于长尾现象的存在,这个词汇表可能会超大。像Transformer XL库就用到了一个26.7万个单词的词汇表。这需要极大的embedding matrix才能存得下。embedding matrix是用于查找取用token的embedding vector的。这对于内存或者显存都是极大的挑战。常规的词汇表,一般大小不超过5万。

基于词粒度的Tokenization优缺点优点:词粒度很像人类去阅读一样,一方面能够很好地保留词的边界信息,另一方面能够很好地保留词的含义。缺点:(1)词粒度的方法,需要构造的词典太过庞大,严重影响计算效率和消耗内存。(2)即使使用这么大的词典不影响效率,也会造成 OOV 问题。因为人类语言是不断发展的,词汇也在发展中不断增加。例如:针不戳,Niubility,Sixology 等。 (3)词表中的低频词/稀疏词在模型训练过程中无法得到充分训练,进而模型不能充分理解这些词的语义。(4)一个单词因为不同的形态会产生不同的词,如由“look”衍生出的“looks”, “looking”, 但是意义相近,对他们都进行训练是不必要的。字符级别char/字符,即最基本的字符,如英语中的’a’,‘b’,‘c’或中文中的’你’,‘我’,'他’等。而一般来讲,字符的数量是少量有限的。这样做的问题是,由于字符数量太小,我们在为每个字符学习嵌入向量的时候,每个向量就容纳了太多的语义在内,学习起来非常困难。

基于字符粒度的Tokenization优缺点优点:它的优点是,词表大大减小,26 个英文字母基本能覆盖出几乎所有词,5000 多个中文基本也能组合出覆盖的词汇。缺点: 这种方法严重丢失了词汇的语义信息和边界信息,这对 NER 等关注词汇边界的任务来说会有一定的影响。而且把单词切分的太细,会使得输入太过长增加输入计算压力,减小词表的代价就是输入长度大大增加,从而输入计算变得更耗时,训练时更占内存空间。子词级别subword/子词级,它介于字符和单词之间。比如说’Transformers’可能会被分成’Transform’和’ers’两个部分。这个方案平衡了词汇量和语义独立性,是相对较优的方案。它的处理原则是,常用词应该保持原状,生僻词应该拆分成子词以共享token压缩空间。

2 常用tokenize算法最常用的三种tokenize算法:BPE(Byte-Pair Encoding),WordPiece和SentencePiece

2.1 BPEBPE 全称 Byte Pair Encoding,字节对编码,是一种数据压缩方法。最早是论文 [1] 将其引入到 NLP 技术中。BPE 迭代地合并最频繁出现的字符或字符序列,具体步骤:

举一个例子,有一个段文本““FloydHub is the fastest way to build, train and deploy deep learning models. Build deep learning models in the cloud. Train deep learning models.””首先让我们看看单个单词出现的频率。本文中的单词出现频率如下:

可以看到的是每个单词末尾都有一个“ ”标记。这是为了识别单词边界,以便算法知道每个单词结束的位置。这一点很重要,因为子词算法会查看文本中的每个字符并尝试找到频率最高的字符对。BPE 子词算法的主要目标是找到一种方法来用最少的标记表示整个文本数据集。与压缩算法类似,我妈们希望找到表示图像、文本或您正在编码的任何内容的最佳方式,它使用最少的数据量,或者在我们的例子中是令牌。在 BPE 算法中,合并是我们尝试将文本“压缩”为子词单元的方式。合并通过识别最常表示的字节对来实现。在我们的示例中,一个字符与一个字节相同,但情况并非总是如此,例如,在某些语言中,一个字符将由多个字节表示。但出于我们的目的,并且为了简单起见,字节对和字符对是相同的。这些合并操作有几个步骤():获取单词计数频率获取初始token计数和频率(即每个字符出现多少次)合并最常见的字节对将其添加到token列表并重新计算每个token的频率计数;这将随着每个合并步骤而改变清洗去重,直到达到定义的令牌限制或设定的迭代次数(如我们的示例所示)

在一次迭代之后,我们最频繁的字符对是“ d ”和“ e ”。因此,我们将这些结合起来创建了我们的第一个子词标记(不是单个字符)“ de ”。我们是如何计算的?如果你还记得我们之前计算的词频,你会发现“ de ”是最常见的配对。

如果你把“ de ”出现的单词的频率加起来,你会得到 3 + 2 + 1 + 1 = 7,这就是我们新的“ de ”标记的频率。由于“ de ”是一个新token,我们需要重新计算所有标记的计数。我们通过从合并操作之前的单个字符的频率中减去新的“ de ”标记的频率 7 来实现这一点。如果我们考虑一下,这是有道理的。我们刚刚创建了一个新的token“ de ”。这在我们的数据集中出现了 7 次。现在我们只想计算“ d ”和“ e ”未配对时出现的次数。为此,我们从“ e”的原始出现频率中减去 7”,16,得到 9。我们从“ d ”的原始频率,12 中减去 7,得到 5,可以在“迭代 1”表中看到这一点。让我们再做一次迭代,看看下一个最频繁的字符对是什么:

同样,我们添加了一个新字符,使字符数量达到 29,因此我们实际上在 2 次迭代后增加了字符数量。这很常见;当我们开始创建新的合并对时,字符的数量会增加,但随着我们将它们组合在一起并删除其他字符,字符的数量会开始减少。当我们在这里进行不同的迭代时,我们可以看到这个数字发生变化:

正如上图所看到的,当我们开始合并时,词汇的数量最初会增加。然后它在 34 处达到峰值并开始下降。此时子词单元开始合并,我们开始消除一个或两个合并对。然后,我们将字符构建成一种格式,该格式可以以最有效的方式表示整个数据集。对于我们这里的例子,我们在 70 次迭代和 18 个标记处停止。事实上,我们已经从单个字符标记的起点重新创建了原始单词。最终的词汇列表如下所示:

这看起来很熟悉吗?确实是这样的,这就是我们一开始开始使用的原始单词列表。那么我们做了什么?我们通过从单个字符开始并在多次迭代中合并最频繁的字节对标记来重新创建原始单词列表(如果使用较小的迭代,将看到不同的标记列表)。虽然这看起来毫无意义,但记住这是一个demo数据集,目标是展示子词标记化所采取的步骤。在现实世界的例子中,数据集的词汇量应该大得多,那么你将无法为词汇表中的每个单词都分配一个字符。代码实现import re

import collections

class BytePairEncoder:

def __init__(self):

self.merges = None

self.characters = None

self.tokens = None

self.vocab = None

def format_word(self, text, space_token='_'):

return ' '.join(list(text)) + ' ' + space_token

def initialize_vocab(self, text):

text = re.sub('\s+', ' ', text)

all_words = text.split()

vocab = {}

for word in all_words:

word = self.format_word(word)

vocab[word] = vocab.get(word, 0) + 1

tokens = collections.Counter(text)

return vocab, tokens

def get_bigram_counts(self, vocab):

pairs = {}

for word, count in vocab.items():

symbols = word.split()

for i in range(len(symbols)-1):

pair = (symbols[i], symbols[i+1])

pairs[pair] = pairs.get(pair, 0) + count

return pairs

def merge_vocab(self, pair, vocab_in):

vocab_out = {}

bigram = re.escape(' '.join(pair))

p = re.compile(r'(?

bytepair = ''.join(pair)

for word in vocab_in:

w_out = p.sub(bytepair, word)

vocab_out[w_out] = vocab_in[word]

return vocab_out, (bigram, bytepair)

def find_merges(self, vocab, tokens, num_merges):

merges = []

for i in range(num_merges):

pairs = self.get_bigram_counts(vocab)

best_pair = max(pairs, key=pairs.get)

best_count = pairs[best_pair]

vocab, (bigram, bytepair) = self.merge_vocab(best_pair, vocab)

merges.append((r'(?

tokens[bytepair] = best_count

return vocab, tokens, merges

def fit(self, text, num_merges):

vocab, tokens = self.initialize_vocab(text)

self.characters = set(tokens.keys())

self.vocab, self.tokens, self.merges = self.find_merges(vocab, tokens, num_merges)复制2.2 WordPieceWordPiece 最早在《Japanese and korean voice search》中提出,并应用于解决日语和韩语语音问题。它与 BPE 相同点:每次从统计语料中选取出两个新的子词进行合并。**它与 BPE 最大区别在于选择两个子词进行合并的原则:BPE 按频率,WordPiece 按能够使得 LM 概率最大的相邻子词加入词表。 **对于 WordPiece 构造词表的原理如下:

假设由句子s=\{t_1,t_2,t_3,...,t_n\} 由n个子词组成, t_i表示第i 个子词,且假设子词之间是相互独立的,那么句子 s的语言模型对数似然值为:

假设把相邻的t_i和 t_j两个子词合并,产生t_x子词,此时句子的对数似然值增益为:

两个子词合并前后的对数似然值增益等于t_x和t_it_j 的互信息。所以,WordPiece 每次选择合并的两个子词,具有最大的互信息值,从语言模型上来说两个子词之间有很强的关联性,从语料上来说两个子词共现概率比较高。

WordPiece 的算法步骤如下:2.3 UniLMUnigram 语言建模首先在 《 Improving neural network translation models with multiple subword candidates》 中提出。这种方法与 WordPiece 相同点是:同样使用语言模型来挑选子词。与 WordPiece 最大区别:WordPiece 算法的词表大小都是从小到大变化。UniLM 的词库则是从大到小变化,即先初始化一个大词表,根据评估准则不断丢弃词表,直到满足限定条件。ULM 算法考虑了句子的不同分词可能,因而能够输出带概率的多个子词分段。对于 UniLM 构造词表的原理如下:

对于句子s ,假如存在一种子词切分结果为 s=\{t_1,t_2,t_3,...,t_n\} 则当前分词下句子s的对数似然值可以表示为:

对于句子s,挑选似然值最大的作为分词结果,即:

s^*为最优切分结果。

UniLM 构造词典的算法步骤如下:

可以看出,UniLM 会保留那些以较高频率出现在很多句子的分词结果中的子词,因为这些子词如果被丢弃,其损失会很大。到这里我们喘口气,谁想到深度学习 NLP 过程的这一部分会如此困难?这只是这些模型的第一步!现在,简要总结一下:BPE:只是使用出现的频率来识别每次迭代的最佳匹配,直到它达到预定义的词汇量大小。WordPiece:类似于 BPE,使用频率出现来识别潜在的合并,但根据合并令牌的可能性做出最终决定Unigram:不使用频率出现的完全概率模型。相反,它使用概率模型训练

LM,删除提高整体可能性最少的标记,然后重新开始,直到达到最终标记限制。

2.4 SentencePiece以上三种方法都存在着两个问题就是:1)无法逆转;2)训练的时候需要提前切分。无法逆转是什么意思呢,就是对句子 s 进行切分后得到的结果无法准确复原回 s。更直白地说就是空格不能被保留,如下:到此,我们今天主角登场!

而 SentencePiece 的解决方法是: SentencePiece 首先将所有输入转换为 unicode 字符。这意味着它不必担心不同的语言、字符或符号,可以以相同的方式处理所有输入;

空白也被当作普通符号来处理。Sentencepiece显式地将空白作为基本标记来处理,用一个元符号 “▁”( U+2581 )转义空白,这样就可以实现简单地decoding;

Sentencepiece 可以直接从 raw text 进行训练;

支持 BPE 和 UniLM 训练方法。

SentencePiece 由谷歌将一些词-语言模型相关的论文进行复现,开发了一个开源工具——训练自己领域的SentencePiece 模型,该模型可以代替预训练模型(BERT,XLNET)中词表的作用。开源代码地址为:https://github.com/google/sentencepiece。其原理就相当于:提供四种关于词的切分方法。这里跟中文的分词作用是一样的,但从思路上还是有区分的。通过使用我感觉:在中文上,就是把经常在一起出现的字组合成一个词语;在英文上,它会把英语单词切分更小的语义单元,减少词表的数量。例如“机器学习领域“这个文本,按jieba会分“机器/学习/领域”,但你想要粒度更大的切分效果,如“机器学习/领域”或者不切分,这样更有利于模型捕捉更多N-gram特征。为实现这个,你可能想到把对应的大粒度词加到词表中就可以解决,但是添加这类词是很消耗人力。然而对于该问题,sentencepiece可以得到一定程度解决,甚至完美解决你的需求。模型在训练中主要使用统计指标,比如出现的频率,左右连接度等,还有困惑度来训练最终的结果,论文题目为:《SentencePiece: A simple and language independent subword tokenizer

and detokenizer for Neural Text Processing》,地址为:https://arxiv.org/pdf/1808.06226.pdfSentencePiece 的训练目标如下。我们希望最大化对数似然

其中x是 unigram 序列,S( x ) 表示所有可能序列的集合。同样,这些是隐藏变量,我们只看到未标记的语料库!为了解决这个问题,我们采用了 EM 类型的算法。如果熟悉 EM,你会注意到这些步骤实际上是倒退的,我们采用 ME 方法。尽管名字很花哨,但它实际上非常直观和直接。步骤是:初始化一元概率。记住 P( x ) = P(x_1)…P(x_n) 所以一旦我们有了

unigrams,我们就有了任何序列的概率。在我们的代码中,我们只是使用 BPE 频率计数来更接近目标。M-step:计算给定当前概率的最可能的一元序列。这定义了单个标记化。实现这一点需要一些思考。E-step:给定当前标记化,通过计算标记化中所有子词的出现次数来重新计算一元概率。一元组概率就是该一元组出现的频率。实际上,将其贝叶斯化并改为计算并不困难

这里,c_i 是当前标记化中子词(unigram)i 的计数。M 是子词的总数。Psi 是双伽马函数。箭头表示我们如何进行贝叶斯化。重复步骤 2 和 3 直到收敛。理论上保证对数似然单调增加,所以如果不是这样,你就错了。3 训练SentencePiece分词模型实现代码可以见: https://github.com/google/sentencepiece

3.1 训练 BPE 模型# train sentencepiece model from our blog corpus

spm.SentencePieceTrainer.train('--model_type=bpe --input=blog_test.txt --model_prefix=bpe --vocab_size=500 --normalization_rule_tsv=normalization_rule.tsv')复制训练完模型后,加载它就可以开始使用了!# makes segmenter instance and loads the BPE model file (bpe.model)

sp_bpe = spm.SentencePieceProcessor()

sp_bpe.load('bpe.model')复制3.2 训练 Unigram 模型可以采用与 BPE 模型大致相同的方式训练 Unigram 模型。# train sentencepiece model from our blog corpus

spm.SentencePieceTrainer.train('--model_type=unigram --input=blog_test.txt --model_prefix=uni --vocab_size=500 --normalization_rule_tsv=normalization_rule.tsv')

# makes segmenter instance and loads the BPE model file (bpe.model)

sp_uni = spm.SentencePieceProcessor()

sp_uni.load('uni.model')复制3.3 对比两种模型可以通过调用“encode_as_pieces”函数使用训练好的子词模型对句子进行编码。我们对句子进行编码:“This is a test”。print("BPE: {}".format(sp_bpe.encode_as_pieces('This is a test')))

print("UNI: {}".format(sp_uni.encode_as_pieces('This is a test')))复制输出:BPE: ['▁This', '▁is', '▁a', '▁t', 'est']

UNI: ['▁Thi', 's', '▁is', '▁a', '▁t', 'est']复制3.4 查看所有的token可以运行以下代码以查看完整词汇列表vocabs = [sp_bpe.id_to_piece(id) for id in range(sp_bpe.get_piece_size())]

bpe_tokens = sorted(vocabs, key=lambda x: len(x), reverse=True)

bpe_tokens复制输出如下:['▁something',

'▁because',

'▁thought',

'▁really',

.

.

.

'9',

'*',

'8',

'6',

'7',

'$']复制3.5 HuggingFace TokenizersHuggingFace的Tokenizers也实现了分词算法,具体使用可以参考如下:from tokenizers import (ByteLevelBPETokenizer,

BPETokenizer,

SentencePieceBPETokenizer,

BertWordPieceTokenizer)

tokenizer = SentencePieceBPETokenizer()

tokenizer.train(["../blog_test.txt"], vocab_size=500, min_frequency=2)

output = tokenizer.encode("This is a test")

print(output.tokens)`复制4 如何训练一个LLM分词器SentencePiece的核心参数如下:"""

sentencepiece 参数

trainer_spec {

input: data/corpus.txt

input_format: #

model_prefix: open_llama # 模型输出路径

model_type: BPE # 模型类型 bpe、char、word、unigram(gram)

vocab_size: 50000 # 词汇表大小,数量越大训练越慢,太小(<4000)可能训练不了

self_test_sample_size: 0

character_coverage: 0.9995 # 模型中覆盖的字符数

input_sentence_size: 0

shuffle_input_sentence: 0

seed_sentencepiece_size: 1000000 #

shrinking_factor: 0.75

max_sentence_length: 16384 # 最大句子长度,默认是4192,长度按照字节计算,一个中文代表长度为2

num_threads: 16 # 进程个数

num_sub_iterations: 2

max_sentencepiece_length: 16

split_by_unicode_script: 1

split_by_number: 1

split_by_whitespace: 1

split_digits: 1

pretokenization_delimiter:

treat_whitespace_as_suffix: 0

allow_whitespace_only_pieces: 1

required_chars:

byte_fallback: 1

vocabulary_output_piece_score: 1

train_extremely_large_corpus: 1

hard_vocab_limit: 1

use_all_vocab: 0 # 使用

unk_id: 0

bos_id: 1

eos_id: 2

pad_id: 3

}

normalizer_spec {

name: nfkc

add_dummy_prefix: 1

remove_extra_whitespaces: 0

escape_whitespaces: 1

normalization_rule_tsv:

}

"""复制下面是我基于一个中文wiki语料(1.4GB)左右训练的sp模型例子:

import time

import sentencepiece as spm

start_time = time.time()

spm.SentencePieceTrainer.train(

input='data/corpus.txt', # 输入文件

model_prefix='open_llama', # 模型前缀

shuffle_input_sentence=False, # 是否打乱句子

train_extremely_large_corpus=True,

# hyperparameters of tokenizer

max_sentence_length=16384, # 句子最大长度

pad_id=3,

model_type="BPE",

vocab_size=50000,

split_digits=True,

split_by_unicode_script=True,

byte_fallback=True,

allow_whitespace_only_pieces=True,

remove_extra_whitespaces=False,

normalization_rule_name="nfkc",

)

end_time = time.time()

print(end_time - start_time)复制熟悉LLaMA模型的同学知道,LLaMA模型预训练中文语料特别少,并且中文测试效果比较差,在做中文增量的时候,我们可以将自己在中文训练语料训练的分词模型和原版llama分词模型合并:#!/usr/bin/env python

# -*- coding:utf-8 _*-

"""

@author:quincy qiang

@license: Apache Licence

@file: step4_merge_tokenizers.py

@time: 2023/05/19

@contact: yanqiangmiffy@gamil.com

@software: PyCharm

@description: coding..

"""

from sentencepiece import sentencepiece_model_pb2 as model

''' Merge tokenizer '''

orig_model_path = '/path/to/llama/tokenizer.model'

belle_model_path = '/path/to/belle/belle.model'

orig_m = model.ModelProto()

belle_m = model.ModelProto()

orig_m.ParseFromString(open(orig_model_path, "rb").read())

belle_m.ParseFromString(open(belle_model_path, "rb").read())

print(len(orig_m.pieces), len(belle_m.pieces))

orig_pieces = []

for piece in orig_m.pieces:

orig_pieces.append(piece.piece)

for piece in belle_m.pieces:

if piece.piece not in orig_pieces:

orig_m.pieces.append(piece)

orig_pieces.append(piece.piece)

print(len(orig_m.pieces))

save_vocab_path = '/path/to/merge_tokenizer/tokenizer.model'

with open(save_vocab_path, 'wb') as f:

f.write(orig_m.SerializeToString())复制训练大模型分词器的笔者认为比较重要的因素是:

(1)词表大小,词表大小应该是和语料大小去匹配的,具体设置我们可以参考下ChatGLM、和一些Chinese-LLaMA模型,像ChatGLM词表大小有13万,其他Chinese-LLaMA模型基本上在5万-8万左右。词表大小设置是否合理直接影响了模型参数以及训练速度

(2) 语料尽量充沛,因为垂直领域语料以及特殊语料库与大的底座模型的词频统计差别挺大的,如果单纯用一个相对狭隘的语料库训练tokenizer,有可能切词出来的token和常见切词方式不太一样,不符合通用语义。

(3) 词汇量大小的选择取决于模型质量和效率之间的权衡。当模型参数量较大的时候,我们可以设置较大的词汇表,在语料充足的情况下完整代码:

https://github.com/yanqiangmiffy/how-to-train-tokenizer

参考资料BPE、WordPiece和SentencePieceNLP技术中的Tokenization本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。 原始发表:2023-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除前往查看编码模型数据算法LLM本文分享自 作者个人站点/博客 前往查看如有侵权,请联系 cloudcommunity@tencent.com 删除。本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!编码模型数据算法LLM评论登录后参与评论0 条评论热度最新登录 后参与评论推荐阅读LV.关注文章0获赞0目录1 背景与基础1.1 为什么需要分词1.2 分词粒度介绍word级别字符级别子词级别2 常用tokenize算法2.1 BPE2.2 WordPiece2.3 UniLM2.4 SentencePiece3 训练SentencePiece分词模型3.1 训练 BPE 模型3.2 训练 Unigram 模型3.3 对比两种模型3.4 查看所有的token3.5 HuggingFace Tokenizers4 如何训练一个LLM分词器参考资料领券社区专栏文章阅读清单互动问答技术沙龙技术视频团队主页腾讯云TI平台活动自媒体分享计划邀请作者入驻自荐上首页技术竞赛资源技术周刊社区标签开发者手册开发者实验室关于社区规范免责声明联系我们友情链接腾讯云开发者扫码关注腾讯云开发者领取腾讯云代金券热门产品域名注册云服务器区块链服务消息队列网络加速云数据库域名解析云存储视频直播热门推荐人脸识别腾讯会议企业云CDN加速视频通话图像分析MySQL 数据库SSL 证书语音识别更多推荐数据安全负载均衡短信文字识别云点播商标注册小程序开发网站监控数据迁移Copyright © 2013 - 2024 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有 深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569腾讯云计算(北京)有限责任公司 京ICP证150476号 |  京ICP备11018762号 | 京公网安备号11010802020287问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档Copyright © 2013 - 2024 Tencent Cloud.All Rights Reserved. 腾讯云 版权所有登录 后参与评论00

Tokenizing with TF Text  |  TensorFlow

Tokenizing with TF Text  |  TensorFlow

Install

Learn

Introduction

New to TensorFlow?

Tutorials

Learn how to use TensorFlow with end-to-end examples

Guide

Learn framework concepts and components

Learn ML

Educational resources to master your path with TensorFlow

API

TensorFlow (v2.15.0.post1)

Versions…

TensorFlow.js

TensorFlow Lite

TFX

Resources

LIBRARIES

TensorFlow.js

Develop web ML applications in JavaScript

TensorFlow Lite

Deploy ML on mobile, microcontrollers and other edge devices

TFX

Build production ML pipelines

All libraries

Create advanced models and extend TensorFlow

RESOURCES

Models & datasets

Pre-trained models and datasets built by Google and the community

Tools

Tools to support and accelerate TensorFlow workflows

Responsible AI

Resources for every stage of the ML workflow

Recommendation systems

Build recommendation systems with open source tools

Community

Groups

User groups, interest groups and mailing lists

Contribute

Guide for contributing to code and documentation

TensorFlow Certificate

Differentiate yourself by demonstrating your ML proficiency

Blog

Stay up to date with all things TensorFlow

Forum

Discussion platform for the TensorFlow community

Why TensorFlow

About

Case studies

English

Español – América Latina

Français

Indonesia

Italiano

Polski

Português – Brasil

Tiếng Việt

Türkçe

Русский

עברית

العربيّة

فارسی

हिंदी

বাংলা

ภาษาไทย

中文 – 简体

日本語

한국어

GitHub

Text

Overview

Tutorials

Guide

API

Install

Learn

More

API

More

Resources

More

Overview

Tutorials

Guide

API

Community

More

Why TensorFlow

More

GitHub

Overview

Keras NLP

Get started with KerasNLP

tf.strings

Work with Unicode

TensorFlow Text

Get started with TF-Text

Convert to TF Lite

Pre-processing

BERT preprocessing

Tokenize strings

Subword Tokenization

TensorFlow Models - NLP

Overview

Customize a transformer encoder

Load LM checkpoints

Introduction

Tutorials

Guide

Learn ML

TensorFlow (v2.15.0.post1)

Versions…

TensorFlow.js

TensorFlow Lite

TFX

LIBRARIES

TensorFlow.js

TensorFlow Lite

TFX

All libraries

RESOURCES

Models & datasets

Tools

Responsible AI

Recommendation systems

Groups

Contribute

TensorFlow Certificate

Blog

Forum

About

Case studies

TensorFlow

Resources

Text

Guide

Tokenizing with TF Text

View on TensorFlow.org

Run in Google Colab

View on GitHub

Download notebook

See TF Hub models

Overview

Tokenization is the process of breaking up a string into tokens. Commonly, these tokens are words, numbers, and/or punctuation. The tensorflow_text package provides a number of tokenizers available for preprocessing text required by your text-based models. By performing the tokenization in the TensorFlow graph, you will not need to worry about differences between the training and inference workflows and managing preprocessing scripts.

This guide discusses the many tokenization options provided by TensorFlow Text, when you might want to use one option over another, and how these tokenizers are called from within your model.

Setup

pip install -q "tensorflow-text==2.11.*"

import requests

import tensorflow as tf

import tensorflow_text as tf_text

2024-02-25 12:38:30.151517: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory

2024-02-25 12:38:30.965980: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory

2024-02-25 12:38:30.966064: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory

2024-02-25 12:38:30.966073: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.

Splitter API

The main interfaces are Splitter and SplitterWithOffsets which have single methods split and split_with_offsets. The SplitterWithOffsets variant (which extends Splitter) includes an option for getting byte offsets. This allows the caller to know which bytes in the original string the created token was created from.

The Tokenizer and TokenizerWithOffsets are specialized versions of the Splitter that provide the convenience methods tokenize and tokenize_with_offsets respectively.

Generally, for any N-dimensional input, the returned tokens are in a N+1-dimensional RaggedTensor with the inner-most dimension of tokens mapping to the original individual strings.

class Splitter {

@abstractmethod

def split(self, input)

}

class SplitterWithOffsets(Splitter) {

@abstractmethod

def split_with_offsets(self, input)

}

There is also a Detokenizer interface. Any tokenizer implementing this interface can accept a N-dimensional ragged tensor of tokens, and normally returns a N-1-dimensional tensor or ragged tensor that has the given tokens assembled together.

class Detokenizer {

@abstractmethod

def detokenize(self, input)

}

Tokenizers

Below is the suite of tokenizers provided by TensorFlow Text. String inputs are assumed to be UTF-8. Please review the Unicode guide for converting strings to UTF-8.

Whole word tokenizers

These tokenizers attempt to split a string by words, and is the most intuitive way to split text.

WhitespaceTokenizer

The text.WhitespaceTokenizer is the most basic tokenizer which splits strings on ICU defined whitespace characters (eg. space, tab, new line). This is often good for quickly building out prototype models.

tokenizer = tf_text.WhitespaceTokenizer()

tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])

print(tokens.to_list())

[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

2024-02-25 12:38:32.713724: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory

2024-02-25 12:38:32.713828: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcublas.so.11'; dlerror: libcublas.so.11: cannot open shared object file: No such file or directory

2024-02-25 12:38:32.713895: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcublasLt.so.11'; dlerror: libcublasLt.so.11: cannot open shared object file: No such file or directory

2024-02-25 12:38:32.713954: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcufft.so.10'; dlerror: libcufft.so.10: cannot open shared object file: No such file or directory

2024-02-25 12:38:32.771255: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcusparse.so.11'; dlerror: libcusparse.so.11: cannot open shared object file: No such file or directory

2024-02-25 12:38:32.771472: W tensorflow/core/common_runtime/gpu/gpu_device.cc:1934] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.

Skipping registering GPU devices...

You may notice a shortcome of this tokenizer is that punctuation is included with the word to make up a token. To split the words and punctuation into separate tokens, the UnicodeScriptTokenizer should be used.

UnicodeScriptTokenizer

The UnicodeScriptTokenizer splits strings based on Unicode script boundaries. The script codes used correspond to International Components for Unicode (ICU) UScriptCode values. See: http://icu-project.org/apiref/icu4c/uscript_8h.html

In practice, this is similar to the WhitespaceTokenizer with the most apparent difference being that it will split punctuation (USCRIPT_COMMON) from language texts (eg. USCRIPT_LATIN, USCRIPT_CYRILLIC, etc) while also separating language texts from each other. Note that this will also split contraction words into separate tokens.

tokenizer = tf_text.UnicodeScriptTokenizer()

tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])

print(tokens.to_list())

[[b'What', b'you', b'know', b'you', b'can', b"'", b't', b'explain', b',', b'but', b'you', b'feel', b'it', b'.']]

Subword tokenizers

Subword tokenizers can be used with a smaller vocabulary, and allow the model to have some information about novel words from the subwords that make create it.

We briefly discuss the Subword tokenization options below, but the Subword Tokenization tutorial goes more in depth and also explains how to generate the vocab files.

WordpieceTokenizer

WordPiece tokenization is a data-driven tokenization scheme which generates a set of sub-tokens. These sub tokens may correspond to linguistic morphemes, but this is often not the case.

The WordpieceTokenizer expects the input to already be split into tokens. Because of this prerequisite, you will often want to split using the WhitespaceTokenizer or UnicodeScriptTokenizer beforehand.

tokenizer = tf_text.WhitespaceTokenizer()

tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])

print(tokens.to_list())

[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

After the string is split into tokens, the WordpieceTokenizer can be used to split into subtokens.

url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_wp_en_vocab.txt?raw=true"

r = requests.get(url)

filepath = "vocab.txt"

open(filepath, 'wb').write(r.content)

52382

subtokenizer = tf_text.UnicodeScriptTokenizer(filepath)

subtokens = tokenizer.tokenize(tokens)

print(subtokens.to_list())

[[[b'What'], [b'you'], [b'know'], [b'you'], [b"can't"], [b'explain,'], [b'but'], [b'you'], [b'feel'], [b'it.']]]

BertTokenizer

The BertTokenizer mirrors the original implementation of tokenization from the BERT paper. This is backed by the WordpieceTokenizer, but also performs additional tasks such as normalization and tokenizing to words first.

tokenizer = tf_text.BertTokenizer(filepath, token_out_type=tf.string, lower_case=True)

tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])

print(tokens.to_list())

[[[b'what'], [b'you'], [b'know'], [b'you'], [b'can'], [b"'"], [b't'], [b'explain'], [b','], [b'but'], [b'you'], [b'feel'], [b'it'], [b'.']]]

SentencepieceTokenizer

The SentencepieceTokenizer is a sub-token tokenizer that is highly configurable. This is backed by the Sentencepiece library. Like the BertTokenizer, it can include normalization and token splitting before splitting into sub-tokens.

url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_oss_model.model?raw=true"

sp_model = requests.get(url).content

tokenizer = tf_text.SentencepieceTokenizer(sp_model, out_type=tf.string)

tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])

print(tokens.to_list())

[[b'\xe2\x96\x81What', b'\xe2\x96\x81you', b'\xe2\x96\x81know', b'\xe2\x96\x81you', b'\xe2\x96\x81can', b"'", b't', b'\xe2\x96\x81explain', b',', b'\xe2\x96\x81but', b'\xe2\x96\x81you', b'\xe2\x96\x81feel', b'\xe2\x96\x81it', b'.']]

Other splitters

UnicodeCharTokenizer

This splits a string into UTF-8 characters. It is useful for CJK languages that do not have spaces between words.

tokenizer = tf_text.UnicodeCharTokenizer()

tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])

print(tokens.to_list())

[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]]

The output is Unicode codepoints. This can be also useful for creating character ngrams, such as bigrams. To convert back into UTF-8 characters.

characters = tf.strings.unicode_encode(tf.expand_dims(tokens, -1), "UTF-8")

bigrams = tf_text.ngrams(characters, 2, reduction_type=tf_text.Reduction.STRING_JOIN, string_separator='')

print(bigrams.to_list())

[[b'Wh', b'ha', b'at', b't ', b' y', b'yo', b'ou', b'u ', b' k', b'kn', b'no', b'ow', b'w ', b' y', b'yo', b'ou', b'u ', b' c', b'ca', b'an', b"n'", b"'t", b't ', b' e', b'ex', b'xp', b'pl', b'la', b'ai', b'in', b'n,', b', ', b' b', b'bu', b'ut', b't ', b' y', b'yo', b'ou', b'u ', b' f', b'fe', b'ee', b'el', b'l ', b' i', b'it', b't.']]

HubModuleTokenizer

This is a wrapper around models deployed to TF Hub to make the calls easier since TF Hub currently does not support ragged tensors. Having a model perform tokenization is particularly useful for CJK languages when you want to split into words, but do not have spaces to provide a heuristic guide. At this time, we have a single segmentation model for Chinese.

MODEL_HANDLE = "https://tfhub.dev/google/zh_segmentation/1"

segmenter = tf_text.HubModuleTokenizer(MODEL_HANDLE)

tokens = segmenter.tokenize(["新华社北京"])

print(tokens.to_list())

[[b'\xe6\x96\xb0\xe5\x8d\x8e\xe7\xa4\xbe', b'\xe5\x8c\x97\xe4\xba\xac']]

It may be difficult to view the results of the UTF-8 encoded byte strings. Decode the list values to make viewing easier.

def decode_list(x):

if type(x) is list:

return list(map(decode_list, x))

return x.decode("UTF-8")

def decode_utf8_tensor(x):

return list(map(decode_list, x.to_list()))

print(decode_utf8_tensor(tokens))

[['新华社', '北京']]

SplitMergeTokenizer

The SplitMergeTokenizer & SplitMergeFromLogitsTokenizer have a targeted purpose of splitting a string based on provided values that indicate where the string should be split. This is useful when building your own segmentation models like the previous Segmentation example.

For the SplitMergeTokenizer, a value of 0 is used to indicate the start of a new string, and the value of 1 indicates the character is part of the current string.

strings = ["新华社北京"]

labels = [[0, 1, 1, 0, 1]]

tokenizer = tf_text.SplitMergeTokenizer()

tokens = tokenizer.tokenize(strings, labels)

print(decode_utf8_tensor(tokens))

[['新华社', '北京']]

The SplitMergeFromLogitsTokenizer is similar, but it instead accepts logit value pairs from a neural network that predict if each character should be split into a new string or merged into the current one.

strings = [["新华社北京"]]

labels = [[[5.0, -3.2], [0.2, 12.0], [0.0, 11.0], [2.2, -1.0], [-3.0, 3.0]]]

tokenizer = tf_text.SplitMergeFromLogitsTokenizer()

tokenizer.tokenize(strings, labels)

print(decode_utf8_tensor(tokens))

[['新华社', '北京']]

RegexSplitter

The RegexSplitter is able to segment strings at arbitrary breakpoints defined by a provided regular expression.

splitter = tf_text.RegexSplitter("\s")

tokens = splitter.split(["What you know you can't explain, but you feel it."], )

print(tokens.to_list())

[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

Offsets

When tokenizing strings, it is often desired to know where in the original string the token originated from. For this reason, each tokenizer which implements TokenizerWithOffsets has a tokenize_with_offsets method that will return the byte offsets along with the tokens. The start_offsets lists the bytes in the original string each token starts at, and the end_offsets lists the bytes immediately after the point where each token ends. To refrase, the start offsets are inclusive and the end offsets are exclusive.

tokenizer = tf_text.UnicodeScriptTokenizer()

(tokens, start_offsets, end_offsets) = tokenizer.tokenize_with_offsets(['Everything not saved will be lost.'])

print(tokens.to_list())

print(start_offsets.to_list())

print(end_offsets.to_list())

[[b'Everything', b'not', b'saved', b'will', b'be', b'lost', b'.']]

[[0, 11, 15, 21, 26, 29, 33]]

[[10, 14, 20, 25, 28, 33, 34]]

Detokenization

Tokenizers which implement the Detokenizer provide a detokenize method which attempts to combine the strings. This has the chance of being lossy, so the detokenized string may not always match exactly the original, pre-tokenized string.

tokenizer = tf_text.UnicodeCharTokenizer()

tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])

print(tokens.to_list())

strings = tokenizer.detokenize(tokens)

print(strings.numpy())

[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]]

[b"What you know you can't explain, but you feel it."]

TF Data

TF Data is a powerful API for creating an input pipeline for training models. Tokenizers work as expected with the API.

docs = tf.data.Dataset.from_tensor_slices([['Never tell me the odds.'], ["It's a trap!"]])

tokenizer = tf_text.WhitespaceTokenizer()

tokenized_docs = docs.map(lambda x: tokenizer.tokenize(x))

iterator = iter(tokenized_docs)

print(next(iterator).to_list())

print(next(iterator).to_list())

WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/autograph/pyct/static_analysis/liveness.py:83: Analyzer.lamba_check (from tensorflow.python.autograph.pyct.static_analysis.liveness) is deprecated and will be removed after 2023-09-23.

Instructions for updating:

Lambda fuctions will be no more assumed to be used in the statement where they are used, or at least in the same block. https://github.com/tensorflow/tensorflow/issues/56089

WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/autograph/pyct/static_analysis/liveness.py:83: Analyzer.lamba_check (from tensorflow.python.autograph.pyct.static_analysis.liveness) is deprecated and will be removed after 2023-09-23.

Instructions for updating:

Lambda fuctions will be no more assumed to be used in the statement where they are used, or at least in the same block. https://github.com/tensorflow/tensorflow/issues/56089

[[b'Never', b'tell', b'me', b'the', b'odds.']]

[[b"It's", b'a', b'trap!']]

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2024-02-25 UTC.

Stay connected

Blog

GitHub

Twitter

哔哩哔哩

Support

Issue tracker

Release notes

Stack Overflow

Brand guidelines

Cite TensorFlow

Terms

Privacy

ICP证合字B2-20070004号

Manage cookies

Sign up for the TensorFlow newsletter

Subscribe

English

Español – América Latina

Français

Indonesia

Italiano

Polski

Português – Brasil

Tiếng Việt

Türkçe

Русский

עברית

العربيّة

فارسی

हिंदी

বাংলা

ภาษาไทย

中文 – 简体

日本語

한국어