- 人工智能
- 大模型
- 预训练
- 微调
- LoRA
- RLHF
- 强化学习
- 分布式训练
【免费下载链接】PaddleNLP
Easy-to-use and powerful LLM and SLM library with awesome model zoo.
PaddleNLP 的 llm/tools/preprocess 目录提供了一套完整的预训练数据处理工具链,覆盖从原始文本清洗、jsonl 转换、中文分词、token ID 化到训练 index 生成的四个核心阶段。本文以 ziya-llama-13b-v1 中文预训练为贯穿示例,逐环节讲解脚本参数、源码实现原理与实战命令,读完即可独立把 CLUECorpusSmall、OpenWebText2、WuDaoCorpus2.0 Base 等主流开源语料加工成可直接用于训练的.bin/.idx数据文件。
一、预训练数据流程总览
预训练数据管线被划分为四个阶段,每一步产出明确的中间产物,最终得到训练器直接消费的二进制数据集:
| 步骤 | 阶段 | 数据格式 | 样例 |
|---|---|---|---|
| 0️⃣ 初始状态 | - | 原始数据:每个 doc 之间用空行间隔;中文默认每句换行作为句子结束,英文默认使用 nltk 判断句子结束 | 飞桨是功能完备、开源开放的产业级深度学习平台。飞桨拥有核心训练和推理框架、基础模型库。PaddleNLP是自然语言处理领域的优秀工具。 |
1️⃣ 原始数据转换(trans_to_json.py) | 预处理 | jsonl 格式:每个 doc 对应一行 json 字符串 | {"text": "飞桨是功能完备、开源开放的产业级深度学习平台。飞桨拥有..."} |
❇️(可选)数据中文分词(words_segmentation.py) | 语料分词:中文 WWM | 将 jsonl 恢复为分词后的原始格式数据 | 飞桨 是 功能 完备、开源 开放的 产业级 深度学习 平台。 |
2️⃣ 数据 ID 化(create_pretraining_data.py) | 预处理 | .bin(token id)+.idx(句子、文章位置索引) | - |
| 3️⃣ 训练 index 文件生成 | 训练启动 | .npy:根据 max_steps 生成 train/valid/test 的样本索引文件 | - |
| 4️⃣ token 动态 mask(可选) | Dataset 取数据 | 无 | - |
工具目录共包含 5 个文件:
├── create_pretraining_data.py ├── merge.py ├── trans_to_json.py ├── words_segmentation.py └── README.md二、环境依赖
处理脚本依赖以下 Python 包:
- tqdm:
create_pretraining_data.py处理文件时展示进度条 - numpy:用于 token id 的 dtype 判定与索引构建
- pybind11:编译支撑 fast_dataindex 等扩展
- fast_dataindex:数据索引相关能力
- lac(可选):中文分词,提供
lac/seg两种 LAC 模式 - zstandard(可选):用于解压
.zst格式的压缩语料(如 OpenWebText2)
一键安装命令:
pip install tqdm numpy pybind11 fast_dataindex lac zstandard另外,部分功能需要g++ >= 4.8编译支持。若处理英文语料并开启--split_sentences,还需要 nltk 环境——源码中通过try: import nltk判断可用性,若缺失则直接报错退出(见 create_pretraining_data.py)。
三、步骤 1:原始数据转换(trans_to_json.py)
trans_to_json.py将原始纯文本转换为 jsonl 格式,每个 doc 对应一行 json 字符串。
3.1 参数说明
optional arguments: -h, --help 显示帮助 --input_path 必须设置。原始文件路径,可以是文件夹或单个文件; 文件夹中的目录默认最多搜索两层子目录。 --output_path 必须设置。输出 json 文件的名称。 --json_key json 的 content key,建议不修改,默认是 text --doc_spliter 文档分隔符。默认空行作为文章分隔符; 若使用空行分隔 doc,该项留空即可。 --min_doc_length 可选。过滤过短文章,默认值 10(字符数) --workers 可选。多进程转换文件数,适用于 input_path 中文件较多的情况, 每个文件分配给不同 worker 处理 --log_interval 可选。处理完文件个数的日志间隔,默认 1 --no-merge 可选。默认不开启;开启后每个文件转换的 jsonl 不拼接 到同一个文件,而是各自输出 --no-shuffle 可选。默认不开启;默认处理完会对所有 doc 进行 shuffle3.2 源码实现要点
从源码看,核心转换逻辑在raw_text_to_json函数(trans_to_json.py):
- 逐行读取原始文本,遇到
line.strip() == doc_spliter(即空行)时,把累积的doc字符串判断长度后写入一行json.dumps({json_key: doc}, ensure_ascii=False); ensure_ascii=False保证中文以原文形式(而非\u转义)写入,便于人眼检查;- 主流程使用
multiprocessing.Pool并行处理文件(每个文件一个 worker),默认 1 个进程; - 合并(
merge_file)直接用二进制流shutil.copyfileobj拼接,随后用系统shuf命令对整文件做 shuffle(shuffle_file)。
3.3 实战命令
以下载百度百科样例数据为例:
mkdir data && cd data wget https://bj.bcebos.com/paddlenlp/models/transformers/data_tools/baike.txt cd ..执行转换(此处默认对所有 doc 进行 shuffle):
python trans_to_json.py --input_path ./data --output_path baike_sample查看产出的 jsonl:
head -1 baike_sample.jsonl {"text": "中国效仿西方发展工业的过程,于中华民国国民政府成立后至中日战争开战前夕已顺畅发展,尽管其间受到内外因素的多重干扰。尔后直至中日战争和国共战争的结束,中国始有较为长期的和平发展时期。\n1980年代以来,邓小平政府宣布改革开放,开始实行社会主义市场经济并推行经济体制改革。……\n"}四、步骤 ❇️(可选):中文语料预分词(words_segmentation.py)
words_segmentation.py是中文预训练做 WWM(Whole Word Masking)的可选步骤,作用是把 jsonl 格式的数据恢复成"分词 + 按句换行"的原始格式,供后续create_pretraining_data.py直接以--cn_splited=True消费。
4.1 使用原则
- 数据量较少时,分词耗时短,不需要单独分词,直接在
create_pretraining_data.py步骤中完成分词即可; - 单独分词的目的是提前分词、加快后续 ID 转化:当数据集很大或需要多次尝试转换时,可避免每次运行
create_pretraining_data.py都重复执行分词程序; - 若此处输入的是 jsonl 文件,最好为多文件,并在
trans_to_json.py阶段开启--no-merge选项; - 分词转换完成后,需要重新执行步骤 1️⃣(
trans_to_json.py),最后在步骤 2️⃣ 中设置--cn_splited=True; - 反过来,步骤 2️⃣ 也可以在转化 ID 的同时一起完成分词,此时无需 ❇️ 预分词步骤。
4.2 参数与实现
--input_path 必须设置。输入路径,文件夹或单个文件 --output_path 输出目录,默认 ./tmp --data_format 输入数据格式,可选 jsonl 或 wudao(默认 jsonl) --cn_seg_func 中文分词函数,可选 lac / seg / jieba(默认 jieba) --workers 多进程个数,默认 1 --log_interval 处理文件的日志间隔,默认 1三种分词函数在 words_segmentation.py 中均有实现:jieba直接调用jieba.cut;lac与seg都基于 LAC 库,分别使用LAC(mode="lac")(词法分析,返回词语与词性)和LAC(mode="seg")(纯分词)。
源码还包含一套简单的断句规则(text_to_text函数,words_segmentation.py):
- 用正则
re.sub("[" + char + "]+[ ]*", char, text)把连续的特殊符号(\n、。、?、?、空格、;、;、!、!)压缩为单个,避免同一符号被当作多个句子分隔符; - 再把断句符号(
。、?、?、;、;、!、!)替换为"符号 + 换行",实现按句切分; - 最后对每行调用分词函数,用空格连接词语,每句一行输出。
WuDao 数据则通过data_format=wudao分支读取,按js["content"]字段逐条产出。
五、步骤 2:数据 ID 化(create_pretraining_data.py)
这是整个管线最核心的脚本:读取 jsonl,断句、分词、tokenize,最终产出两个文件——XXX.bin(数据 ID 化后的 token ids)与XXX.idx(数据句子、文章位置索引)。
5.1 参数说明
--model_name_or_path 必须设置。使用的模型名或词表路径,如 idea-ccnl/ziya-llama-13b-v1; 使用自定义词表时,指定 model_name 为词表所在文件夹地址。 data input/output: --input_path 必须设置。输入 jsonl 文件或目录 --output_prefix 必须设置。输出文件名,假设为 XXX, 则输出 XXX.bin(token ids)与 XXX.idx(句子/文章位置索引) --data_format {JSON} 不需要设置。目前默认处理 jsonl 数据格式(choices 仅 JSON) --json_key json 文本的 key 值,与 trans_to_json.py 一致,默认 text --split_sentences 是否将文章划分成句子。一般 GPT 不需要,BERT/ERNIE 模型需要 --data_impl {mmap,lazy} 处理后的数据格式,可选 mmap 或 lazy; mmap 读入时建立内存映射,lazy 读入时直接从文件读取 chinese words: --chinese 处理中文且设置了 split_sentences 时需要设置 --cn_whole_word_segment 是否需要 WWM 策略。一般 BERT/ERNIE 需要,GPT 不需要 --cn_seg_func {lac,seg,jieba} 中文分词函数,默认 jieba(速度快);lac 模型更准确但计算量高 --cn_splited 语料是否已分词。设置后 cn_seg_func 不起作用; 例如分词后的文本串 "中国 效仿 西方 发展 工业 的过 程" --cn_split_dimer 配合 cn_splited 使用,默认空格表示分词间隔 common config: --append_eos doc 末尾追加 <eos> token。gpt 类模型专用,表示 doc 结束; 若 tokenizer 不含 eos_token,输出 warning 且不追加 --log_interval 打印日志间隔,表示处理文本行数/doc 数的间隔 --workers 文本 id 化的进程个数 --max_repeated_len 最大保留的重复字符个数(默认 100) --max_doc_num 处理到该 doc 数时停止(源码中默认 sys.maxsize)5.2 源码实现要点
ID 化逻辑集中在Converter类(create_pretraining_data.py):
- Tokenizer 初始化:每个 worker 进程通过
AutoTokenizer.from_pretrained(model_name_or_path)加载分词器;开启 WWM 时还会调用extend_chinese_char()扩充中文单字词表; - 句子切分:中文用
NewlineSplitter(按\n切分),英文用 nltk 的punkt模型;未开--split_sentences时用IdentitySplitter原样返回; - WWM 分词:
get_whole_word_mask_tokens函数(create_pretraining_data.py)把 WordPiece 切出的中文单字与 jieba/LAC 分词结果对齐,对处于中文词语中间的字符加上##前缀(如["通过","利用"]→["通","##过","利","##用"]),确保 WWM 时整词一起被 mask。非中文字符直接沿用 WordPiece 结果;max_word_length默认 6,避免过长中文词被整词 mask; - 重复字符过滤:
remove_repeated_chars用正则(.)\1{N,}把连续出现 N 次(默认 100)以上的重复字符压缩为单个; - dtype 自适应:
vocab_size < 2^16 - 1时用np.uint16存储,否则用np.int32(create_pretraining_data.py),小词表模型可节省一半存储; - 并行流水线:
multiprocessing.Pool(workers, initializer=convert.initializer)配合pool.imap(convert.encode, text, 256)实现按行分发的并行编码; - 数据写入:通过
paddlenlp.data.indexed_dataset.make_builder构建 mmap/lazy 数据集,add_item写入句子、end_document结束文档,最后finalize生成 idx 索引; - .zst 支持:输入文件以
.zst结尾时自动调用zstandard.ZstdDecompressor流式解压,可直接处理 OpenWebText2 一类压缩语料。
5.3 实战命令
针对 llama 模型(GPT 类,不切句、不加 WWM,追加 eos):
python -u create_pretraining_data.py \ --model_name_or_path "idea-ccnl/ziya-llama-13b-v1" \ --input_path "baike_sample.jsonl" \ --output_prefix "baike_sample" \ --data_format "JSON" \ --json_key "text" \ --data_impl "mmap" \ --append_eos \ --log_interval 5 \ --workers 40针对 ernie 模型(BERT 类,切句、中文、WWM):
python -u create_pretraining_data.py \ --model_name_or_path "ernie-3.0-base-zh" \ --input_path "baike_sample.jsonl" \ --output_prefix "baike_sample" \ --data_format "JSON" \ --json_key "text" \ --split_sentences \ --data_impl "mmap" \ --chinese \ --cn_whole_word_segment \ --cn_seg_func "jieba" \ --log_interval 5 \ --workers 40两个实用技巧:
- 使用已分好词的语料时,设置
--cn_splited,同时指定--cn_split_dimer(如空格)。此时源码中segment_func退化为lambda text: text.split(cn_split_dimer),且会处理连续空词对应的分隔符位置; - 使用自定义词表时,
--model_name_or_path直接指定词表所在文件夹地址即可。
六、大语料并行加工与 merge.py 合并
若预处理文件过大、单次转换耗时过长,可把 jsonl 拆分为多个小文件,并行运行多个create_pretraining_data.py,各自产出多组.bin/.idx,再用merge.py合并为一份完整数据。
6.1 参数说明
--input 必须设置。待合并文件所在文件夹; 文件夹内各小文件需按 merge 的顺序排列, 如 1.bin / 1.idx,2.bin / 2.idx ... --output_prefix 必须设置。合并后输出文件名,假设为 XXX, 则输出 XXX.bin 与 XXX.idx --data_impl {mmap,lazy} 合并前后数据格式必须一致,可选 mmap 或 lazy6.2 实现与命令
从 merge.py 源码可见合并流程:
- 扫描输入目录,以
.bin/.idx扩展名配对确认每个 prefix 的两个文件齐全,去重后按文件名排序依次合并(保证顺序与生成时一致); - 首个文件决定目标格式:
MMapIndexedDataset走MMapIndexedDatasetBuilder(沿用首文件的_index.dtype),lazy 走IndexedDatasetBuilder; - 逐个
builder.merge_file_(prefix)追加数据,最后finalize写出 idx。
实际合并命令:
python merge.py \ --input /root/data \ --output-prefix /root/data/merged \ --data_impl mmap七、步骤 3 与步骤 4:训练 index 生成与 token 动态 mask
- 训练 index 文件生成:发生在训练启动阶段,根据训练步数
max_steps生成.npy格式的 train / valid / test 每个样本的索引文件,训练器据此顺序消费样本。 - token 动态 mask(可选):在 Dataset 取数据阶段由 Python 层实时对文本做 mask。相关实现位于 slm/model_zoo/ernie-1.0/data_tools/dataset_utils.py,核心入口为
create_masked_lm_predictions函数(dataset_utils.py),其关键参数包括:
| 参数 | 含义 |
|---|---|
do_whole_word_mask | 是否执行 WWM(把同一原始词的所有 wordpiece 一起 mask) |
favor_longer_ngram | 是否偏好更长 n-gram 的 mask 片段(默认pvals = 1/n更偏好短 n-gram,置 True 后反转) |
do_permutation | 是否启用排列(permutation)式 mask 策略 |
geometric_dist | 是否用几何分布采样 n-gram 长度(默认均匀分布) |
masking_style | mask 风格,默认"bert" |
to_chinese_char | 是否把##中形式的字符还原为原始中文字符 |
用户可根据需求在dataset_utils.py中灵活修改 mask 方式,这些策略(do_whole_word_mask、favor_longer_ngram、do_permutation、geometric_dist 等)与 Megatron-LM 的 lm_mask 策略一脉相承。
八、开源数据集制作教程汇总
针对常见开源语料,llm/tools/preprocess/docs目录提供了四个制作教程:
| 名称 | 文本类型 | 纯文本大小 | 适配模型 |
|---|---|---|---|
| CLUECorpusSmall | 中文 | 14GB | Llama |
| OpenWebText2 | 英文 | 70GB | Llama |
| WuDaoCorpus2.0 Base | 中文 | 200GB | Llama |
| CLUECorpus2020 | 中文 | 200GB | Llama |
8.1 CLUECorpusSmall(中文 14GB)
数据量超过 14G,近 4000 个 txt 文件、50 亿字,包含新闻、社区互动、维基百科、评论四类子语料。解压后先执行转换:
python trans_to_json.py --input_path ./clue_corpus_small_14g --output_path clue_corpus_small_14g.jsonlLlama 数据制作(--append_eos、--data_impl mmap、--workers 48,分词较耗时约一小时完成,产出clue_corpus_small_14g.bin/.idx,全文约 1570 万文档):
python -u create_pretraining_data.py \ --model_name "idea-ccnl/ziya-llama-13b-v1" \ --input_path "clue_corpus_small_14g.jsonl" \ --output_prefix "clue_corpus_small_14g" \ --data_format "JSON" \ --json_key "text" \ --data_impl "mmap" \ --append_eos \ --log_interval 10000 \ --workers 48Ernie 数据制作(切句 + 中文 + WWM,分词函数可换lac获取更高准确率):
python -u create_pretraining_data.py \ --model_name "ernie-3.0-base-zh" \ --input_path "clue_corpus_small_14g.jsonl" \ --output_prefix "clue_corpus_small_14g" \ --data_format "JSON" \ --json_key "text" \ --split_sentences \ --data_impl "mmap" \ --chinese \ --cn_whole_word_segment \ --cn_seg_func "lac" \ --log_interval 10000 \ --workers 488.2 OpenWebText2(英文 70GB)
源自 Reddit 的英文网页文本,经去重清洗后含 800 多万个文档。下载解压后直接用create_pretraining_data.py制作(Llama 类无需分词与切句):
python -u create_pretraining_data.py \ --model_name meta-llama/Llama-2-7b \ --tokenizer_name LlamaTokenizer \ --data_format JSON \ --input_path /path/to/openwebtext/ \ --append_eos \ --output_prefix llama_openwebtext \ --workers 40 \ --log_interval 10000 \ --data_impl "mmap"处理约一小时产出llama_openwebtext.bin/.idx,统一放入 data 目录供训练使用。
8.3 WuDaoCorpus2.0 Base(中文 200GB)
WuDaoCorpora 是悟道爬取的中文大规模语料,开源部分约 200GB。由于数据量极大,教程演示了"预分词 → 重转 jsonl → ID 化"的完整链路:
- 下载解压(压缩包约 64GB)后先做语料分词与断句:
python words_segmentation.py \ --input_path ./WuDaoCorpus2.0_base_200G \ --workers 40 \ --data_format wudao \ --cn_seg_func seg \ --output_path ./wudao_lac_cut注意:预训练若需要实现 SOP(Sentence Order Prediction)任务,分词时会用简单规则进行文本断句;如果语料只有一句话,建议去除 SOP loss,训练时设置
binary_head=False。
- 重新转换为 jsonl(此时语料已分词):
python ./trans_to_json.py \ --input_path ./wudao_lac_cut \ --output_path wudao_corpus_200g.jsonl \ --workers 40- 对 llama(未分词路径,直接处理原始 json)或 ernie 进行 ID 化。Ernie 路径由于已提前分词,需加上
--cn_splited:
python -u create_pretraining_data.py \ --model_name "ernie-3.0-base-zh" \ --input_path "wudao_corpus_200g.jsonl" \ --output_prefix "wudao_corpus_200g" \ --data_format "JSON" \ --json_key "text" \ --split_sentences \ --data_impl "mmap" \ --chinese \ --cn_whole_word_segment \ --cn_seg_func "jieba" \ --cn_splited \ --log_interval 10000 \ --workers 488.4 CLUECorpus2020(中文 200GB)
由 Common Crawl 中文部分清洗而来,可通过邮件向 CLUEbenchmark 申请下载。获取后同样走trans_to_json.py+create_pretraining_data.py的标准流程(详见 CLUECorpus2020.md)。
九、预训练启动:数据接入与下一步
数据制作完成后,把.bin/.idx拷贝到训练目录即可启动预训练:
mkdir data mv ./preprocess/baike_sample* ./data- llama 类模型预训练可参考 llm 目录 下的相关配置与启动脚本;
- ernie 类模型预训练可参考 slm/model_zoo/ernie-1.0 的预训练说明(该目录同时维护着动态 mask 的实现 dataset_utils.py)。
十、小结
PaddleNLP 的预训练数据管线在设计上有几个值得借鉴的特点:原始文本转换与 ID 化两个阶段充分解耦,配合可选的预分词环节,让大数据集可以"分步并行、一次分词、多次复用";mmap/lazy两种数据格式兼顾大文件的内存映射提速与简单文件直读;多进程 worker 贯穿转换、分词、ID 化全流程,并支持多份.bin/.idx的按序合并。整体流程参考自 Megatron-LM 的数据处理思路,用户在掌握上述步骤后,既可以沿用现成命令直接处理开源语料,也可以按同样的数据结构接入自有数据,快速构建大规模预训练数据集。
- 人工智能
- 大模型
- 预训练
- 微调
- LoRA
- RLHF
- 强化学习
- 分布式训练
【免费下载链接】PaddleNLP
Easy-to-use and powerful LLM and SLM library with awesome model zoo.
相关推荐
PaddleNLP 预训练数据处理全流程指南:从原始语料到可训练 Token ID
PaddleNLP 预训练数据处理全流程指南:从原始语料到可训练 Token ID PaddleNLP 在 llm/tools/preprocess https
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLPPaddleNLP 预训练数据准备实战:OpenWebText2 英文语料下载、Token 化与 Llama 训练数据生成
PaddleNLP 预训练数据准备实战:OpenWebText2 英文语料下载、Token 化与 Llama 训练数据生成 OpenWebText2 是 Pad
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLPPaddleNLP 中文预训练数据实战:WuDaoCorpus2.0 Base 200GB 语料的获取、分词、ID 化与训练接入全流程
PaddleNLP 中文预训练数据实战:WuDaoCorpus2.0 Base 200GB 语料的获取、分词、ID 化与训练接入全流程 本篇技术指南以 Padd
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考