新闻详情

新闻详情

首页 / 资讯中心 / 详情

大模型预训练数据质量过滤:MindSpore多级流水线实战

发布时间:2026/10/2 3:30:12来源:尧图网络
大模型预训练数据质量过滤:MindSpore多级流水线实战
1. 大模型预训练里数据质量过滤到底在解决什么问题做过大模型预训练的人都有一个共识模型效果的上限很大程度上在数据准备阶段就已经被决定了。你后面调参、换优化器、加训练轮次能拉回来的空间其实很有限。而数据质量过滤就是数据准备阶段里最容易被低估、又最不能省的一环。我先把话说直白一点所谓数据质量过滤就是从海量原始语料里把那些“会拖后腿”的内容挑出来扔掉或者降权。这些内容大致分几类——重复的、乱码的、机器批量生成的、广告灌水的、格式错乱的、语义不完整的、有害的。它们混在训练集里轻则浪费算力重则让模型学会一堆坏习惯比如复读、胡言乱语、输出格式崩坏。在 MindSpore 这套框架下做大模型预训练数据质量过滤的方案设计和 PyTorch 生态有相通之处但也有它自己的特点。MindSpore 的数据处理链路主要围绕mindspore.dataset展开配合MindRecord这种自有数据格式以及mindspore.dataset.text下的各类文本变换算子。这意味着过滤逻辑要么在数据进入 Dataset 管道之前用离线脚本处理完要么在管道里用算子做在线过滤。两种方式各有取舍后面我会详细拆。这篇文章适合谁看如果你正在用 MindSpore 做百亿甚至千亿参数级别的预训练手头有 TB 级别的原始语料正在为“数据太脏导致 loss 降不下去”或者“模型输出重复严重”发愁那这篇内容基本就是给你写的。如果你只是做小规模微调数据量在 GB 级别那这里的部分方案可能偏重但过滤思路依然可以借鉴。我自己的经验是一个成熟的预训练数据过滤方案通常不是单一手段而是多级流水线粗过滤去明显垃圾细过滤去语义低质去重控制冗余最后再做质量打分和采样配比。每一级的阈值怎么定、用什么指标、在哪个环节执行都有讲究。下面我按这个流水线的顺序把每个环节拆开讲。2. 过滤方案的整体设计与流水线拆解2.1 为什么不能只做单一过滤新手最容易犯的错就是只用一个规则或者一个模型做过滤。比如只做去重或者只用一个困惑度阈值卡一遍。实测下来这种单点方案漏网之鱼非常多。原因很简单低质数据的“脏”是多种多样的。重复文本靠去重解决但乱码和广告靠去重是去不掉的困惑度能筛掉语义不通的句子但对格式规整的机器生成内容又不够敏感。所以必须做分层过滤每一层针对一类问题层层收窄。我一般把整个流水线分成四个阶段格式与字符级粗过滤处理编码错误、乱码、超短文本、HTML 残留、特殊符号堆砌。重复与冗余过滤处理完全重复、近似重复、段落级重复。语义与质量细过滤用统计指标或小模型打分筛掉语义低质内容。领域配比与采样按目标领域分布做加权采样控制各类数据比例。这四个阶段的顺序不能乱。粗过滤必须放最前面因为如果先做语义打分那些乱码文本会白白消耗模型推理算力。去重放在语义过滤之前也有讲究——重复内容如果先被语义模型打分等于同一段文本被反复评估浪费资源。2.2 离线过滤与在线过滤的取舍在 MindSpore 里过滤逻辑放哪里执行是个关键决策。离线过滤指的是在训练开始前用独立的 Python 脚本可以配合 Spark、Ray 或者纯多进程把原始语料清洗成干净的数据集再转成 MindRecord 格式喂给训练。优点是过滤逻辑灵活可以用任意第三方库不占用训练时的算力缺点是数据一旦处理完就固定了想调整阈值得重新跑一遍全量数据。在线过滤指的是在mindspore.dataset管道里用map操作挂载自定义过滤函数或者用内置的文本算子做实时过滤。优点是灵活可调改阈值不用重跑离线任务缺点是过滤逻辑会占用训练时的 CPU 资源如果过滤函数写得重可能成为数据加载瓶颈。我的建议是混合使用重逻辑比如语义模型打分、大规模去重放离线轻逻辑比如长度过滤、简单规则放在线兜底。这样既保证过滤质量又不至于拖慢训练。提示MindSpore 的dataset.map支持num_parallel_workers参数在线过滤时一定要把这个值调大否则单线程过滤会成为整个训练管道的瓶颈。我一般设成 CPU 核数的 70% 左右。2.3 过滤强度的平衡问题过滤太松脏数据进模型过滤太狠数据量骤减模型欠拟合。这个平衡点怎么找我的经验是先统计后定阈值。不要拍脑袋定一个“困惑度大于 100 就扔掉”而是先对全量数据算一遍指标分布看 P50、P90、P99 分位数在哪再决定卡在哪个位置。通常我会保留 85% 到 92% 的数据具体看原始语料本身的干净程度。另外过滤强度要跟数据总量挂钩。如果你有 10TB 原始数据扔掉 30% 还剩 7TB完全扛得住但如果你只有 500GB扔掉 30% 可能就不够了。这种情况下与其硬过滤不如对低质数据做降权采样而不是直接丢弃。3. 核心过滤环节的实操细节与参数计算3.1 字符级粗过滤的具体规则这一层看起来简单但细节最多。我列一下我实际在用的规则以及每条规则背后的理由。编码与乱码处理原始语料里经常混入非 UTF-8 编码的片段或者 Unicode 替换字符UFFFD。这类内容必须直接丢弃因为模型学到的就是乱码。检测方法是统计替换字符占比超过 0.5% 就整条丢弃。长度过滤太短的文本比如少于 20 个字符信息量不足太长的文本比如超过 10000 字符往往是拼接或爬取错误。我一般保留 50 到 8000 字符之间的文本。这个区间不是绝对的要看你的模型上下文长度。如果你训练的是 2048 上下文那单条文本控制在 2000 字符以内更合理。特殊符号比例统计非字母、非数字、非标点符号的字符占比。如果一条文本里 emoji、数学符号、控制字符占比超过 15%基本可以判定为垃圾。这里要注意代码类语料本身符号比例就高所以规则要按领域区分。HTML 与 Markdown 残留爬取的网页数据经常带div、nbsp;、\n\n\n这类残留。用正则批量清理清理后如果文本长度骤减超过 50%说明原文主要是标签直接丢弃。import re def char_level_filter(text, min_len50, max_len8000): if not text or not isinstance(text, str): return False # 替换字符检测 if text.count(\ufffd) / max(len(text), 1) 0.005: return False # 长度检测 if len(text) min_len or len(text) max_len: return False # 特殊符号比例 special sum(1 for c in text if not c.isalnum() and not c.isspace() and c not in 。、《》.,!?;:()[]) if special / len(text) 0.15: return False # HTML 残留 text_clean re.sub(r[^]|[a-z];, , text) if len(text_clean) / len(text) 0.5: return False return True这段代码可以直接挂到dataset.map里做在线过滤也可以离线批量跑。实测在 8 核机器上单进程每秒能处理约 2 万条短文本性能足够。3.2 去重从精确匹配到近似匹配去重是数据过滤里收益最高的一环也是最容易做过头的一环。精确去重最简单对每条文本算 MD5 或 SHA256用集合去重。这一步能去掉 5% 到 15% 的完全重复内容成本极低必做。近似去重才是重头戏。网页爬取的数据里同一篇文章经常被转载几十次只是标题或页脚略有不同。这种靠精确哈希是去不掉的。主流做法是MinHash LSH或者用SimHash。我个人的选择是 MinHash因为它在文本长度差异较大时表现更稳定。具体流程是对每条文本做 n-gram 切分n 取 5 比较合适然后算 128 个 MinHash 签名再用 LSH 分桶桶内两两比较 Jaccard 相似度超过 0.8 的判定为重复保留其中一条。参数上n-gram 的 n 值很关键。n 太小比如 3相似度普遍偏高容易误杀n 太大比如 10又抓不住近似重复。我试过 5 和 7最终定在 5因为中文语料的字符级 n-gram 在 5 左右区分度最好。Jaccard 阈值 0.8 也不是拍脑袋来的。我做过对比实验阈值 0.7 时去重率约 22%但会误删一些主题相似但内容不同的文章阈值 0.9 时去重率只有 8%漏网较多。0.8 是个比较平衡的点去重率在 15% 左右误删率控制在 2% 以内。注意去重一定要在语义过滤之前做。否则同一段重复文本会被语义模型反复打分白白浪费算力。我见过有人把顺序搞反结果过滤阶段耗时翻了三倍。3.3 语义质量打分的指标选择到了这一层就要判断“这段文本是不是人写的、有没有信息量”。常用的指标有三个困惑度、重复率、以及基于小模型的质量分类器。困惑度Perplexity是最经典的指标。用一个在干净语料上训练好的 n-gram 或小 Transformer 模型对每条文本算困惑度。困惑度越高说明文本越不符合自然语言分布越可能是乱码或机器生成。但困惑度有个坑它对领域很敏感。用新闻语料训练的模型去评估代码语料困惑度会普遍偏高导致误杀。所以困惑度模型必须和目标领域匹配。重复率指的是文本内部 n-gram 的重复比例。有些机器生成的内容句子结构高度雷同比如“XX 是一种 XXXX 具有 XX 的特点”反复出现。统计 4-gram 重复率超过 0.3 的判定为低质。质量分类器是近几年更流行的做法。用一个人工标注过“高质量/低质量”的小模型比如 1 亿参数级别的 BERT对每条文本打分。这个方案效果最好但成本也最高通常只在大规模预训练时用。我的实际配置是先用重复率做快速筛除成本低再用困惑度做中等筛除最后用质量分类器对边界样本做精细判断。三级串联既控制成本又保证效果。3.4 领域配比与采样权重计算过滤完之后还要解决“各类数据放多少”的问题。预训练语料通常包含网页、书籍、代码、论文、问答等多个领域如果直接混合网页数据往往因为量最大而主导训练导致模型偏向网页风格。我的做法是按目标 token 数反推采样权重。假设我计划训练 1T token希望各领域配比是网页 50%、书籍 20%、代码 15%、论文 10%、问答 5%。那么先统计每个领域过滤后的可用 token 数再算出每个领域的采样概率。如果某个领域数据不够比如问答只有 2% 的量那要么接受这个比例要么对问答数据做上采样重复使用但上采样比例不宜超过 3 倍否则容易过拟合。def compute_sampling_weights(domain_token_counts, target_ratios): total_target sum(domain_token_counts.values()) weights {} for domain, count in domain_token_counts.items(): target total_target * target_ratios.get(domain, 0) if count target: weights[domain] target / count else: weights[domain] min(3.0, target / count) return weights这个权重可以直接传给 MindSpore 的dataset.sampling或者自定义的采样器控制每个 batch 里各领域的比例。4. 在 MindSpore 里落地过滤流水线4.1 离线处理与 MindRecord 生成大规模预训练数据我强烈建议离线处理完再转 MindRecord。原因有两个一是离线可以用多机并行处理 TB 级数据效率高二是 MindRecord 读取性能比原始文本好很多训练时数据加载不会成为瓶颈。离线处理的流程是原始语料 - 字符级过滤 - 去重 - 语义打分 - 领域配比 - 写出为 JSONL 或 TFRecord - 转 MindRecord。转 MindRecord 用mindspore.mindrecord.FileWriter核心代码如下import mindspore.mindrecord as ms_mindrecord schema {text: {type: string, size: -1}} writer ms_mindrecord.FileWriter(train.mindrecord, shard_num16, overwriteTrue) writer.add_schema(schema, pretrain_data) with open(filtered.jsonl, r, encodingutf-8) as f: batch [] for line in f: item json.loads(line) batch.append({text: item[text]}) if len(batch) 1000: writer.write_raw_data(batch) batch [] if batch: writer.write_raw_data(batch) writer.commit()shard_num设成 16 是为了让后续分布式训练时每个卡读一个分片减少 IO 竞争。这个值一般设成训练卡数的整数倍。4.2 在线过滤管道的搭建有些轻量过滤逻辑我放在在线管道里做方便随时调整。MindSpore 的dataset.map支持自定义 Python 函数配合num_parallel_workers并行执行。import mindspore.dataset as ds import mindspore.dataset.text as text def filter_op(text_bytes): text_str text_bytes.decode(utf-8) if not char_level_filter(text_str): return b return text_bytes dataset ds.MindDataset(train.mindrecord, columns_list[text], num_parallel_workers8) dataset dataset.map(operationsfilter_op, input_columns[text], num_parallel_workers8, python_multiprocessingTrue) dataset dataset.filter(predicatelambda t: len(t) 0, input_columns[text]) dataset dataset.batch(32, drop_remainderTrue)这里有个细节map之后接filter把返回空字符串的样本丢掉。python_multiprocessingTrue能显著提升 CPU 密集型过滤函数的吞吐但要注意过滤函数必须是可序列化的顶层函数不能用 lambda 或闭包。4.3 训练时的数据加载性能调优过滤逻辑加进去之后数据加载容易变慢。我踩过的坑是过滤函数里做了太多字符串操作导致单个样本处理耗时超过 1ms整个管道吞吐掉到原来的三分之一。调优手段有几个一是把重逻辑挪到离线在线只做轻量兜底二是调大num_parallel_workers和prefetch_size三是用dataset.prefetch做预取让数据加载和模型计算重叠。dataset dataset.prefetch(buffer_sizeds.config.get_prefetch_size())prefetch_size默认是 16我一般调到 64 甚至 128具体看内存。预取太多会占内存太少又起不到重叠效果。实测在 32 核机器上prefetch 设 64 时数据加载基本不拖后腿。提示如果你用的是 Ascend 卡训练数据加载走的是 host 侧 CPU一定要确保 CPU 核数足够。我见过 8 卡训练只给 16 核 CPU 的配置数据加载直接成为瓶颈GPU/NPU 利用率只有 40%。5. 常见问题与排查技巧实录5.1 过滤后数据量骤减怎么办这是最常见的问题。本来 10TB 数据过滤完只剩 4TB训练 token 不够了。排查思路是逐级统计保留率。把每个过滤阶段的输入输出数量都打点记录看是哪一级掉得最狠。如果是字符级过滤掉太多说明原始数据质量差或者阈值定太严如果是去重掉太多说明数据源重复严重需要换数据源或者放宽 Jaccard 阈值。我的处理原则是如果某一级保留率低于 70%就要重新审视阈值。字符级过滤保留率一般应在 85% 以上去重保留率在 80% 以上语义过滤保留率在 75% 以上。低于这些值要么阈值太严要么数据源本身有问题。如果确实数据不够可以考虑降权而非丢弃。把低质数据的采样权重降到 0.1而不是直接扔掉这样既减少负面影响又保留数据量。5.2 模型输出重复严重是过滤没做好吗模型复读机现象很多人第一反应是数据去重没做好。但实际上去重只是原因之一。我遇到过几次复读问题排查下来原因各不相同有一次是去重阈值太松近似重复没去干净有一次是训练时某几类数据被上采样太多模型过拟合了那部分还有一次是解码策略问题跟数据无关。排查顺序建议是先看去重阶段的 Jaccard 阈值是不是太低再看领域采样权重是不是有某个领域超过 3 倍上采样最后再排查解码参数。数据侧的问题通常表现为模型对某些句式特别执着而不是完全随机复读。5.3 过滤函数报编码错误怎么处理原始语料里混入非 UTF-8 编码是常态。Python 读取时如果直接decode(utf-8)遇到非法字节会抛UnicodeDecodeError导致整个管道中断。处理方法是用 errors 参数容错text_str text_bytes.decode(utf-8, errorsreplace)errorsreplace会把非法字节替换成 UFFFD然后你在字符级过滤里检测替换字符比例超标的直接丢弃。这样既不会中断管道又能把脏数据筛掉。另一个坑是 BOM 头。有些文件带 UTF-8 BOM读取后开头会多一个\ufeff影响后续处理。用encodingutf-8-sig读取可以自动去掉。5.4 常见问题速查表问题现象可能原因排查方向解决手段过滤后数据量骤减阈值过严或数据源差逐级统计保留率放宽阈值或降权采样模型输出重复去重不彻底或上采样过度检查 Jaccard 阈值和采样权重收紧去重或限制上采样倍数编码错误中断管道非 UTF-8 字节检查原始文件编码decode 加 errors 参数数据加载慢在线过滤逻辑过重看单样本处理耗时重逻辑挪离线调大并行度困惑度误杀严重困惑度模型领域不匹配对比目标领域分布换领域匹配的困惑度模型训练 loss 震荡数据质量波动大检查各 batch 数据来源固定采样配比打散数据5.5 几个我踩过的坑第一个坑是去重顺序。我早期把语义过滤放在去重前面结果同一篇转载文章被打了十几次分过滤阶段耗时是正常情况的三倍。后来把去重提前耗时直接降下来。第二个坑是在线过滤用 lambda。MindSpore 的map在多进程模式下lambda 无法序列化会报错。必须用顶层函数。这个错误信息不太直观我查了半天才定位到。第三个坑是MindRecord 分片数设太少。一开始我设成 4结果 8 卡训练时每个分片被两张卡同时读IO 竞争严重。后来改成 16问题解决。分片数建议是训练卡数的 2 到 4 倍。第四个坑是过滤阈值写死在代码里。后来想调整阈值得改代码重新跑全量数据非常痛苦。现在我都会把阈值抽成配置文件过滤脚本读配置执行调整起来方便很多。6. 过滤效果评估与迭代思路6.1 怎么判断过滤方案好不好过滤方案不是做完就完事了得评估效果。我一般从三个维度看数据侧指标各阶段保留率、去重率、领域分布。这些指标反映过滤的“力度”但不反映“质量”。模型侧指标用过滤后的数据训练一个小模型比如 1B 参数看验证集 loss、生成质量、复读率。这是最直接的评估方式但成本高通常只在方案大改时做。人工抽检从过滤后的数据里随机抽 200 条人工判断有多少是真正高质量的。这个比例我一般要求达到 90% 以上。如果低于 85%说明过滤还不够。我通常的做法是先用数据侧指标快速迭代把保留率和去重率调到合理区间然后训一个小模型做验证最后人工抽检确认。三步走下来方案基本就稳了。6.2 迭代时优先调什么如果模型效果不达预期优先调什么我的经验排序是第一优先调去重阈值。去重对模型复读问题的影响最大而且调整成本低重跑一遍去重就行。第二优先调领域配比。如果模型在某类任务上表现差很可能是对应领域数据配比不够。调整采样权重重新训练即可。第三优先调语义过滤阈值。这个影响相对温和而且调整成本高要重跑语义打分一般放在最后。字符级过滤的阈值我基本不动因为那部分规则比较硬调整空间不大。6.3 后续可以扩展的方向这套方案目前是规则加统计指标为主后续可以往几个方向扩展。一是引入更强的质量分类器。用更大参数量的模型做质量打分效果会更好但成本也更高。可以在关键领域比如代码、论文上用网页数据继续用轻量方案。二是做动态过滤。训练过程中根据模型表现动态调整数据配比比如某个领域 loss 降得慢就临时提高该领域采样权重。这个思路在学术界有相关研究工程落地还在探索阶段。三是建立数据质量反馈闭环。把模型评估结果反哺到数据过滤环节形成“过滤-训练-评估-再过滤”的循环。这个工程量比较大但长期看收益明显。我个人在实际操作中的体会是数据质量过滤没有一劳永逸的方案它是一个持续迭代的过程。每次换数据源、换模型规模、换训练目标过滤方案都得重新审视一遍。把过滤逻辑做成可配置、可插拔的流水线比追求某个“最优阈值”更重要。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Vibe Coding 实战:从提示词工程到 Agent 模式的工程化落地 2026/10/2 4:28:05

