AI基本结构10-分词器 接着看看课:https://www.bilibili.com/video/BV1cb421n78rps这个示例让我想到re0课程复现import os os.environ[HF_ENDPOINT] https://hf-mirror.com from transformers import AutoTokenizer import matplotlib.pyplot as plt import huggingface_hub import transformers tokenizer_gpt2 AutoTokenizer.from_pretrained(gpt2) # 分词效果示例三段文本表示的意思是相近的 text_fr Évariste Galois (/ɡælˈwɑː/; français : [evaʁist ɡalwa] ; 25 octobre 1811 - 31 mai 1832) était un mathématicien français et un militant politique. Alors quil était encore adolescent, il parvint à déterminer une condition nécessaire et suffisante pour quun polynôme soit résoluble par des radicaux, résolvant ainsi un problème qui était resté ouvert pendant 350 ans. Son travail posa les fondements de la théorie de Galois et de la théorie des groupes, deux branches majeures de lalgèbre abstraite. Il était un fervent républicain et fut très impliqué dans les troubles politiques qui entourèrent la Révolution française de 1830. En raison de son activisme politique, il fut arrêté à plusieurs reprises, purgé une peine de plusieurs mois de prison. Pour des raisons restées obscures, peu de temps après sa libération de prison, il se battit en duel et décéda des blessures quil subit. text_en Évariste Galois (/ɡælˈwɑː/; French: [evaʁist ɡalwa]; 25 October 1811 – 31 May 1832) was a French mathematician and political activist. While still in his teens, he was able to determine a necessary and sufficient condition for a polynomial to be solvable by radicals, thereby solving a problem that had been open for 350 years. His work laid the foundations for Galois theory and group theory, two major branches of abstract algebra. He was a staunch republican and was heavily involved in the political turmoil that surrounded the French Revolution of 1830. As a result of his political activism, he was arrested repeatedly, serving one jail sentence of several months. For reasons that remain obscure, shortly after his release from prison he fought in a duel and died of the wounds he suffered. text_zh 埃瓦里斯特·伽罗瓦法语Évariste Galois1811年10月25日—1832年5月31日法语发音 [evaʁist ɡalwa]是一位法国数学家和政治活动家。尽管还在十几岁时他就能够确定多项式能够通过根式求解的充分必要条件从而解决了一个悬而未决的问题该问题已经存在了350年。他的工作奠定了Galois理论和群论的基础这两个是抽象代数的重要分支。他是一位坚定的共和派深度参与了1830年法国大革命期间的政治动荡。由于他的政治活动他多次被逮捕其中一次入狱数月。由于原因不明他在刑满释放后不久参与了一场决斗并因受伤而去世。 texts { fr: text_fr, en: text_en, zh: text_zh } def draw_bar(str_stats, token_stats): # 将统计结果可视化 fig plt.figure(figsize(6, 6), dpi80) plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False plt.rcParams.update({font.size: 13}) bar_width 0.1 base range(len(str_stats)) br_str [x - bar_width for x in base] br_token [x bar_width for x in base] plt.bar(br_str, str_stats.values(), colorg, widthbar_width * 2, label文本长度) plt.bar(br_token, token_stats.values(), colorb, widthbar_width * 2, label分词后的长度) plt.xticks([r for r in base], str_stats.keys(), fontsize18) plt.legend(shadowTrue) return fig def get_token_stats(tokenizer): # 统计文本中的单词数量如果是中文则为文本的字数 str_stats {} # 统计分词后的词元数量 token_stats {} for (k, v) in texts.items(): text_len len(v.split()) if k ! zh else len(list(v)) token_len len(tokenizer.encode(v)) str_stats[k] text_len token_stats[k] token_len print(str_stats) print(token_stats) return draw_bar(str_stats, token_stats) # 使用gpt2分词器进行分词的效果 f get_token_stats(tokenizer_gpt2) f.savefig(gpt2_tokenizer.png, dpi200) for text in texts: # 英文分词效果展示 stringText_.join([tokenizer_gpt2.decode(i) for i in tokenizer_gpt2.encode(texts[text])]) print(stringText) from datasets import load_dataset # 使用中文语料训练分词器 raw_data load_dataset(BelleGroup/train_0.5M_CN) def get_training_corpus(): # 为了减少运算时间只选择较少的训练数据 data raw_data[train].select(range(10000)) for idx in range(0, len(data), 1000): samples data[idx : idx 1000] yield samples.get(instruction, []) samples.get(output, []) # 为了减少运算时间只将词汇表大小设置为1000正常应该在5万左右 tokenizer_zh tokenizer_gpt2.train_new_from_iterator(get_training_corpus(), 1000) # 展示新分词器的效果 f get_token_stats(tokenizer_zh) f.savefig(zh_tokenizer.png, dpi200) for text in texts: # 英文分词效果展示 stringText_.join([tokenizer_gpt2.decode(i) for i in tokenizer_gpt2.encode(texts[text])]) print(stringText)按字符分词# 使用gpt2分词器进行分词的效果 f get_token_stats(tokenizer_gpt2) f.savefig(gpt2_tokenizer.png, dpi200) for text in texts: # 英文分词效果展示 stringText_.join([tokenizer_gpt2.decode(i) for i in tokenizer_gpt2.encode(texts[text])]) print(stringText)join函数:将列表推导式生成的字符串列表用下划线_拼接成一个字符串。例如若解码结果为[hello, world]则输出为hello_world。中文分词的挑战中文文本缺乏显式的词边界标记需依赖上下文语义、词典或统计模型进行切分。而英文分词直接利用空格和标点符号避免了歧义切分的复杂性例如中文“结婚的和尚未结婚的”可能被错误切分为“结婚/的/和/尚未/结婚/的”英文分词字母文字的优势英文分词基于空格和标点符号进行切分天然具有词边界标记。这种特性使得英文分词在技术上相对简单多数情况下无需复杂的算法即可实现基本的分词功能效率更高英文分词算法复杂度低处理速度快无需依赖大规模词典或复杂的统计模型。准确性稳定词边界明确歧义切分问题极少错误率显著低于中文分词。资源消耗少不需要训练庞大的语言模型或维护高频词典节省计算和存储资源。基于训练的分词器预训练与微调微调Fine-tuning是在预训练模型的基础上针对特定任务使用有标注数据进行参数调整的过程。其目的是使模型适应具体场景如情感分类、医学图像分割。数据需求需要任务相关的标注数据但规模远小于预训练数据。调整策略可能仅优化顶层网络如分类头或全局微调所有参数。效率优势相比从头训练微调能显著减少计算成本和数据需求。训练分词器from datasets import load_dataset # 使用中文语料训练分词器 raw_data load_dataset(BelleGroup/train_0.5M_CN) def get_training_corpus(): # 为了减少运算时间只选择较少的训练数据 data raw_data[train].select(range(10000)) for idx in range(0, len(data), 1000): samples data[idx : idx 1000] yield samples.get(instruction, []) samples.get(output, []) # 为了减少运算时间只将词汇表大小设置为1000正常应该在5万左右 tokenizer_zh tokenizer_gpt2.train_new_from_iterator(get_training_corpus(), 1000) # 展示新分词器的效果 f get_token_stats(tokenizer_zh) f.savefig(zh_tokenizer.png, dpi200) for text in texts: # 英文分词效果展示 stringText_.join([tokenizer_gpt2.decode(i) for i in tokenizer_gpt2.encode(texts[text])]) print(stringText)从Hugging Face数据集加载中文语料并基于GPT-2的分词器训练一个适配中文的新分词器。代码分为数据加载、迭代器构建、分词器训练和效果验证四个部分。raw_data load_dataset(BelleGroup/train_0.5M_CN)从Hugging Face数据集库加载名为BelleGroup/train_0.5M_CN的中文数据集该数据集包含50万条中文训练样本。get_training_corpus()函数定义了一个生成器通过raw_data[train].select(range(10000))选取前1万条训练数据并以每1000条为批次进行迭代。每次迭代时将样本中的instruction和output字段内容合并后生成训练语料片段这种分批次生成方式可有效控制内存消耗。tokenizer_zh tokenizer_gpt2.train_new_from_iterator(get_training_corpus(), 1000)调用GPT-2分词器的训练方法基于中文语料迭代器训练新分词器。参数1000指定词汇表大小实际应用应设置更大值如5万该方法会分析语料中的字符/子词频率构建适合中文的分词方案。yield语句在 Python 中yield是用于定义生成器函数的关键字。生成器函数返回一个生成器对象该对象可以迭代每次迭代时函数会执行到yield语句处暂停并将yield后的值返回给调用者。下次迭代时函数会从上次暂停的位置继续执行。调用生成器函数时函数不会立即执行而是返回一个生成器对象。使用 next() 或迭代如 for 循环时函数执行到第一个 yield 语句返回 yield 后的值并暂停。再次调用 next() 时函数从上次暂停的位置继续执行直到遇到下一个 yield 或函数结束。# 手动实现迭代器 class Counter: def __init__(self, low, high): self.current low self.high high def __iter__(self): return self def __next__(self): if self.current self.high: raise StopIteration else: self.current 1 return self.current - 1 # 使用生成器实现相同功能 def counter_generator(low, high): current low while current high: yield current current 1词嵌入词嵌入Embedding是将离散的符号如单词映射到连续向量空间的技术旨在用低维稠密向量表示文本替代传统的高维稀疏表示如独热编码。