8.参数与指标管理
在机器学习项目中,参数和指标的管理往往比代码本身更复杂。调参、记录结果、对比实验,这些工作如果靠手动维护,很快就会变成一场噩梦。DVC 提供了一套完整的解决方案,让参数和指标的管理变得像代码版本控制一样自然。
参数文件 params.yaml
参数文件是 DVC 参数管理的核心。本质上,它就是一个普通的 YAML 文件,但 DVC 赋予了它特殊的意义。默认情况下,DVC 会寻找项目根目录下的 params.yaml 文件。
参数文件的结构非常灵活,可以采用任意层级。来看一个典型的例子:
seed: 20180226
train:
lr: 0.0041
epochs: 75
layers: 9
processing:
threshold: 0.98
bow_size: 15000
这个文件定义了三个部分:全局的随机种子、训练参数和数据处理参数。DVC 支持 YAML 1.2 格式,通过 ruamel.yaml 库解析,这比传统的 PyYAML 支持更多特性。
参数文件的命名并不强制。虽然 params.yaml 是默认选择,但完全可以使用其他名称,比如 config.yaml、hyperparams.json 等。关键在于如何在流水线中引用它。
参数依赖管理
在流水线中定义参数依赖
参数依赖是 DVC 流水线中最精细的依赖类型。与普通文件依赖不同,参数依赖可以追踪到文件中的某个具体值。这意味着修改 params.yaml 中的一个参数,不会导致所有阶段都被重新执行。
在 dvc.yaml 中定义参数依赖有两种方式。第一种是手动编辑文件:
stages:
train:
cmd: python train_model.py
deps:
- train_model.py
- matrix-train.p
params:
- seed
- train.lr
- train.epochs
outs:
- model.p
params 列表中的每个条目都对应 params.yaml 中的一个路径。点号表示层级关系,比如 train.lr 对应 YAML 中的 train 下的 lr 键。
第二种方式是使用 dvc stage add 命令:
$ dvc stage add -n train \
-d train_model.py -d matrix-train.p \
-o model.p \
-p seed,train.lr,train.epochs \
python train_model.py
-p 参数接受逗号分隔的参数路径列表。这种方式的优势在于,DVC 会立即验证参数路径的有效性,而手动编辑则要等到执行时才能发现问题。
使用自定义参数文件
如果参数不在 params.yaml 中,可以通过前缀指定文件路径:
$ dvc stage add -n train \
-p params.json:learning_rate,batch_size \
-p config.toml:threshold \
python train.py
甚至可以使用 : 来追踪整个文件的所有参数:
$ dvc stage add -n train \
-p myparams.toml: \
python train.py
在代码中读取参数
定义了参数依赖后,代码需要能够读取这些值。DVC 提供了 Python API 来简化这个过程:
import dvc.api
params = dvc.api.params_show()
seed = params['seed']
lr = params['train']['lr']
epochs = params['train']['epochs']
dvc.api.params_show() 会自动解析默认的 params.yaml 文件。如果需要指定其他文件:
params = dvc.api.params_show('config.toml')
对于非 Python 项目,可以直接使用标准的 YAML/JSON/TOML 解析器读取文件。DVC 只关心文件内容是否变化,不关心如何读取。
参数依赖的工作机制
当执行 dvc repro 或 dvc exp run 时,DVC 会检查所有依赖的状态。对于参数依赖,DVC 会计算参数值的哈希值,而不是整个文件的哈希。这意味着:
- 修改未使用的参数不会触发阶段重新执行
- 多个阶段可以共享同一个参数文件,但依赖不同的参数子集
- 参数变化会精确地反映在
dvc.lock文件中
# dvc.lock 中的参数部分
stages:
train:
params:
params.yaml:
seed: 20180226
train.lr: 0.0041
train.epochs: 75
这种细粒度的追踪机制,让大规模参数调优变得高效。修改一个超参数不再需要重新运行整个流水线。
Metrics 指标定义
什么是 Metrics
Metrics 是描述模型性能的键值对数据。与参数不同,metrics 是阶段的输出,而不是输入。典型的 metrics 包括准确率、损失值、AUC 等。
Metrics 文件应该保持小巧且人类可读,通常使用 JSON、YAML 或 TOML 格式。DVC 对 metrics 文件有特殊处理:它们会被 Git 追踪,而不是 DVC 缓存。
定义 Metrics
在 dvc.yaml 中定义 metrics 有两种方式。第一种是顶级定义:
metrics:
- metrics.json
- eval/scores.yaml
这种方式适用于简单的项目,所有 metrics 文件都会被自动识别。
第二种方式是在阶段定义中指定:
stages:
evaluate:
cmd: python eval.py
deps:
- model.pkl
outs:
- metrics.json:
cache: false
通过设置 cache: false,告诉 DVC 这个文件应该由 Git 管理。也可以使用 dvc stage add 的 -m 或 -M 选项:
$ dvc stage add -n evaluate \
-d model.pkl \
-m metrics.json \
python eval.py
-m 表示 metrics 文件会被 DVC 追踪(类似普通输出),而 -M 表示不缓存(推荐用于 metrics)。
Metrics 文件格式
Metrics 文件必须包含键值对结构。可以是扁平的:
{
"accuracy": 0.95,
"loss": 0.12,
"auc": 0.89
}
也可以是嵌套的:
{
"train": {
"accuracy": 0.98,
"loss": 0.08
},
"test": {
"accuracy": 0.95,
"loss": 0.12
}
}
DVC 会解析这种结构,并在对比时正确显示层级路径。
使用 DVCLive 自动记录 Metrics
手动写入 metrics 文件容易出错。DVCLive 提供了更优雅的方案:
from dvclive import Live
with Live() as live:
live.log_metric("accuracy", 0.95)
live.log_metric("loss", 0.12)
DVCLive 会自动创建 dvclive/metrics.json 文件,并在 dvc.yaml 中配置好 metrics 追踪。这种方式不仅简洁,还能与训练循环无缝集成。
Plots 可视化配置
Plots 与 Metrics 的区别
虽然 plots 和 metrics 都是阶段的输出,但用途不同。Metrics 是标量值,用于量化比较;plots 则是数据系列或图像,用于可视化分析。典型的 plots 包括 ROC 曲线、混淆矩阵、特征重要性图等。
Plots 文件格式
DVC 支持多种 plots 数据格式:
- 数据系列文件:JSON、YAML、CSV 或 TSV 格式,包含多个数据点
- 图像文件:JPEG、GIF、PNG 或 SVG 格式,直接渲染
对于数据系列,DVC 使用 Vega-Lite 规范生成交互式图表。例如,CSV 格式的训练日志:
epoch,train_loss,train_acc,val_loss,val_acc
1,0.45,0.82,0.38,0.85
2,0.32,0.89,0.29,0.91
3,0.28,0.92,0.25,0.93
在 dvc.yaml 中定义 Plots
Plots 的定义比 metrics 更灵活,支持丰富的配置选项:
plots:
# 简单文件路径,使用默认配置
- logs.csv
# 自定义 plot ID 和坐标轴
- ROC:
template: simple
x: fpr
y:
eval/train/roc.json: tpr
eval/test/roc.json: tpr
title: Train vs Test ROC
# 混淆矩阵
- Confusion-Matrix:
template: confusion
x: actual
y:
eval/train/cm.json: predicted
eval/test/cm.json: predicted
# 图像文件
- eval/importance.png
# 整个目录
- eval/misclassified_examples
每个 plot 配置可以包含以下字段:
y:Y 轴数据来源,可以是单个字段或映射x:X 轴字段名,默认为自动生成的索引title:图表标题template:模板名称(linear、simple、confusion 等)x_label、y_label:坐标轴标签
使用 dvc stage add 定义 Plots
命令行方式同样支持 plots 定义:
$ dvc stage add -n evaluate \
-d model.pkl \
--plots roc_curve.json \
--plots-no-cache confusion_matrix.png \
python eval.py
--plots 会缓存输出文件,而 --plots-no-cache 不会。对于图像类 plots,通常不需要缓存。
高级配置技巧
当需要组合多个数据源时,可以使用自定义 plot ID:
plots:
- precision_recall:
x:
prc_train.json: recall
prc_test.json: recall
y:
prc_train.json: precision
prc_test.json: precision
title: Precision vs Recall
这种方式允许将不同文件中的数据绘制在同一张图上,便于直接对比。
差异对比 diff
参数和指标的价值在于对比。DVC 提供了一套完整的 diff 工具,让实验比较变得简单直观。
dvc params diff
比较参数变化是最常用的操作。默认比较工作区与最新提交:
$ dvc params diff
Path Param HEAD workspace
params.yaml lr — 0.0041
params.yaml train.epochs — 70
params.yaml train.layers — 9
如果参数文件已提交过,会显示具体的变化:
$ dvc params diff
Path Param HEAD workspace
params.yaml lr 0.0041 0.0043
params.yaml train.layers 9 7
params.yaml train.epochs 70 110
常用选项包括:
--all:显示所有参数,包括未变化的--deps:只显示作为阶段依赖的参数--targets:指定参数文件路径
比较两个特定版本:
$ dvc params diff e12b167 HEAD^
Path Param e12b167 HEAD^
params.yaml lr 0.0038 0.0041
params.yaml train.layers 10 9
params.yaml train.epochs 50 70
dvc metrics diff
Metrics diff 的工作方式类似,但会额外显示变化量:
$ dvc metrics diff
Path Metric HEAD workspace Change
dvclive/metrics.json AUC 0.78912 0.18114 -0.60798
dvclive/metrics.json TP 215 768 553
对于数值型指标,Change 列显示差值;对于非数值,显示 -。可以通过 --precision 控制小数位数。
dvc plots diff
Plots diff 不是显示数值差异,而是将多个版本的 plots 叠加显示:
$ dvc plots diff HEAD HEAD^
这会生成一个 HTML 文件,其中包含所有指定版本的曲线。对于数据系列 plots,不同版本会用不同颜色区分。
常用选项:
--targets:指定 plots 文件-x、-y:指定坐标轴字段--template:指定模板--open:生成后自动在浏览器打开
dvc exp diff
实验 diff 是最高层的对比命令,它结合了 params diff 和 metrics diff:
$ 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
默认比较 HEAD 与工作区,也可以指定两个实验:
$ dvc exp diff exp-1 exp-2
在 Python 中比较
所有 diff 功能都可以通过 Python API 访问:
import dvc.api
# 获取参数差异
params_diff = dvc.api.params_show(rev='HEAD')
# 获取指标差异
metrics_diff = dvc.api.metrics_show(rev='HEAD')
# 获取实验表格
exps = dvc.api.exp_show()
import pandas as pd
df = pd.DataFrame(exps)
这种方式便于在 Jupyter Notebook 中进行自定义分析。
实际工作流程示例
让我们看一个完整的工作流程,体会参数与指标管理的便利性。
初始状态,我们有如下 params.yaml:
train:
lr: 0.001
epochs: 10
batch_size: 32
定义训练阶段:
$ dvc stage add -n train \
-p train.lr,train.epochs,train.batch_size \
-d train.py -d data \
-m metrics.json \
--plots curves.json \
python train.py
训练脚本 train.py 读取参数并记录指标:
import dvc.api
from dvclive import Live
params = dvc.api.params_show()
lr = params['train']['lr']
epochs = params['train']['epochs']
with Live() as live:
for epoch in range(epochs):
# 训练逻辑...
accuracy = train_one_epoch(lr)
live.log_metric("accuracy", accuracy)
live.next_step()
运行实验:
$ dvc repro
查看结果:
$ dvc metrics show
Path accuracy
metrics.json 0.85
发现准确率不够理想,调整学习率:
$ dvc exp run --set-param train.lr=0.01
比较两次实验:
$ dvc metrics diff
Path Metric HEAD workspace Change
metrics.json accuracy 0.85 0.89 0.04
可视化训练曲线:
$ dvc plots diff HEAD workspace --targets curves.json
这个流程展示了参数与指标管理的闭环:定义 → 执行 → 评估 → 调整 → 对比。所有操作都被 DVC 追踪,确保可重复性。
启下:迈向实验管理
掌握了参数与指标管理后,我们已经具备了进行系统化实验的基础。下一章将深入 DVC 的实验管理系统,学习如何批量运行实验、比较多个迭代、以及分享实验结果。参数与指标不再是孤立的数据点,而是构成实验故事的重要章节。
参数调优不再是盲目的尝试,而是有追踪、有对比、有分析的科学过程。当面对几十个实验版本时,这套系统将成为导航的罗盘。