ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大模型预训练数据管线:清洗、去重与配比实战指南

大模型预训练数据管线:清洗、去重与配比实战指南 在大模型预训练阶段数据清洗、去重与配比策略的重要性经常被低估。很多人把注意力放在模型结构、训练框架和 GPU 数量上却忽略了喂给模型的每一条文本会如何影响模型的知识结构、记忆能力和泛化能力。斯坦福大模型开发课 EP14 专门用一整讲讨论这个主题核心观点非常直接预训练数据不是越多越好而是越干净、越去重、配比越合理越好。本文围绕这一讲的主题从清洗、去重、配比三个环节展开梳理一条可以从零落地到实际训练任务的数据处理管线并给出每个环节的检查点、常见坑和工程建议。这篇文章适合正在做大模型预训练、持续预训练或领域微调数据准备的同学阅读。即使你只负责数据处理不碰训练代码也能从中理解数据质量是如何传导到最终模型效果上的。文中会给出可运行的清洗脚本思路、去重算法原理、配比配置文件示例以及一套可用于排查数据问题的检查清单。1. 预训练数据管线解决什么问题1.1 数据质量会直接决定模型的能力上限预训练模型的参数量和计算量决定了模型能容纳多少知识但数据决定了这些知识是什么、以什么形式被学会。一个典型的反例是如果训练语料里大量重复同一段新闻模型会倾向于把这段新闻背诵下来而不是学习新闻背后的语言规律。另一个反例是低质量网页文本包含大量导航栏、广告、乱码和碎片化句子模型从这些文本里学到的是断裂的语义结构生成时就会出现前言不搭后语的问题。所以数据工作不是“锦上添花”而是“提前决定模型上限”。同样一批 GPU同样的模型结构数据清洗和配比做得更好的团队往往能用更少的数据量训练出更稳定的模型。这也是为什么很多开源大模型的技术报告里都会花很大篇幅描述数据管线而不是只贴训练配置。1.2 清洗、去重、配比三个环节的分工课程标题里的三个关键词正好对应数据管线的三个核心环节它们解决的是不同层次的问题环节目标解决什么问题主要手段清洗去掉噪声和低质量内容乱码、广告、导航、无意义短句、错误文本规则过滤、语言识别、质量打分、敏感信息过滤去重消除重复和近似重复记忆泄露、采样偏差、算力浪费精确哈希、MinHash、SimHash、子串去重配比决定领域数据权重模型知识结构失衡、低资源领域学不好采样概率调整、过采样、下采样、epoch 控制这三个环节不是独立执行的。清洗之后才能去重去重之后才能准确统计每个领域的真实数据量配比才有可靠依据。如果先去重再清洗重复检测会把大量带噪声的文本识别为“相似”结果要么误删要么漏删。实际项目中建议顺序是清洗到一定质量基线后做去重再统计和配比。1.3 在完整预训练流程中的位置数据管线位于原始数据采集和 tokenization 之间。完整的训练数据链路是原始数据采集比如网页爬虫、书籍扫描、论文库、代码仓库。数据清洗把原始格式转成纯文本过滤低质量内容。数据去重消除文档级、段落级和子串级重复。数据配比按领域比例混合所有清洗去重后的语料。Tokenization把文本切分成 token 序列。预训练用采样器按配比概率读取数据。很多人会忽略第 4 步和第 5 步之间的衔接。配比决定的是“数据源出现概率” tokenization 决定的是“每个样本的实际长度”。如果两个领域文档平均长度差异很大按文档数采样和按 token 数采样最终进入训练的实际比例会完全不同。这个细节在后续配比章节会展开。2. 数据清洗从原始网页到高质量语料2.1 预训练语料的主要来源和典型脏数据预训练语料来源可以分成几大类每类的脏数据类型完全不同数据来源典型例子常见脏数据网页爬虫Common Crawl导航菜单、广告、Cookie 提示、HTML 标签残留、乱码书籍电子书、古籍库OCR 错误、目录和页眉页脚、版权页学术论文arXiv、PubMed公式和引用格式混乱、图表说明缺失、重复的模板文本代码GitHub 公开仓库生成文件、依赖锁文件、超长单行、非代码片段百科与问答Wikipedia、StackExchange模板重复、编辑噪音、不同语言混杂这些脏数据如果不处理训练出来的模型会表现出很差的文本连贯性。比如网页爬虫语料里大量“点击这里”“阅读全文”这类模板会让模型在生成时频繁输出无意义短语。2.2 清洗流程的六个典型步骤一个可落地的清洗流程通常包含六个步骤每一步都有关键检查点提取与格式转换。把 HTML、PDF、XML 等格式转成纯文本。HTML 要去除 script、style、nav 标签但要保留正文结构。检查点是抽样查看转换后的文本是否保留了完整段落。语言识别。用 fastText 或类似的语言分类模型判断文本语言筛掉非目标语言内容。检查点是统计各语言占比确认目标语言占比没有异常。规则过滤。按长度、符号比例、重复率等规则过滤明显低质文本。检查点是记录每一条规则的过滤数量避免某条规则误杀过多内容。质量打分。用困惑度、分类器打分等方式对文本质量排序可保留阈值以上的内容。检查点是观察打分分布确认阈值不是拍脑袋定的。敏感信息过滤。去除个人身份信息、联系方式、非法内容等。检查点是做随机抽检确认没有明显残留。内容和偏见过滤。去除有毒内容、成人内容、恶意引导内容。检查点是在最终语料上跑一次内容安全评估。第 3 步和第 4 步最容易混淆。规则过滤是“硬过滤”条件明确、可解释、易调试。质量打分是“软过滤”通过模型或统计指标给出连续分数再设置阈值。推荐先用规则过滤把明显问题处理掉再用质量打分做精细筛选两层配合比单用一层更稳。2.3 质量过滤的常用信号没有一套固定的清洗规则能适配所有语料但以下特征经常被用来判断文本质量特征含义常见处理思路文档长度字符数或 token 数过短文档通常信息量低可设最小长度阈值平均词长字符数除以词数异常高或异常低都可能表示乱码或非目标语言符号占比非字母数字字符比例过高说明可能包含大量代码、公式或乱码重复 n-gram 比例文档内部是否有大量重复片段比例过高说明可能是模板页或机器生成文本困惑度语言模型对文本的惊讶程度困惑度过高说明文本不符合语言规律分类器打分训练二元分类器区分好坏文本可以结合人工标注样本做精细过滤这些信号需要组合使用。单独看文档长度会把很多质量差但长度达标的文本放进来单独看困惑度又会误杀专业术语密集的领域文本。实际项目中建议先用 1000 条样本人工标注确定每个特征的阈值范围再全量执行。2.4 清洗效果的验证方式清洗完不是直接拿去训练先用以下方式验证随机抽样可视化。抽取 100 到 200 条清洗后的文本人工阅读确认语言通顺、结构完整。统计指标对比。记录清洗前后的平均长度、符号占比、重复率、语言分布确认清洗方向符合预期。小规模消融实验。用清洗前后的语料各训练一个很小的模型对比困惑度和下游任务分数。这是最可靠的验证方式但成本最高。需要注意清洗效果验证不能只看“数据变干净了”。有些清洗规则会同时把有价值的专业内容一起删掉。比如严格过滤包含专业符号的文本会误删数学、物理领域的内容。所以验证时要特别关注领域数据的保留率。2.5 学习环境与生产环境的清洗差异学习环境可以用 pandas 处理少量数据脚本简单、跑得快。生产环境至少要面对几十 TB 的原始数据单机脚本根本跑不完而且规模和成本完全不同维度学习环境生产环境数据量GB 级TB 到 PB 级处理工具pandas、Python 脚本Spark、Ray 等分布式框架任务调度直接执行需要任务编排、失败重试、断点续跑可观测性打印日志需要埋点上报、血缘追踪、数据版本管理规则调整改参数重跑改参数后要对比前后版本数据分布差异建议先在小样本上把清洗规则调稳定再迁移到分布式平台。不要一开始就在生产环境里试规则调一次规则跑一次全量任务成本太高。3. 数据去重为什么重复数据比噪声更危险3.1 重复数据的危害重复数据比噪声更危险因为噪声只是影响单条样本重复会系统性扭曲整个数据分布。具体危害可以归纳为四点采样偏差。重复内容在训练集中被过度表示模型会认为这类内容比实际更重要导致输出偏向高频内容。记忆与泄露。模型可能直接背诵训练语料中的重复段落。如果评测集与训练集有重叠评测分数会虚高无法反映真实能力。训练不稳定。大量重复文档可能让 loss 出现周期性波动影响学习率和训练收敛。算力浪费。重复文档占用的训练时间是无效的对模型能力的提升几乎为零。这里要特别强调评测集污染问题。很多团队只对训练数据做去重忽略了评测集。如果评测文本在训练语料里出现过最终成绩会失真。正确做法是同时做训练集和评测集的交叉去重确保评测集文本与训练集没有明显 n-gram 重叠。3.2 精确去重与模糊去重根据重复的形态去重方法可以分为两层第一层是精确去重。整篇文档完全相同或者去掉空白后完全相同。实现最简单用哈希就能完成。把每条文档的哈希值存入一个集合遇到相同哈希就删除。对于海量数据可以用 Bloom filter 减少内存占用但 Bloom filter 有误判率工业实践中通常会配合原始哈希做二次确认。第二层是模糊去重。大多数网页重复不是完全一样而是“近似重复”比如同一篇文章在不同网站的转载会带上各自不同的页眉页脚。精确哈希检测不出来需要计算文档相似度。常用的方法是 MinHash 和 SimHash。MinHash 适用于文本集合相似度SimHash 适用于大规模文本去重和相似检索两者的核心都是用降维后的指纹近似表示文档内容。3.3 MinHash 去重原理和一个最小示例MinHash 的基本思想是如果两篇文档足够相似它们包含相同 n-gram 的比例就会高。把文档切分成 n-gram 集合然后对每个 n-gram 做哈希取最小值作为签名。两个文档的 MinHash 签名中相同位置的比例可以近似表示它们的 Jaccard 相似度。下面是一个简化示例用于说明思路import hashlib def shingles(text: str, k: int 5): 把文本切成 k 个词的滑动窗口集合 tokens text.split() if len(tokens) k: return set() return { tuple(tokens[i:i k]) for i in range(len(tokens) - k 1) } def minhash_signature(shingle_set, num_hashes: int 128): 对每个 shingle 做哈希对每个哈希函数取最小值作为签名 signature [] for seed in range(num_hashes): min_hash None for shingle in shingle_set: hash_input f{seed}:{shingle}.encode(utf-8) value int(hashlib.md5(hash_input).hexdigest(), 16) if min_hash is None or value min_hash: min_hash value signature.append(min_hash) return signature def similarity(sig_a, sig_b) - float: 比较两个签名的相同位置比例 if not sig_a or not sig_b: return 0.0 same sum(1 for a, b in zip(sig_a, sig_b) if a b) return same / len(sig_a)这个示例简化了真实实现。生产环境不会用 Python 双层循环计算海量文档签名通常会用datasketch这样的库配合 LSH 分桶把“所有文档两两比较”变成“只比较可能的相似候选对”。示例的价值在于理解原理shingle 决定相似度计算的粒度哈希函数数量决定近似精度。3.4 去重粒度选择去重粒度决定了你能去掉哪类重复也决定了计算量粒度检测对象适用场景成本文档级整篇文档的相似度重复转载网页、重复文章低段落级文档内每个段落文档中嵌入了重复片段中n-gram 级连续 token 或连续词需要彻底去除长重复子串高文档级去重最快但会放过“一篇文章里插入一段重复内容”的情况。段落级去重更精细适合网页正文中夹带公共模板内容的场景。n-gram 级最彻底但计算量大而且阈值设置不当会误删合理重复的短语。实际项目常常是分层执行先文档级去重再段落级去重最后对剩余高风险部分抽样检查。不要一开始就追求最高粒度先看看重复主要出现在哪个层级再决定投入多少算力。4. 数据配比塑造模型知识结构的旋钮4.1 配比为什么重要配比决定的是模型的知识结构。如果代码数据占比过高模型代码能力会强但自然语言流畅度可能下降如果百科和书籍占比过高模型语言表达会规范但缺少真实世界的网络语言多样性。预训练最重要的目标之一是让模型在不同领域之间取得平衡而不是只精通某一个领域。配比和模型规模、数据总量之间存在联动关系。数据总量固定时某个领域占比越高该领域数据被重复采样的次数就越多。重复次数过多模型会趋向记忆而不是泛化。所以配比不能只看“这个领域重要就多加”还要考虑每个领域的实际数据量和重复容忍度。4.2 常见参考配比不同团队公开的配比差异很大因为和基座模型定位有关。一个常见的通用预训练参考配比如下领域参考占比说明网页文本50% - 60%提供多样性和真实语言用法质量过滤后仍需保留较大比例代码15% - 25%提升逻辑推理和代码能力注意过滤生成文件书籍10% - 15%提供长文本连贯性和深度知识学术论文5% - 10%提供专业领域知识公式和引用格式要先处理百科与问答3% - 5%高质量结构化知识量少但价值高对话与指令1% - 3%为后续对齐做准备量不宜过大这张表是说明性参考不是标准答案。实际配比要结合可用数据量、模型定位和评测目标调整。如果做代码模型代码占比可以大幅提高如果做通用助手网页和问答占比可能需要重新权衡。4.3 采样概率、重复次数与过采样配比落到训练代码里通常体现为数据集的采样概率。这里有一个非常容易踩的坑按文档数采样和按 token 数采样结果完全不同。假设百科文档平均 2000 token网页文档平均 500 token如果想让两者 token 占比相同就需要在文档采样概率上让百科约为网页的四分之一。另一个关键参数是每个数据集的重复次数。对于书籍和百科这类高质量但量少的数据可以适当重复 2 到 3 个 epoch对于网页文本通常只训练 1 个 epoch。重复次数过高会导致过拟合和记忆这个约束比占比更重要。4.4 用验证集校准配比配比很少能一次定好。推荐的做法是先按经验设定初始配比。用一个较小的验证集覆盖各下游任务和领域。训练小规模的模型观察各领域指标。根据短板调整配比再训练下一轮。关键在于验证集必须按固定标准构建且保证与训练集去重。否则验证集本身存在污染调整配比时会走错方向。也可以用领域困惑度作为中间指标如果模型在某个领域语料上的困惑度明显偏高说明该领域数据不足可以适当提高配比。5. 一条可落地的预训练数据管线示例5.1 管线总览下面这条管线适合从零开始搭建也适合在开源工具基础上做定制。整体分四段原始数据存储、清洗、去重、配比与输出。raw/ 清洗 clean/ 去重 dedup/ 配比 train/ 网页/书籍/论文 -------- 清洗后语料 -------- 去重后语料 -------- 混合训练集 .jsonl .jsonl .jsonl .arrow / .jsonl生产环境建议用 JSONL 作为中间格式每行一条 JSON 文档包含text、meta来源、语言、长度、质量分数等字段。中间格式要保留元信息不要在清洗过程中丢弃否则后期排查问题没有线索。5.2 清洗脚本示例以下脚本演示了用启发式规则做第一层过滤import json import re MIN_LEN 200 MAX_SYMBOL_RATIO 0.4 MAX_REPEAT_RATIO 0.3 def symbol_ratio(text: str) - float: # 统计非中英文、非数字、非空白的字符比例 cn_en re.findall(r[\u4e00-\u9fffA-Za-z0-9\s], text) if not text: return 1.0 return 1 - len(cn_en) / len(text) def repeat_ratio(text: str) - float: lines [line.strip() for line in text.splitlines() if line.strip()] if not lines: return 1.0 # 用行的唯一性近似衡量重复程度 return 1 - len(set(lines)) / len(lines) def clean_document(doc: dict) - dict: text doc[text].strip() if not text: return None if len(text) MIN_LEN: return None if symbol_ratio(text) MAX_SYMBOL_RATIO: return None if repeat_ratio(text) MAX_REPEAT_RATIO: return None doc[clean_text] text doc[meta][symbol_ratio] round(symbol_ratio(text), 4) return doc这段代码的关键点在于clean_document返回None表示该文档被过滤保留的文档会追加质量指标到meta中。这些指标后续可以用于统计清洗比例、分析误删情况。实际项目中建议把每条过滤规则的触发情况单独记录而不是只返回最终结果。否则无法回答“数据为什么少了 30%”这个问题。5.3 去重脚本示例去重用简化 MinHash 思路可以写成一个 Spark 风格的伪代码但实际生产中更推荐直接用成熟库。以datasketch为例最小用法如下from datasketch import MinHashLSH, MinHash # 每个文档生成一个 MinHash 对象 def doc_to_minhash(text: str, num_perm: int 128): tokens text.split() m MinHash(num_permnum_perm) for token in tokens: m.update(token.encode(utf-8)) return m # 建立 LSH 索引阈值设 0.8 表示相似度高于 0.8 认为是重复 lsh MinHashLSH(threshold0.8, num_perm128) for doc_id, text in documents.items(): m doc_to_minhash(text) lsh.insert(doc_id, m) # 查询每个文档的相似文档 for doc_id, text in documents.items(): m doc_to_minhash(text) candidates lsh.query(m) # candidates 中包含与当前文档相似的其他文档 id按需决策删除这里要注意LSH 返回的是候选集合还需要进一步用精确 Jaccard 相似度确认避免误删。阈值不是越高越好阈值越高漏掉近似重复的风险越大。一般先取 0.7 到 0.9 之间做实验抽样观察被标记为重复的文档是否真的是重复。5.4 配比配置文件示例配比建议用 YAML 或 JSON 单独管理方便版本化和对比实验mix: - name: web path: data/dedup/web.jsonl ratio: 0.55 repeat: 1 - name: code path: data/dedup/code.jsonl ratio: 0.20 repeat: 1 - name: books path: data/dedup/books.jsonl ratio: 0.15 repeat: 2 - name: wiki_qa path: data/dedup/wiki_qa.jsonl ratio: 0.10 repeat: 2这里的ratio是 token 占比目标repeat是最大重复 epoch 数。加载数据时先按ratio计算每个数据集每个 epoch 需要采样的 token 数再转换成采样概率。配置文件一旦确定就要和训练日志一起存档保证后续可以回溯“这次训练用了哪个版本的数据配比”。5.5 数据质量报告完整的数据管线需要输出质量报告至少包含以下指标指标作用总量原始 token 数、清洗后 token 数、去重后 token 数过滤率每条规则过滤的文档数占比去重率被识别为重复并删除的文档数占比语言分布目标语言和其他语言的比例领域分布配比后的实际 token 分布与目标配比的偏差重复监测训练集与评测集的重叠度可以用一个简单脚本统计这些指标或者用数据平台自带的报表功能。质量报告不是为了好看而是为了在模型效果出问题时能快速定位是数据哪个环节引起的。6. 常见问题与排查路径6.1 训练 loss 出现周期性尖峰或明显波动现象loss 曲线稳定下降但每隔若干步出现一次尖峰或者某一段训练 loss 明显偏高。排查链路先确认 dataloader 是否开启了 shuffle。未开启时同一批次的数据顺序固定可能连续出现某个异常难学的领域。检查是否为数据重复。计算相邻样本或同批次样本的重叠度如果重复率很高说明去重不彻底。检查删除和后处理是否改变文本结构。比如清洗时把换行全删了导致 tokenizer 切分异常。检查 tokenizer 的截断策略。超长文档被截断后可能残留不完整的句子造成 loss 尖峰。解决方案开启 shuffle补充去重修正清洗规则设置合理的样本最大长度与截断策略。6.2 模型能背诵训练语料或评测集分数虚高现象模型在开放生成任务里直接输出训练语料原文评测集准确率异常高明显不合理。原因训练集与评测集存在重叠或训练数据重复过多导致记忆。排查链路用 n-gram 重叠检测评测集与训练集。取评测问题的连续 n 个 token到训练集里检索统计命中率。检查重复率是否为 0。如果文档级去重后重复率仍很高检查段落级重复。检查是否需要按评测集窗口做精细去重而不是只按整篇文档去重。解决方案构建评测集污染黑名单在去重阶段同时标注和去除与评测集高度重合的文档并在每次数据集更新后重新检测。6.3 清洗后数据量骤减现象原始数据 100 TB清洗后只剩 20 TB明显低于预期。原因某条过滤规则过严或者语言识别把大量有效文本判为其他语言。排查链路统计每条规则的过滤文档数找到占比异常高的规则。抽样查看被该规则过滤的文档确认是否存在误杀。检查语言分类模型是否对领域文本有偏见。比如学术文本包含大量公式符号占比天然偏高容易触发符号过滤。解决方案分领域设置不同阈值增加按质量分数排序而非硬删除的机制用软过滤替代部分硬过滤。6.4 去重任务内存溢出或耗时过长现象去重程序运行几小时后 OOM或者完成一次全量去重要好几天。原因内存中保存了过多文档签名或使用了全量两两比较。排查链路用哈希分桶把文档按签名前缀分到不同桶逐桶处理。用 LSH 减少候选对数量不要对所有文档做两两比较。检查是否可以把数据分片并行使用 Spark 或 Ray 提升吞吐。如果内存仍然紧张考虑用 Bloom filter 做第一轮粗筛再用精确哈希做第二轮确认。解决方案按“粗筛 精判”两层结构实现去重用分桶和并行化控制资源占用。7. 最佳实践与扩展方向7.1 数据管线检查清单每次准备新数据或调整数据管线时建议按下面这个清单走一遍[ ] 是否保留原始数据快照和处理脚本版本能随时回溯某批数据的来源[ ] 清洗规则是否在小样本上抽样验证过确认没有明显误删[ ] 是否记录了每条规则的过滤数量能够解释数据量变化的原因[ ] 是否在清洗后执行了文档级、段落级去重[ ] 是否对训练集与评测集做了交叉去重排除评测污染[ ] 是否统计了清洗后的语言分布、领域分布和重复率[ ] 配比目标是按 token 计算还是按文档数计算两者是否混淆[ ] 每个数据集的重复 epoch 是否控制在合理范围[ ] 配比配置文件、数据版本号和处理脚本是否一起存档方便实验复现[ ] 是否用小规模训练验证过数据质量而不是只看统计指标这个清单可以直接用于代码评审或数据发布前的检查。7.2 从学习环境到生产环境的扩展路径如果是从零开始建议按三个阶段扩展第一阶段单机跑通。用 pandas 和 Python 脚本处理几 GB 数据验证清洗和去重规则是否合理形成稳定的处理逻辑。第二阶段并行化重构。把脚本迁移到 Spark 或 Ray加入失败重试、断点续跑和日志埋点。这个阶段要保证清洗顺序和去重逻辑与单机版本一致。第三阶段数据治理。引入数据血缘、版本管理和自动化报表。每次数据更新都能生成新的数据集版本训练实验与数据集版本严格绑定这样定位模型问题时能快速缩小范围。7.3 下一步可以深入的方向预训练数据领域还有很多值得继续深入的方向。课程之外的常见扩展点包括持续预训练时的数据选择策略如何从旧数据中识别新知识合成数据在预训练中的使用边界什么时候用合成数据补足真实数据以及数据飞轮也就是从模型评测和用户反馈中回收高质量数据进入下一轮训练。对于初学者最有效的练习方式是自己下载一个小型公开语料完成清洗、去重、配比三个环节的全流程记录每个环节的数据变化最后训练一个很小的模型观察效果。跑通一次完整的数据闭环比看十篇理论文章更有价值。预训练数据的核心并不在于某个具体算法有多复杂而在于你是否建立了可观测、可回溯、可迭代的数据处理流程。
返回列表