Vibe Coding 实战:从提示词工程到 Agent 模式的工程化落地

1. 从“会写代码”到“会描述意图”:Vibe Coding 到底改了什么“Vibe Coding”这个词最近在开发圈子里出现的频率越来越高,很多人第一次听到会以为是某种新的编程语言或者框架,其实它描述的是一种工作方式的转变:开发者不再逐行敲…

阅读更多 →
LimiX-2:面向表格数据的语义块掩码建模 2026/10/2 4:28:05

LimiX-2:面向表格数据的语义块掩码建模

1. LimiX-2不是“另一个BERT复刻”,而是表格数据专属的预训练范式重构你可能刚在论文列表里扫到“LimiX-2 表格模型的masked modeling”这个标题,下意识点开——结果发现满屏公式、消融实验和Ablation Table,连一句“它到底解决了什么实际问题…

阅读更多 →
Codex CLI接入Jev本地模型:OpenAI兼容协议下的高效AI编程配置实战 2026/10/2 4:28:05

Codex CLI接入Jev本地模型:OpenAI兼容协议下的高效AI编程配置实战

给ChatGPT账号充值像割肉、官方的模型偶尔还闹脾气限流,这是我把Codex CLI用起来之后最真实的感受。Codex本身没得说,面向任务的Agent式工作流,规划、改代码、跑验证一步到位,用顺手了是真的回不去。但默认模式下它非常依赖ChatGP…

