HuggingFace Tokenizers 是一个高效的文本分词库,用于将自然语言文本分割成单个的标记(tokens),以便用于自然语言处理任务中,如文本分类、命名实体识别、机器翻译等。它支持多种语言,并提供了多种分词器的实现,包括 BPE、WordPiece 和 Unigram。
pip install tokenizers
1. 准备训练集
import pandas as pd import pickle import jieba import logging jieba.setLogLevel(logging.CRITICAL) def demo(): data = pd.read_csv('weibo_senti_100k/weibo_senti_100k.csv') # 去除异常值 data = data.dropna() # 文本进行分词 corpus = [' '.join(jieba.lcut(review)) for review in data['review'].to_numpy().tolist()] print(corpus[0]) # 存储语料 pickle.dump(corpus, open('weibo_senti_100k/corpus.pkl', 'wb')) if __name__ == '__main__': demo()
更博 了 , 爆照 了 , 帅 的 呀 , 就是 越来越 爱 你 ! 生快 傻 缺 [ 爱 你 ] [ 爱 你 ] [ 爱 你 ]
2. 训练分词器
import pickle from tokenizers import pre_tokenizers from tokenizers import normalizers from tokenizers import processors from tokenizers import Tokenizer, models from tokenizers import trainers def train(): # 初始化分词器,并设置方法为 BPE tokenizer = Tokenizer(model=models.BPE(unk_token='[UNK]')) # 在词表中添加特殊的标记 special_tokens = ['[CLS]', '[SEP]', '[UNK]', '[PAD]'] tokenizer.add_special_tokens(special_tokens) # 1. 对文本进行标准化,例如将文本转换为小写(Lowercase)、统一字符编码(NFC)等 tokenizer.normalizer = normalizers.Sequence([normalizers.Lowercase(), normalizers.NFC()]) # 2. 将文本分割成初步的单元(如单词、字符等),为后续的分词操作提供基础。 tokenizer.pre_tokenizer = pre_tokenizers.WhitespaceSplit() # 3. 在分词完成后,对分词结果进行进一步处理,例如添加特殊标记(如 [CLS] 和 [SEP])以适配模型的输入格式。 tokenizer.post_processor = processors.TemplateProcessing( single="[CLS] $A [SEP]", special_tokens=[ ('[CLS]', tokenizer.token_to_id('[CLS]')), ('[SEP]', tokenizer.token_to_id('[SEP]')) ] ) # 初始化训练器,设置词汇表大小、特殊令牌和最小频率 # continuing_subword_prefix: 子词表示前缀,例如:问答使用两个子词表示:['问', '###答'] # min_frequency: 只有出现频率至少为 min_frequency 的字符对才会被合并 trainer = trainers.BpeTrainer(vocab_size=20000, min_frequency=0, continuing_subword_prefix='###', show_progress=False) # 从文本数据迭代训练分词器 corpus = pickle.load(open('weibo_senti_100k/corpus.pkl', 'rb')) tokenizer.train_from_iterator(corpus, trainer) print('词典大小:', tokenizer.get_vocab_size()) # 保存训练好的分词器 # 1. tokenizer 保存 tokenizer.save('tokenizer.json') # 2. transfomers 保存 from transformers import PreTrainedTokenizerFast tokenizer = PreTrainedTokenizerFast(tokenizer_object=tokenizer) tokenizer.save_pretrained('tokenizer') if __name__ == '__main__': train()
3. 使用分词器
import jieba import logging jieba.setLogLevel(logging.CRITICAL) import pickle from tokenizers import Tokenizer # 1. encode def demo01(): # 1. 加载分词器 tokenizer = Tokenizer.from_file('tokenizer.json') content = '某 问答 社区 上 收到 一 大学生 Edward Meng 发给 我 的 私信。' encode_content = tokenizer.encode(content, add_special_tokens=True) print(encode_content.tokens) print(encode_content.ids) print(encode_content.word_ids) # 3. 输出解码 decode_content = tokenizer.decode(encode_content.ids, skip_special_tokens=False) print(decode_content) # 2. encode_batch def demo02(): tokenizer = Tokenizer.from_file('tokenizer.json') # 启动 PAD 对齐 tokenizer.enable_padding(direction='right', pad_token='[PAD]', pad_id=tokenizer.token_to_id('[PAD]')) contents = ['我 是 中国人', '我 爱 我 的 国家'] # 批量编码 encode_contents = tokenizer.encode_batch(contents, is_pretokenized=False) for content in encode_contents: print(content) print(content.tokens) print(content.ids) # 注意力掩码 print(content.attention_mask) print(content.special_tokens_mask) print('-' * 30) if __name__ == '__main__': demo01() print('*' * 30) demo02()
['[CLS]', '某', '问答', '社区', '上', '收到', '一', '大学生', 'ed', 'ward', 'meng', '发给', '我', '的', '私信', '。', '[SEP]'] [0, 2510, 17166, 9468, 319, 6309, 313, 12022, 7889, 16561, 11938, 10628, 2011, 3488, 6461, 168, 1] [None, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 12, None] ! 某 问答 社区 上 收到 一 大学生 ed ward meng 发给 我 的 私信 。 " ****************************** Encoding(num_tokens=7, attributes=[ids, type_ids, tokens, offsets, attention_mask, special_tokens_mask, overflowing]) ['[CLS]', '我', '是', '中国', '人', '[SEP]', '[PAD]'] [0, 2011, 2376, 5921, 414, 1, 20003] [1, 1, 1, 1, 1, 1, 0] [1, 0, 0, 0, 0, 1, 1] ------------------------------ Encoding(num_tokens=7, attributes=[ids, type_ids, tokens, offsets, attention_mask, special_tokens_mask, overflowing]) ['[CLS]', '我', '爱', '我', '的', '国家', '[SEP]'] [0, 2011, 3188, 2011, 3488, 6231, 1] [1, 1, 1, 1, 1, 1, 1] [1, 0, 0, 0, 0, 0, 1] ------------------------------