河内机器人 基于 HuggingFace Tokenizers 训练自定义分词器

admin1个月前河内机器人30

tokenizers 是 HuggingFace 用 Rust 实现核心、Python 绑定的高性能分词库,训练和推理速度比纯

 Python 实现快几个数量级,且支持多线程训练。当前最新稳定版为 0.22.x(pip show tokenizers 显

示 0.22.2)[citation:web:2.3];核心训练 API(Tokenizer / BpeTrainer / WordPieceTrainer / UnigramTrainer)

从 0.13 到 0.19 乃至更新版本都保持稳定,老代码基本可直接运行[citation:web:2.14]。


---

一、为什么需要自定义分词器


预训练模型的通用分词器在面对特定领域语料(医学、法律、代码、某种语言)时会退化:

领域专业词被切成大量碎片 token,浪费序列长度;

中低频字词覆盖率低,OOV 比例高;

词表里塞了大量与你任务无关的 token。


自己训练可以让词表、合并规则与你的语料分布对齐,显著提升下游模型效率。


---

二、先理解「分词流水线」


tokenizers 把一个分词器拆成 5 个可替换组件,训练时按顺序作用于文本:


原始文本

 → Normalizer 规范化(Unicode 归一化 / 大小写 / 去重音)

 → PreTokenizer 预分词(按空格 / 字节级 / 正则切分)

 → Model 核心子词模型(BPE / WordPiece / Unigram)

 → PostProcessor 后处理(加 [CLS]/[SEP] 等特殊 token)

 → Decoder 解码回文本


训练时只需关心前三个;PostProcessor 和 Decoder 在训练后补齐。


---

三、三种核心算法对比


| 算法 | 思路 | 特点 | 典型代表 |

|------|------|------|----------|

| BPE | 从字符起步,反复合并最高频相邻对 | 直观、易实现、无歧义 | GPT 系列 |

| WordPiece | 类似 BPE,但合并依据是最大化似然增益 | 贪心、效果略优 | BERT |

| Unigram | 从大词表起步,逐步删减低概率子词 | 概率模型、可出多个候选 | T5、SentencePiece |

选择建议:英文/一般场景 BPE 最稳;复现 BERT 用 WordPiece;中文、日文等无空格语言优先 Unigram(配 Metaspace 预处理,等价 SentencePiece 行为)。


---

四、完整训练代码(以 BPE 为例)

准备语料


语料用纯文本文件,每行一个句子/文档即可(corpus.txt),越大越干净越好。

训练脚本


from tokenizers import Tokenizer

from tokenizers.models import BPE

from tokenizers.trainers import BpeTrainer

from tokenizers.pre_tokenizers import ByteLevel

from tokenizers.normalizers import NFKC, Sequence

from tokenizers.decoders import ByteLevel as ByteLevelDecoder

① 声明核心模型:BPE,unk 用 [UNK]

tokenizer = Tokenizer(BPE(unk_token="[UNK]"))

② 规范化:NFKC 统一全半角、兼容字符

tokenizer.normalizer = Sequence([NFKC()])

③ 预分词:字节级(对 OOV/多语言最鲁棒,GPT 风格)

tokenizer.pretokenizer = ByteLevel(addprefix_space=True)

④ 训练器

trainer = BpeTrainer(

 vocab_size=30000, # 词表大小

 min_frequency=2, # 最小频次,低于此不参与合并

 special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"],

 show_progress=True,

)

⑤ 训练(files 传路径列表;也支持 trainfromiterator)

tokenizer.train(files=["corpus.txt"], trainer=trainer)

⑥ 解码器(与 ByteLevel 预分词配套)

tokenizer.decoder = ByteLevelDecoder()

⑦ 保存

tokenizer.save("mybpetokenizer.json")

训练 WordPiece(BERT 风格)


from tokenizers import Tokenizer

from tokenizers.models import WordPiece

from tokenizers.trainers import WordPieceTrainer

from tokenizers.pre_tokenizers import Whitespace


tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))

tokenizer.pre_tokenizer = Whitespace() # BERT 按空格预分词


trainer = WordPieceTrainer(

 vocab_size=30000,

 special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"],

)


tokenizer.train(files=["corpus.txt"], trainer=trainer)

tokenizer.save("mywptokenizer.json")

训练 Unigram(中文/无空格语言推荐)


from tokenizers import Tokenizer

from tokenizers.models import Unigram

from tokenizers.trainers import UnigramTrainer

from tokenizers.pre_tokenizers import Metaspace


tokenizer = Tokenizer(Unigram())

tokenizer.pre_tokenizer = Metaspace() # SentencePiece 风格,▁ 表示词首


trainer = UnigramTrainer(

 vocab_size=30000,

 special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"],

 unk_token="[UNK]",

)


tokenizer.train(files=["corpus.txt"], trainer=trainer)

tokenizer.save("myunigramtokenizer.json")