阅读更多 →
PSO优化Elman回归预测:从初值寻优到可复现的训练流程 2026/10/2 4:28:04

PSO优化Elman回归预测:从初值寻优到可复现的训练流程

简介:面向多变量回归预测与智能优化建模需求,这份资源提供了一套基于粒子群算法(PSO)优化Elman递归神经网络的完整预测模型,适合机器学习、智能计算及数据预测方向的研究者与工程人员使用。PSO-Elman将粒子群全局寻优能力与Elman网络的动态递…

阅读更多 →
VS2017 64位下OSG+osgworks+Bullet3+osgbullet编译与碰撞检测集成指南 2026/10/2 4:28:04

VS2017 64位下OSG+osgworks+Bullet3+osgbullet编译与碰撞检测集成指南

简介:本资源为VS2017 64位环境下编译生成的osg、osgWorks、Bullet3与osgbullet库集合,面向从事三维游戏开发、物理仿真与可视化应用的C开发者,尤其适合需要在Windows平台快速集成3D渲染与碰撞检测的中高级技术人员。压缩包为rar格式&#xff…

阅读更多 →
Python+Playwright抓取动态页面:从XHR截获到数据入库完整实战 2026/10/2 4:27:58

Python+Playwright抓取动态页面:从XHR截获到数据入库完整实战

做爬虫这些年,被问得最多的问题,不是“哪个库好用”,而是“遇到纯前端渲染的页面到底怎么抓”。很多人用 requests 拿不到数据、用 Selenium 又觉得太重太慢,折腾一圈最后发现,真正顺手的方案其实是把 Playwright 当“…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