10.实验比较与筛选
当实验数量从几个增长到几十个甚至上百个时,如何快速定位有价值的实验结果就成了一个现实问题。DVC 提供了一套完整的实验比较与筛选工具,让我们能够在不污染 Git 历史的前提下,高效地管理这些实验产物。这套工具的核心思路很直接:先看清差异,再决定取舍。
实验差异比较
dvc exp diff 是实验比较的第一把钥匙。它的设计哲学类似于 git diff,但专注于机器学习场景下最关心的两个维度:参数(parameters)和指标(metrics)。这个命令能快速告诉我们,两个实验之间到底发生了什么变化,以及这些变化带来了什么影响。
基本比较模式
默认情况下,不带任何参数的 dvc exp diff 会对比当前 workspace 与最新 Git 提交(HEAD)之间的差异。这在刚跑完一个实验、想立即查看结果变化时特别有用。
$ dvc exp diff
Path Metric HEAD workspace Change
scores.json roc_auc 0.915363 0.93345 0.018087
scores.json grade B B- —
Path Param HEAD workspace Change
params.yaml max_features 1500 3000 1500
输出分为两个部分:Metrics 和 Params。每个部分都显示了文件路径、具体的指标或参数名称、两个版本的值,以及数值型数据的变更量。注意那个 grade 指标显示为 "—",这是因为字符串类型的变更无法计算数值差异。
这个表格告诉我们:max_features 参数从 1500 调到了 3000,roc_auc 指标提升了约 0.018,但 grade 从 B 降到了 B-。这种呈现方式让我们能一眼看出参数调整与结果变化之间的关联。
指定实验对比
更常见的场景是对比两个已经完成的实验。假设我们已经运行了多个实验,现在想比较其中两个特定版本:
$ dvc exp diff gluey-leak ochre-dook
Path Metric gluey-leak ochre-dook Change
scores.json auc 0.577559 0.51676 -0.060799
Path Param gluey-leak ochre-dook Change
params.yaml featurize.max_features 2000 500 -1500
这里我们比较了名为 gluey-leak 和 ochre-dook 的两个实验。结果显示,gluey-leak 的 max_features 是 2000,ochre-dook 只有 500,对应的 auc 指标前者也高出约 0.06。这种对比让我们能基于数据做出判断:在当前的参数空间中,增加 max_features 似乎能带来性能提升。
灵活的版本指定
exp diff 接受多种版本标识方式:实验名称、Git 提交哈希、分支名、标签名,甚至可以是 Git 修订表达式。比如想对比某个实验与项目早期版本:
$ dvc exp diff gluey-leak 7-ml-pipeline
Path Metric gluey-leak 7-ml-pipeline Change
scores.json auc 0.577559 None diff not supported
Path Param gluey-leak 7-ml-pipeline Change
params.yaml featurize.max_features 2000 500 -1500
params.yaml featurize.ngrams 2 1 -1
当对比的版本之间某些指标不存在时,DVC 会显示 "diff not supported" 而不是报错,这种容错设计让探索性分析更加顺畅。
输出格式控制
对于需要进一步处理的场景,JSON 格式是个不错的选择:
$ dvc exp diff --json gluey-leak ochre-dook
这会输出结构化的 JSON 数据,方便被其他工具解析。如果要在 GitHub 的 issue 或 PR 中展示对比结果,Markdown 表格格式更合适:
$ dvc exp diff --md gluey-leak ochre-dook
精度控制也很实用。默认情况下,数值会保留 5 位小数,但可以通过 --precision 调整:
$ dvc exp diff --precision 2 gluey-leak ochre-dook
这在处理大范围数值时能让表格更易读。
过滤显示内容
当项目包含大量参数和指标时,表格会变得臃肿。--param-deps 选项可以只显示作为 stage 依赖的参数,这在关注 pipeline 核心配置时很有用。--all 选项则相反,会显示所有内容,包括没有变化的项。
$ dvc exp diff --all gluey-leak
这个命令会列出所有被追踪的参数和指标,即使某些值在对比中没有变化。这在需要完整审计时很有价值。
实验列表管理
dvc exp list 提供了一个轻量级的实验清单视图。与 exp show 的详细表格不同,这个命令只列出实验名称,格式简洁,适合快速浏览或脚本处理。
本地实验列表
默认行为是列出基于当前 HEAD 的所有实验:
$ dvc exp list
10-bigrams-experiment:
60b225a [bally-gude]
b485671 [gluey-leak]
5f30433 [lurid-lair]
输出显示实验所属的基准提交(10-bigrams-experiment)和具体的实验条目。每个条目包含简短的哈希值和实验名称。这种层级结构让我们能快速了解实验的归属关系。
查看所有提交相关的实验
如果项目有较长的开发历史,实验可能分散在不同的提交上。--all-commits(或 -A)选项能列出仓库中的所有实验:
$ dvc exp list --all-commits
这会遍历整个 Git 历史,找出所有关联的实验。虽然输出可能很长,但配合 grep 等工具能快速定位特定实验。
仅显示实验名称
在自动化脚本中,可能只需要纯粹的实验名称列表。--name-only 选项正是为此设计:
$ dvc exp list --name-only --all-commits
bally-gude
gluey-leak
lurid-lair
每行一个名称,这种格式非常适合管道操作。比如想删除所有包含 "test" 的实验:
$ dvc exp list --name-only --all-commits | grep test | xargs dvc exp remove
远程实验探索
exp list 的强大之处在于能直接查看远程仓库的实验,无需先拉取到本地:
$ dvc exp list --all-commits git@github.com:iterative/example-get-started.git
10-bigrams-experiment:
bally-gude
conic-ease
这在团队协作中特别有用。可以先查看同事分享的实验,再决定是否需要拉取到本地。如果本地已经配置了 Git remote,可以直接使用 remote 名称:
$ git remote -v
origin git@github.com:iterative/example-get-started.git
$ dvc exp list --all-commits origin
这种设计让实验的分享和发现变得异常简单,不需要复杂的配置或额外的服务。
实验结果应用
找到心仪的实验后,下一步通常是将结果应用到 workspace 进行验证或进一步开发。dvc exp apply 就是为此而生。
应用实验到工作区
假设经过比较,我们发现 gluey-leak 实验的 AUC 指标最高,想深入分析其模型和数据:
$ dvc exp apply gluey-leak
Changes for experiment 'gluey-leak' have been applied...
这个命令会将实验的所有文件状态恢复到当前 workspace,包括代码、数据、参数、指标和模型等。DVC 会同时处理 Git 追踪的文件和 DVC 追踪的数据文件,确保 workspace 与实验状态完全一致。
检查应用后的变更
应用完成后,建议立即检查具体发生了哪些变化:
$ git status
On branch master
Changes not staged for commit:
modified: dvc.lock
modified: params.yaml
modified: scores.json
Git 状态显示参数文件和指标文件已被修改。查看具体差异:
$ git diff params.yaml
@@ -3,7 +3,7 @@ prepare:
featurize:
- max_features: 1500
+ max_features: 2000
ngrams: 2
参数确实从 1500 改为了 2000。再看 DVC 追踪的数据文件:
$ dvc status
Data and pipelines are up to date.
$ dvc diff
Modified:
data/features/
data/features/test.pkl
data/features/train.pkl
model.pkl
files summary: 0 added, 0 deleted, 3 modified, 0 not in cache
dvc status 显示数据与缓存同步,说明实验的数据文件已经正确恢复。dvc diff 则列出了具体哪些数据文件发生了变化。
应用的风险与恢复
需要特别注意,exp apply 会覆盖 workspace 中同路径的文件。如果当前 workspace 有未提交的修改,这些修改会被实验状态覆盖。不过 DVC 提供了恢复机制:
$ git stash
$ git stash apply refs/exps/apply/stash
这个操作会将应用实验前的 workspace 状态保存到 Git stash,并在需要时恢复。但有个限制:如果在 exp apply 后执行了 git commit 或 git checkout 等修改 HEAD 的操作,stash 恢复可能会失败。因此建议在应用实验前确保 workspace 是干净的,或者先提交重要修改。
从应用到持久化
应用实验的最终目的通常是将其纳入正式的版本控制。确认实验结果符合预期后,可以提交到 Git:
$ git add .
$ git commit -m "persist gluey-leak"
提交后,这个实验就变成了项目历史的一部分。此时再查看实验列表:
$ dvc exp show
─────────────────────────────────────────────────────────────────────────────
neutral:**Experiment** neutral:**Created** metric:**auc** param:**featurize.max_features** param:**featurize.ngrams**
─────────────────────────────────────────────────────────────────────────────
workspace - 0.69830 2000 2
master 04:31 PM 0.69830 2000 2
─────────────────────────────────────────────────────────────────────────────
可以看到 workspace 和 master 分支现在处于同一状态,auc 指标也更新为 0.69830。原来的实验仍然保存在 DVC 的实验存储中,但默认不再显示,因为它们基于的是旧的提交。
实验分支化
有时我们不想直接修改 workspace,而是希望基于某个实验继续开发。这时 dvc exp branch 是更好的选择。
创建实验分支
假设我们想基于 gluey-leak 实验开发新功能:
$ dvc exp branch gluey-leak
Git branch 'gluey-leak-branch' has been created from experiment 'gluey-leak'.
To switch to the new branch run:
git checkout gluey-leak-branch
DVC 创建了一个名为 gluey-leak-branch 的新 Git 分支,内容完全来自实验。注意 DVC 不会自动切换分支,需要手动执行 git checkout。
分支的灵活性
创建分支后,可以像普通 Git 分支一样操作:
$ git branch
* master
gluey-leak-branch
$ git checkout gluey-leak-branch
Switched to branch 'gluey-leak-branch'
$ dvc checkout
dvc checkout 确保 DVC 追踪的数据文件也切换到对应版本。现在可以在这个分支上继续修改、提交,甚至推送到远程仓库与团队分享。
分支与应用的对比
exp apply 和 exp branch 的选择取决于使用场景:
- 想快速查看实验结果,或准备将实验合并到当前分支 → 使用
exp apply - 想基于实验继续开发,或需要独立维护实验代码 → 使用
exp branch
两者都不会删除原始实验,所以可以放心尝试。实验分支化后,实验本身仍然保留在 DVC 的实验存储中,直到显式删除。
实验清理
随着时间推移,实验数量会不断累积。虽然 DVC 的实验存储机制很高效,但清理无用实验能让列表更整洁,也减少存储占用。
按名称删除实验
最简单的清理方式是按名称删除特定实验:
$ dvc exp list
master:
major-mela
conic-ease
lucid-lair
$ dvc exp remove conic-ease lucid-lair
$ dvc exp list
master:
major-mela
可以一次指定多个实验名称,用空格分隔。删除后,实验从列表中消失,但注意这不会删除 DVC 缓存中的数据文件。如果确定不再需要实验相关的数据,可以后续用 dvc gc 清理缓存。
批量清理选项
当实验数量很多时,逐个删除很麻烦。--all(或 -A)选项可以删除所有已运行的实验:
$ dvc exp remove --all
这会清空所有实验,但保留队列中等待运行的实验。如果想清理队列,使用 --queue:
$ dvc exp remove --queue
基于提交范围清理
有时只想清理某个时间段或某个功能分支相关的实验。--rev 和 --num 选项提供了这种能力:
$ dvc exp remove --rev HEAD~5 --num 3
这会删除从 HEAD~5 提交开始,往后 3 个提交范围内的所有实验。--num 接受负值表示包含所有父提交,类似于 git log -n。
反向选择:保留特定实验
--keep 选项提供了反向选择的能力:保留指定实验,删除其余所有:
$ dvc exp list
master:
major-mela
conic-ease
lucid-lair
$ dvc exp remove --keep major-mela
$ dvc exp list
master:
major-mela
在这个例子中,conic-ease 和 lucid-lair 被删除,只保留了 major-mela。--keep 可以与 --num 和 --rev 组合使用,但不能与 --queue 一起使用。
清理远程实验
如果实验已经推送到远程,也可以从远程删除:
$ dvc exp push myremote
$ dvc exp list myremote
master:
conic-ease
urban-sign
major-mela
$ dvc exp remove -g myremote urban-sign major-mela
$ dvc exp list myremote
master:
conic-ease
-g(或 --git-remote)选项指定远程仓库。这在实验分享后发现错误或不再需要时很有用,可以避免远程仓库被无用实验污染。
总结
本章介绍了 DVC 实验管理的核心筛选工具:exp diff 让我们看清实验间的差异,exp list 提供快速清单,exp apply 和 exp branch 提供了两种将实验结果纳入工作流的方式,而 exp remove 则帮助保持实验列表的整洁。
这些命令共同构成了一个完整的实验比较与筛选闭环。从运行实验到分析结果,从选择优胜者到清理无用产物,每个环节都有对应的工具支持。更重要的是,这些操作都不会污染 Git 历史,让实验阶段的快速迭代与正式版本的严谨管理可以并存。
下一章将探讨更高级的实验工作流,包括实验队列管理、超参数调优以及与 Hydra 配置的深度集成,这些能力将进一步提升大规模实验管理的效率。