在 GitHub 上编辑

commit

记录由 DVC 跟踪的文件或目录的更改。

概要

usage: dvc commit [-h] [-q | -v] [-f] [-d] [-R]
                  [--no-relink] [targets [targets ...]]

positional arguments:
  targets        Limit command scope to these stages or .dvc files.
                 Using -R, directories to search for stages or .dvc
                 files can also be given.

描述

将 DVC 跟踪的文件和目录当前的内容存储到 缓存 中,并在需要时更新 dvc.lock.dvc 文件。这会强制 DVC 接受工作区(workspace)中当前被跟踪数据的所有变更内容。

💡 为方便起见,DVC 提供了一个 pre-commit Git 钩子,用于提醒你在必要时执行 dvc commit。更多信息请参见 dvc install

dvc commit 提供了一种方式来完成那些使用了 --no-commit--no-exec 选项的数据跟踪命令(如 dvc adddvc reprodvc import 等)。这些选项会导致命令在处理每个文件或目录时跳过以下步骤:

  • 将文件/目录的哈希值保存在 dvc.lock.dvc 文件中。
  • 将文件内容存储到缓存中。

通常跳过这些步骤是为了避免缓存尚未完成的数据,例如在探索不同数据集时。

dvc commit 的一些使用场景包括:

  • 作为已跟踪数据的 dvc add 替代方案:dvc commit 可以将所有更改添加到已被 DVC 跟踪的文件或目录中,而无需逐一指定目标。

  • 我们经常修改源代码、配置文件或其他在 dvc.yaml 中定义为依赖项deps 字段)的文件,但这些修改并不会导致输出发生变化,例如:重新格式化输入数据、添加代码注释等。然而,DVC 会检测到所有依赖项的变化,并提示你重新运行相应管道(dvc repro)。此时你可以改用 dvc commit 来强制接受这些新版本,而无需执行阶段命令。

  • 有时在执行某个阶段后,我们才发现其部分依赖项或输出未在 dvc.yaml 中正确定义。此时可以添加缺失的 deps/outs,而无需重新执行该阶段,但需要使用 dvc commit 来完成操作(详见链接)。

  • 也可以手动执行阶段命令(不使用 dvc repro),或手动修改其输出文件或目录。完成后,使用 dvc commit 将更改注册到 DVC 中。

    请注意,在重写由 DVC 跟踪的文件/目录之前,通常需要先执行 dvc unprotect(或删除输出文件)。

请注意,应尽量避免这些强制更新缓存dvc.lock.dvc 文件的情况。在这种情况下,DVC 无法保证结果的可复现性。

选项

  • -d--with-deps - 仅在指定 targets 时有意义。此选项通过解析目标阶段或.dvc文件的所有依赖关系来确定要提交的文件:DVC 会从相应管道中的目标节点向后搜索。该操作不会提交在目标阶段之后的阶段中引用的文件。

  • -R--recursive - 通过搜索每个目标目录及其子目录中的阶段(位于dvc.yaml中)或.dvc文件来确定要提交的文件。如果 targets 中没有目录,则此选项无效。

  • -f--force - 即使依赖项或输出的哈希值未发生变化,也会提交数据。

  • --no-relink - 不从缓存重新创建文件链接类型到工作区。在处理大量文件时可节省时间,但即使配置了其他链接类型,文件仍可能从缓存中重新建立硬链接或被复制。

  • -h, --help - 打印使用说明/帮助信息,然后退出。

  • -q, --quiet - 不向标准输出写入任何内容。如果没有问题则以 0 退出,否则以 1 退出。

  • -v--verbose - 显示执行dvc add命令时的详细跟踪信息。

示例

让我们使用一个包含一些数据、代码、机器学习模型和流水线阶段的简单工作区,例如为快速入门创建的DVC 项目。然后我们可以观察在不同情况下使用 git commitdvc commit会发生什么。

如果你还没有该项目,请先克隆我们的示例仓库:

$ git clone https://github.com/iterative/example-get-started
$ cd example-get-started

现在让我们安装依赖项。但在执行此操作之前,我们强烈建议创建一个 虚拟环境

$ python3 -m venv .env
$ source .env/bin/activate
$ pip install -r src/requirements.txt

使用以下命令下载预计算的数据:

$ dvc pull -aT

示例:快速迭代