---

五、加载与使用


from tokenizers import Tokenizer


tok = Tokenizer.fromfile("mybpe_tokenizer.json")

编码

enc = tok.encode("Hello, how are you?")

print(enc.ids) # token id 序列

print(enc.tokens) # 子词片段(如 ['Hello', ',', 'Ġhow', ...],Ġ 表示前有空格)

print(enc.attention_mask)

解码

print(tok.decode(enc.ids)) # 'Hello, how are you?'


---

六、接入 Transformers 生态


训练好的 tokenizer.json 可以无缝接进 transformers,配合任意模型使用:


from transformers import PreTrainedTokenizerFast


fast_tok = PreTrainedTokenizerFast(

 tokenizerfile="mybpe_tokenizer.json",

 # 若需对齐 BERT 格式的特殊 token

 unk_token="[UNK]",

 pad_token="[PAD]",

 cls_token="[CLS]",

 sep_token="[SEP]",

 mask_token="[MASK]",

)


fasttok.savepretrained("./mytokenizerdir")


也可以直接用 tokenizer_object 传入内存中的 Tokenizer 对象。


---

七、关键注意事项

预处理与解码必须配套:用了 ByteLevel 预分词,解码也要用 ByteLevel 解码器,否则会多出 Ġ 前缀或丢失空格。

addprefixspace 一致性:训练和推理时的这个参数要相同,否则首个 token 的前导空格处理会不一致。

语料质量 > 词表大小:脏数据、短文本碎片多,再大的词表也没用;先做清洗(去重、去 HTML、去乱码)。

minfrequency 与 vocabsize 的权衡:语料小时,minfrequency 调高能避免学到噪声合并;vocabsize 过大反而留下大量低频无用 token。

trainfromiterator 处理大语料:文件太大无法一次性读入时,用生成器逐条喂数据,避免内存爆炸:


def batchiterator(path, batchsize=1000):

 with open(path, "r", encoding="utf-8") as f:

 batch = []

 for line in f:

 batch.append(line.strip())

 if len(batch) == batch_size:

 yield batch

 batch = []

 if batch:

 yield batch


tokenizer.trainfromiterator(batch_iterator("corpus.txt"), trainer=trainer)

tokenizers 与 transformers 版本锁:transformers 导入时会校验 tokenizers 版本,装了过新/过旧的 tokenizers 可能触发 UserWarning 甚至报错[citation:web:2.12];两者一起 pip install 时让 pip 自动解析依赖最稳妥。


---


需要的话,我可以再展开:怎么评估一个分词器的好坏(fertility、覆盖率、压缩率等指标),或者给一个中文语料训练 SentencePiece 风格分词器的完整可运行脚本。


澳五机器人 澳八机器人 河内机器人 加拿大机器人 花开月下机器人 朱雀机器人 速飞机器人 名爵机器人 飞天机器人 BV机器人 涂六飞单机器人 美猴王机器人 大富豪机器人 速讯机器人 五球助手 十球助手

相关文章

河内机器人 30K Star 神器,给 Claude Code 装上代码地图,Token 中位数省 65 倍

项目:CodeGraph(colbymchenry/codegraph) GitHub 约30K⭐,基于 Tree-sitter,通过 MCP(Model Context Protocol) 接入 C...

.NET 10 新功能新增功能介绍:WebSocket 功能增强(四)

在 .NET 10 的持续创新中,WebSocket 功能的增强进一步提升了其在实时通信领域的竞争力。作为 .NET 10 中 WebSocket 功能增强的第四部分,本文将深入探讨其在流量...

花开月下机器人 .NET跨平台桌面开发的痛点与需求

一、.NET跨平台桌面开发的痛点与需求在.NET生态的桌面开发领域,长期以来存在着平台割裂的痛点。Windows平台上有成熟的WPF和WinForms,但它们无法直接在Linux、macOS等系统运行...

河内机器人 Linux桌面端应用向鸿蒙PC迁移适配纪实

Linux桌面端应用向鸿蒙PC迁移适配纪实从Linux桌面生态迁移到鸿蒙PC平台,不是简单的“换个系统编译”,而是要在构建体系、系统API、交互体验、包管理逻辑上完成全链路适配。以下是基于真实开源项目...

河内机器人 把PicoServer的极简服务调度能力和SimdPaddleOCR的极致SIMD加速能力结合

这套轻量部署方案,是把PicoServer的极简服务调度能力和SimdPaddleOCR的极致SIMD加速能力结合,在x86/ARM边缘硬件上实现低资源占用、高吞吐的OCR服务部署,完全适配你之前关注...

Qwen3-Embedding国产化部署

1. 背景最近一直在做ToG的项目,其中用到了语义检索,研发环境使用A40和vllm,即可轻松部署Qwen3-Embedding-8B,但客户环境要求国产化环境,因此探索Qwen3-Embe...