如何快速对数百万条样本执行HuggingFace分词器分词操作?
HuggingFace 百万级文本分词提速方案
你当前用pandas map逐行调用分词函数慢的核心原因是:逐行串行执行的Python循环会产生极高的函数调用开销,同时完全没有用到HuggingFace分词器原生的批量处理、Rust底层优化能力,百万级样本下这个开销会被放得非常大。
以下是按改造成本从低到高、性能提升从明显到极致排序的可落地方案:
1. 优先使用Fast版本分词器,替换纯Python实现的慢分词器
绝大多数主流HuggingFace模型都配套了基于Rust实现的Fast Tokenizer,比纯Python版本速度快5~10倍,内存占用更低,加载时显式指定即可:
from transformers import AutoTokenizer # 显式开启fast分词器 tokenizer = AutoTokenizer.from_pretrained("你的模型路径/名", use_fast=True)
可以通过tokenizer.is_fast确认是否加载成功,返回True就是正常启用了。
2. 放弃逐行map,直接调用分词器原生批量接口
HuggingFace Tokenizer原生支持传入字符串列表做批量处理,底层会走Rust并行逻辑,比逐行Python调用快10~100倍,不需要依赖额外库:
# 把整列文本转成列表,分批次传入分词器,避免一次性加载过多数据OOM texts = df["text_column"].tolist() batch_size = 2048 # 根据内存大小调整,1024~4096都是常用值 all_tokenized = [] for i in range(0, len(texts), batch_size): batch_texts = texts[i:i+batch_size] batch_res = tokenizer( batch_texts, truncation=True, max_length=512, padding=False # 如果是训练阶段用动态padding,这里可以关了省时间 ) all_tokenized.append(batch_res)
注意:不要在全量数据层面做padding='longest',会被极长的异常文本拖慢速度、浪费大量内存,固定max_length或者在训练时的DataLoader阶段做batch内动态padding效率最高
3. 用HuggingFace Datasets替代pandas做数据处理,开启多进程并行
如果单进程批量处理还是达不到速度要求,直接用datasets库替换pandas做分词流程,它基于Apache Arrow做内存映射,支持多进程并行分词,百万级样本在普通消费级CPU上几分钟就能跑完:
from datasets import Dataset # pandas dataframe转Dataset是零拷贝操作,几乎没有额外开销 ds = Dataset.from_pandas(df) def tokenize_batch(batch): return tokenizer( batch["text_column"], truncation=True, max_length=512 ) # 开启批量处理+多进程 tokenized_ds = ds.map( tokenize_batch, batched=True, # 必须开启,批量传入数据给分词器 num_proc=8, # 设为CPU的物理核心数即可,不要超过逻辑核心数避免调度开销 remove_columns=ds.column_names # 分词完成后删除原始文本列,节省内存 )
4. 预分词结果本地缓存,避免重复计算
如果需要多次使用分词后的数据集,直接把处理好的结果存到本地磁盘,下次训练/推理直接加载,不需要重复跑分词流程:
# 保存分词后的数据集 tokenized_ds.save_to_disk("./pre_tokenized_data") # 后续使用直接加载 from datasets import load_from_disk tokenized_ds = load_from_disk("./pre_tokenized_data")
常见踩坑点
- 不要在分词函数里写逐行的Python文本处理逻辑(比如逐行替换特殊字符、正则清洗),尽量在分词前用批量接口完成所有文本清洗工作,逐行Python操作会抵消掉批量分词的性能优势
- 不需要用pandas的第三方加速插件(比如swifter、pandarallel)做分词,这类插件本质还是绕不开Python层的逐行调用开销,性能远不如分词器原生批量+多进程方案
- 如果是GPU训练场景,还可以进一步把分词逻辑放到DataLoader的worker中异步执行,和GPU计算做流水并行,进一步压缩整体训练耗时
内容的提问来源于stack exchange,提问作者SantoshGupta7
相关产品推荐
相关产品推荐