有时我们希望对配置、代码或数据进行多次修改,尝试不同的方法来改进某个阶段的输出结果。为了避免将不需要的中间结果填满缓存,可以使用dvc repro命令的--no-commit选项。当进展达到满意程度后,再使用dvc commit将数据文件保存到缓存中。

featurize阶段中,会执行src/featurization.py。一个有用的修改是调整该脚本的参数。这些参数定义在params.yaml文件中。将max_features参数的值更新为 6000,会改变最终生成的模型:

featurize:
  max_features: 6000
  ngrams: 2

这一修改会导致如果我们运行dvc repro,则featurizetrainevaluate阶段都会被执行。但如果我们想尝试多个max_features的取值,并仅将最佳结果保存到缓存中,可以这样运行:

$ dvc repro --no-commit

我们可以随意多次运行此命令,以任意方式编辑params.yaml,只要使用--no-commit,数据就不会被保存到缓存中。让我们验证这一点:

第一次验证(通过dvc status):

$ dvc status
featurize:
	changed outs:
		not in cache:       data/features
train:
	changed outs:
		not in cache:       model.pkl

现在我们可以查看缓存目录,确认新的model.pkl版本确实不在缓存中。首先查看dvc.locktrain阶段的最新状态:

train:
  cmd: python src/train.py data/features model.pkl
  deps:
    - path: data/features
      md5: de03a7e34e003e54dde0d40582c6acf4.dir
    - path: src/train.py
      md5: ad8e71b2cca4334a7d3bb6495645068c
  params:
    params.yaml:
      train.n_estimators: 100
      train.seed: 20170428
  outs:
    - path: model.pkl
      md5: 9aba000ba83b341a423a81eed8ff9238

为了验证这个model.pkl实例是否在缓存中不存在,我们必须知道缓存文件的路径。在缓存目录中,哈希值的前两个字符用作子目录名,其余字符作为文件名。因此,如果该文件已被提交到缓存,它应出现在.dvc/cache/files/md5/9a目录下。让我们检查一下:

$ ls .dvc/cache/files/md5/9a
ls: .dvc/cache/files/md5/9a: No such file or directory

如果我们确认对params.yaml的更改已成功,就可以执行以下命令集:

$ dvc commit
$ dvc status
Data and pipelines are up to date.
$ ls .dvc/cache/files/md5/9a
ba000ba83b341a423a81eed8ff9238

我们已验证 dvc commit 已将更改保存到缓存中,并且新的 model.pkl 实例也已存在。

示例:不使用 DVC 执行阶段命令

有时你可能希望手动执行阶段命令(而不是使用 dvc repro)。虽然你将无法获得 DVC 的帮助,但你可以自由运行任何命令,包括那些未在 dvc.yaml 中定义的命令。例如:

$ python src/featurization.py data/prepared data/features
$ python src/train.py data/features model.pkl
$ python src/evaluate.py model.pkl data/features auc.metric

和之前一样,dvc status 将显示哪些被跟踪的文件/目录发生了变化,当你的工作完成后,dvc commit 会将输出保存到 缓存 中。

示例:更新依赖项

有时我们希望以一种不会改变其结果的方式清理代码或配置文件。例如添加注释形式的内联文档、调整缩进、删除调试用的打印语句,或其他任何不会导致流水线阶段输出不同的修改。

$ git status -s
M src/train.py

$ dvc status
train:
	changed deps:
		modified:           src/train.py

让我们编辑其中一个源代码文件。具体是哪一个并不重要。你会看到 Git 和 DVC 都识别到了变更。

如果此时运行 dvc repro,该流水线将会被重新执行。但由于此次更改并无实际影响,这将浪费时间和 CPU 资源。特别是当相关阶段执行需要消耗大量资源时,这一点尤为关键。

$ git add src/train.py

$ git commit -m "CHANGED"
[master 72327bd] CHANGED
1 file changed, 2 insertions(+)

$ dvc commit
dependencies ['src/train.py'] of 'train.dvc' changed.
Are you sure you commit it? [y/n] y

$ dvc status
Data and pipelines are up to date.

对于不会产生不同结果的更改,无需重新运行整个流水线,只需在 Git 和 DVC 中都执行 commit 即可。

内容

🐛 发现问题?告诉我们!或者修复它:

在 GitHub 上编辑

有疑问?加入我们的聊天,我们会为您提供帮助:

Discord 聊天