14. 训练数据怎么做版本管理和血缘追踪?
整理大模型训练数据的版本控制、血缘追踪与可复现性设计。
简单回答
大模型训练数据的版本管理和传统 ML 完全不是一个量级——数据集动辄几 TB 到几 PB,而且每个最终模型背后是几十个数据源经过几十次清洗、过滤、合成、混合的复杂血缘。做不好版本管理的后果是:模型出问题了不知道哪批数据导致的、想复现某个老版本模型的训练数据找不到、合规审计要求"证明这个模型没用某条数据"做不到。落地的做法是给每个数据集打 content hash(基于内容的指纹)、记录每次处理 step 的输入输出和参数(数据血缘 lineage)、把训练 run 和具体数据快照精确绑定。工程上常用 DVC、LakeFS、Delta Lake 这类支持大数据版本化的工具,再叠加自研的元数据系统。
详细解释
为什么传统 Git 不够用
代码用 Git 管理就够了——文件小、变化频繁、diff 直观。训练数据完全不一样:
- 单个数据集动辄几 GB 到几 TB,Git 根本放不下(即使 Git LFS 也不适合 PB 级)
- 数据修改通常不是"改几行"而是"加 100 万条新样本"或"过滤掉 200 万条质量差的"——传统 diff 没意义
- 训练数据是从多个上游数据源经过多次处理融合而来,需要的是"血缘"而不是"diff"
- 很多数据需要离线一次性大批量计算(去重、嵌入、合成),无法每次小步提交
所以训练数据的版本管理需要专门的工具栈和流程,思路也和代码版本控制不同。
版本管理的三个核心维度
要做好数据版本管理,至少要管三件事:
维度 1:内容指纹(Content Hash)
每个数据集(或每个数据切片)都要有一个基于内容计算的唯一指纹。常见做法:
- 对数据文件做 SHA256,得到文件级 hash
- 对数据集整体做 Merkle 树——每个文件 hash 后再 hash 起来,得到数据集 hash
- 对样本级做 hash 用于去重和精确匹配检测
内容指纹的好处是:相同的数据无论存在什么位置、什么时间,hash 一样。这让"我是不是用了那批数据"变成精确可查询的事。
维度 2:数据血缘(Lineage)
记录数据是怎么来的——上游来源、经过了哪些处理 step、每个 step 的参数、产生了什么输出。
血缘图大致长这样:
每条边记录处理参数(filter 阈值、dedup 算法、mix 比例),每个节点记录内容 hash 和元数据。这样从最终模型反查到原始数据源是完全可追溯的。
工程实现通常是元数据库(PostgreSQL 或专用 lineage store 如 OpenLineage)记录这张图,数据本身存在对象存储(S3)。
维度 3:训练 run 和数据的绑定
每次训练 run 启动时记录使用的数据集 hash 和血缘指针,固化成不可变的引用。即使后面数据被覆盖、删除,旧的训练 run 仍然指向当时的精确数据快照。
这是模型可复现性的最后一道保障——10 个月后想知道"模型 v3.2 用了什么数据训练的",查 run 元数据就能拿到。
工具栈选择
业界常用的工具组合有几套:
DVC(Data Version Control):把数据当 Git artifact 管理,元数据放 Git 仓库,实际数据放 S3 等对象存储。轻量、适合中小团队。但对超大数据集(百 TB+)支持有限。
LakeFS:把对象存储变成"有 Git 语义的数据湖"——支持 branch、commit、merge 数据。适合大规模数据集的团队协作。
Delta Lake / Apache Iceberg:表格式的版本化存储,支持 ACID、时间旅行(time travel,按时间点查询历史版本)。适合结构化训练数据。
自研元数据 + 对象存储:很多大厂走这条路——OSS/S3 存数据本身,自研一套元数据服务(PostgreSQL + 自定义 schema)记录 hash、血缘、依赖关系、权限。灵活度最高但要自己维护。
Hugging Face Datasets + DVC 组合:开源生态最常见的轻量方案。Datasets 处理加载和缓存,DVC 管理版本。
实际选型看团队规模和数据规模。10TB 以下的小团队 DVC + 对象存储就够,PB 级别的需要自研或商业方案。
血缘追踪的具体落地
血缘的关键是 记录每个处理 step 的所有输入和参数。一个 step 通常是一个脚本/任务(quality filter、minhash dedup、language detection、合成数据生成)。
每次跑这个脚本时记录:
这条记录入库后,从输出反查就能完整还原"这个数据集是怎么得来的"。
代码 commit 也要记录——同样的输入数据用不同版本的清洗代码可能得到不同输出,代码版本和数据版本要一起锁定。
对训练数据合规的支持
血缘和版本管理是合规的基础设施。常见的合规场景:
用户数据撤回(GDPR、删除请求):用户要求删除他们的数据,需要证明这部分数据从训练数据里移除了。没有血缘就没法证明,要重新训练(成本极高);有血缘就能定位到这部分数据进了哪些下游数据集和模型,做精确清理。
版权和数据授权审计:审计方要求证明"模型没用未授权的 X 数据集"。content hash 能精确证明某条数据是否在训练集里。
有害数据来源追溯:模型输出了某段有问题的内容(比如背诵了某个具体的人的隐私信息),通过血缘追溯到原始来源,从而清理那个数据源。
数据使用记录:审计要求出具"过去一年某数据集被用于哪些训练 run"的报告——基于血缘图能直接生成。
合规要求往往是数据版本管理基建从"nice to have"变成"must have"的强推动力。
大规模数据的实现取舍
百 TB 到 PB 级数据时,几个实际的工程取舍:
全量 hash 还是采样 hash:对每条样本计算 hash 成本很高。一种优化是只对 样本元数据(不含全文)计算精确 hash,对全文用更快的局部敏感哈希(LSH)做近似匹配。
Snapshot vs Reference:是给每个数据集存一份完整快照,还是只存"指向上游的引用 + 处理步骤"?前者占用存储但访问快,后者节约存储但每次复现都要重算。常见折中是关键节点(pretrain mix、SFT mix)存快照,中间步骤只存引用。
热数据 vs 冷数据:当前正在用的数据集放 SSD/快速对象存储,历史版本归档到便宜的冷存储(S3 Glacier)。访问历史版本会慢但成本可控。
Lineage 图的查询效率:超大规模时血缘图节点数百万级,纯关系数据库查询性能可能不够。可以考虑图数据库(Neo4j)或专用 lineage 系统(DataHub、OpenLineage)。
团队协作的实际流程
一个成熟的数据版本管理流程通常是这样的:
- 数据工程师在 数据 branch 上开发新的清洗脚本
- 在小样本上做 dry-run,验证逻辑
- 全量跑产生新数据集,自动入库(hash + 血缘 + 元数据)
- 提交"数据 PR"——附评估结果(这批新数据在评估集上的影响、统计指标变化)
- 评审通过后 merge 到 main 分支,新数据集对训练 run 可见
- 训练 run 引用 main 分支的最新版本时被冻结到具体 hash
这套流程让数据变更和代码变更一样可审计、可回滚。
面试时可以这样答
大模型训练数据的版本管理传统 Git 完全应付不了。数据集几 TB 到几 PB,变更不是"改几行"而是"加几百万样本/过滤掉几百万样本",且数据是从多个上游经过多次处理融合而来,需要的是血缘不是 diff。
要管三个维度。第一是内容指纹——每个数据集打 content hash(SHA256 或基于 Merkle 树的数据集 hash),相同数据无论在哪 hash 一样,让"是不是用了这批数据"变成精确可查询。
第二是数据血缘 lineage。记录每个处理 step 的输入输出 hash、处理参数、代码版本、操作人、时间。从最终模型能反查到所有原始数据源。工程实现通常是元数据库记血缘图,数据本身在对象存储。
第三是训练 run 和数据的绑定。每次训练 run 启动时固化数据集 hash 和血缘指针,让模型可复现性有保障。
工具栈上小团队用 DVC + S3 就够,大规模用 LakeFS、Delta Lake、Iceberg 这类支持版本化的存储,超大规模通常是自研元数据 + 对象存储。
这套基建对合规支撑特别重要——用户数据撤回、版权审计、有害数据追溯、数据使用报告,都要靠 hash 和血缘做精确证明。合规要求往往是这个基建从 nice-to-have 变成 must-have 的推动力。
大规模时几个工程取舍:全量 hash 太贵就用元数据 hash + LSH;关键节点存快照中间步骤存引用;热数据 SSD 历史版本冷存储;血缘图大了用图数据库或专用 lineage 系统。
常见追问
- 数据集很大(TB 级)时全量 hash 计算成本很高,怎么做增量更新?
- 数据是从外部源(Common Crawl、GitHub)下载来的,每次下载内容可能不同,hash 怎么定?
- 跨团队/跨公司的数据交换,血缘怎么衔接?