4. 远程存储与团队协作

4.远程存储与团队协作

在机器学习项目中,数据文件和模型往往占据大量存储空间,动辄几十GB甚至TB级别。把这些大文件直接塞进Git仓库显然不现实,但团队又需要共享这些数据。DVC的远程存储机制正是为了解决这个矛盾而设计的。它像Git管理代码一样管理数据,但把实际内容存储在专门的存储空间中。

远程存储的核心概念

远程存储(Remote Storage)是DVC体系中与Git远程仓库对应的概念。如果说Git远程仓库存储的是代码和DVC元文件,那么DVC远程存储就是专门存放数据文件和模型的地方。两者配合工作,构成了完整的版本控制体系。

DVC支持多种存储后端,从本地文件系统到主流云服务商,甚至自托管服务器都能胜任。这种灵活性让我们可以根据团队实际情况选择最合适的方案,而不是被锁定在某个特定平台上。

配置远程存储的过程非常直观。DVC会在项目根目录下的.dvc/config文件中记录存储位置信息,这些信息会随Git一起版本化,确保团队成员都能访问到相同的存储配置。

添加远程存储

使用dvc remote add命令添加远程存储。最基本的用法需要指定存储名称和URL:

$ dvc remote add mystorage s3://my-bucket/dvc-store

这个命令会在配置文件中创建对应的远程存储条目。如果希望将其设为默认存储,加上-d参数即可:

$ dvc remote add -d mystorage s3://my-bucket/dvc-store

设置默认存储后,后续的dvc pushdvc pull操作都会自动使用它,无需每次都指定存储名称。

存储URL的格式决定了存储类型。DVC会根据URL前缀自动识别是S3、Azure、GCP还是其他类型的存储。例如:

  • s3://bucket/path - Amazon S3
  • gs://bucket/path - Google Cloud Storage
  • azure://container/path - Azure Blob Storage
  • ssh://user@host/path - SSH服务器
  • /mnt/shared/dvc-cache - 本地文件系统

配置存储参数

添加存储后,通常需要进一步配置认证信息和其他参数。dvc remote modify命令就是为此而生的。对于云存储,最常见的配置是访问凭证。

以S3为例,如果本地已经配置了AWS CLI,DVC会自动读取~/.aws/credentials中的凭证,无需额外设置。但如果需要使用不同的凭证,可以显式指定:

$ dvc remote modify --local mystorage access_key_id 'AKIAIOSFODNN7EXAMPLE'
$ dvc remote modify --local mystorage secret_access_key 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'

注意这里使用了--local标志。这个标志将配置写入.dvc/config.local文件,该文件默认被Git忽略,适合存放敏感信息。这样既能共享存储配置,又不会泄露凭证。

对于S3兼容存储(如MinIO、DigitalOcean Spaces),需要额外指定endpointurl

$ dvc remote add mystorage s3://my-bucket/path
$ dvc remote modify mystorage endpointurl https://nyc3.digitaloceanspaces.com

Azure存储的配置方式类似,支持多种认证方式:

# 使用连接字符串
$ dvc remote modify --local mystorage connection_string 'DefaultEndpointsProtocol=...'

# 使用SAS令牌
$ dvc remote modify --local mystorage sas_token 'sv=2020-08-04&ss=b&srt=...'

# 使用账户密钥
$ dvc remote modify --local mystorage account_key 'mysecretkey'

Google Cloud Storage通常通过服务账户密钥文件认证:

$ dvc remote modify --local mystorage credentialpath '/path/to/project-xxx.json'

管理多个远程存储

大型项目可能需要多个存储位置。比如,一个用于日常开发,另一个用于归档重要版本。DVC支持配置任意数量的远程存储:

$ dvc remote add development s3://dev-bucket/dvc-cache
$ dvc remote add archive s3://archive-bucket/dvc-store
$ dvc remote add backup /mnt/nas/dvc-backup

使用dvc remote list查看所有配置:

$ dvc remote list
development	s3://dev-bucket/dvc-cache
archive    	s3://archive-bucket/dvc-store
backup     	/mnt/nas/dvc-backup  (default)

切换默认存储使用dvc remote default

$ dvc remote default archive

取消默认设置:

$ dvc remote default --unset

重命名和删除远程存储也很直接:

$ dvc remote rename development dev
$ dvc remote remove backup

这些操作只修改配置文件,不会影响存储中已有的数据。

数据推送策略

配置好远程存储后,下一步就是将本地缓存的数据推送到远程。dvc push命令负责这个任务,它会根据.dvc文件和dvc.yaml中的记录,将缓存中的数据上传到远程存储。

基本推送操作

最简单的用法是推送当前工作区所有跟踪的数据:

$ dvc push

这个命令会检查哪些文件在远程存储中不存在,然后上传这些文件。首次推送可能会花费较长时间,取决于数据量和网络速度。

推送特定文件或目录:

$ dvc push data/raw.dvc
$ dvc push models/

推送特定阶段的输出:

$ dvc push train

推送策略选项

--with-deps选项非常实用。当指定某个目标时,DVC会沿着流水线向后查找所有依赖项并推送相关数据。这在只想推送某个实验所需的最小数据集时特别有用:

$ dvc push --with-deps evaluate

--all-branches--all-tags--all-commits选项用于推送多个Git版本引用的数据。这在需要完整备份项目历史时很有用:

$ dvc push --all-branches --all-tags

注意这些选项会显著增加推送时间和存储占用,因为每个Git版本可能引用不同的数据版本。

并行推送

默认情况下,DVC使用4 * cpu_count()个并行任务上传数据。对于大量小文件,增加并行度可以提升速度:

$ dvc push -j 16

也可以在配置中设置默认值:

$ dvc remote modify mystorage jobs 16

推送运行缓存

运行缓存(run-cache)记录了流水线各阶段的执行结果。启用--run-cache可以推送这些记录,让其他协作者能够复用执行结果,避免重复计算:

$ dvc push --run-cache

这在团队协作中能节省大量计算时间,特别是当某些阶段计算代价高昂时。

推送的最佳实践

推送数据前,务必先提交相关的代码和DVC文件到Git:

$ git add data.dvc dvc.yaml dvc.lock
$ git commit -m "Update dataset and retrain model"
$ dvc push
$ git push

这个顺序确保元数据和实际数据保持一致。如果先推送数据但Git提交失败,其他成员可能会遇到找不到数据的问题。

对于大型项目,建议定期推送,避免积累过多未上传的数据。可以设置Git钩子,在git push后自动执行dvc push

$ dvc install

这会安装预推送钩子,确保代码和数据同步推送。

数据拉取操作

与推送对应的是拉取操作。dvc pull命令从远程存储下载数据到本地缓存,并链接到工作区。它相当于git pull的数据版本。

pull与fetch的区别

DVC提供了两个拉取相关的命令:dvc fetchdvc pull。理解它们的区别很重要:

  • dvc fetch:只下载数据到本地缓存,不链接到工作区
  • dvc pull:先fetch,然后自动执行dvc checkout将数据链接到工作区

工作流程如下:

远程存储 → dvc fetch → 本地缓存 → dvc checkout → 工作区

使用fetch的场景包括:

  • 只想下载数据但不立即使用,保持工作区整洁
  • 需要为多个分支准备数据,一次性fetch所有需要的内容
  • 网络不稳定时,先fetch再checkout可以分开处理错误

基本拉取操作

克隆仓库后,通常的第一步是拉取数据:

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

这会下载当前工作区引用的所有数据文件。

拉取特定文件或阶段:

$ dvc pull data/data.xml.dvc
$ dvc pull train

拉取策略选项

--with-deps选项与push类似,会拉取指定目标及其所有依赖项:

$ dvc pull --with-deps featurize

这在只想恢复流水线某个中间阶段的数据时很有用。

--all-branches--all-tags--all-commits选项会拉取多个Git版本引用的数据:

$ dvc pull --all-branches

这在需要比较不同版本实验结果时特别有用,可以一次性准备好所有数据。

处理缺失数据

如果拉取时遇到WARNING: Cache 'xxxx' not found.错误,通常是因为远程存储中没有对应的数据。可能的原因包括:

  1. 数据尚未推送:联系数据提供者执行dvc push
  2. 使用了错误的远程存储:检查dvc remote listcore.remote配置
  3. Git提交与数据版本不匹配:确认当前Git版本对应的数据已推送

使用dvc status -c可以检查本地缓存与远程存储的差异:

$ dvc status -c
    deleted:            data/features/train.pkl
    deleted:            data/features/test.pkl

这表明远程存储缺少这些文件,需要推送。

选择性拉取

在大型项目中,可能不需要所有数据。可以通过指定目标来减少拉取量:

$ dvc pull data/raw.dvc
$ dvc pull --with-deps train

结合--remote选项,可以从特定存储拉取:

$ dvc pull --remote archive

这在数据分布在多个存储位置时很有用。

缓存管理

缓存是DVC工作的核心机制。理解缓存的管理方式,能帮助我们更高效地使用存储空间,并在团队中共享数据。

缓存的作用

DVC缓存采用内容寻址存储(Content-Addressable Storage)结构。每个文件根据其内容计算哈希值,哈希值决定了文件在缓存中的路径。这种设计带来几个好处:

  1. 去重:相同内容的文件只存储一份,无论它在工作区中有多少副本或不同名称
  2. 完整性:通过哈希验证确保文件未被篡改
  3. 高效链接:使用硬链接、符号链接或reflink快速创建工作区文件,避免复制

缓存默认位于.dvc/cache目录,结构如下:

.dvc/cache/files/md5/
├── 0a/
│   └── ec3a687bd65c3e6a13e3cf20f3a6b2.dir
└── 52/
    └── 4bcc8502a70ac49bf441db350eafc2

.dir文件记录了目录的内容和结构。

配置缓存位置

当项目数据量很大时,可能需要将缓存移到更大的磁盘上:

$ dvc cache dir /mnt/large-disk/dvc-cache

这个命令会更新.dvc/config中的cache.dir配置。注意路径可以是绝对路径,也可以是相对于配置文件的路径。

对于团队共享的服务器,可以设置共享缓存:

$ mkdir -p /home/shared/dvc-cache
$ dvc cache dir /home/shared/dvc-cache
$ dvc config cache.shared group
$ dvc config cache.type symlink

cache.shared group确保新缓存文件对组内成员可读写,cache.type symlink使用符号链接避免数据复制。

缓存链接类型

DVC支持多种链接类型,通过cache.type配置:

  • reflink:写时复制链接,修改文件时不影响缓存(需要文件系统支持)
  • hardlink:硬链接,节省空间但修改会污染缓存
  • symlink:符号链接,灵活性高但某些工具可能不支持
  • copy:复制文件,最安全但占用双倍空间

默认配置是reflink,copy,优先使用reflink,不支持时回退到复制。

查看当前系统支持的链接类型:

$ dvc version
...
Cache: reflink - supported, hardlink - supported, symlink - supported

共享缓存的注意事项

使用共享缓存时,需要注意权限问题。确保所有团队成员对缓存目录有读写权限。通常的做法是:

$ sudo chown -R root:data-team /home/shared/dvc-cache
$ sudo chmod -R 775 /home/shared/dvc-cache

此外,共享缓存中的文件不应被手动删除,否则会影响其他项目。清理缓存必须使用dvc gc,并指定需要保留的项目。

缓存与远程存储的同步

缓存和远程存储的关系类似于Git的本地仓库和远程仓库。日常工作在缓存中进行,定期推送到远程存储备份和共享。

查看缓存状态:

$ dvc status
Data and pipelines are up to date.

$ dvc status -c
Cache and remote 'mystorage' are in sync.

第一个命令检查工作区与缓存的差异,第二个命令检查缓存与远程存储的差异。

垃圾回收

随着时间推移,缓存中会积累大量不再使用的数据版本。dvc gc命令用于清理这些无用数据,释放存储空间。

gc的工作原理

dvc gc根据指定的范围选项,确定哪些数据是"有用"的,删除其余数据。它不会自动运行,必须明确指定保留范围,防止误删。

可用的范围选项包括:

  • --workspace:保留工作区引用的数据
  • --all-branches:保留所有Git分支引用的数据
  • --all-tags:保留所有Git标签引用的数据
  • --all-commits:保留所有Git提交引用的数据
  • --all-experiments:保留所有实验引用的数据
  • --rev <commit>:保留指定提交及工作区引用的数据
  • --num <n>:保留最近n个提交引用的数据

基本清理操作

清理工作区未引用的数据:

$ dvc gc --workspace

这会删除缓存中所有未被当前工作区.dvc文件引用的数据。执行前,DVC会显示将要删除的文件列表并请求确认。

清理时保留所有分支和标签的数据:

$ dvc gc --workspace --all-branches --all-tags

这在准备删除临时实验数据时很有用,确保正式版本的数据不会被清理。

清理远程存储

加上--cloud(或-c)选项,gc会同时清理远程存储中的数据:

$ dvc gc --workspace --cloud

警告:这个操作不可逆,除非有其他备份。清理前务必确认远程存储中的数据确实不再需要。

指定特定远程存储进行清理:

$ dvc gc --workspace --cloud --remote archive

共享缓存的清理

当多个项目共享同一个缓存时,在其中一个项目执行gc可能会删除其他项目需要的数据。为避免这种情况,使用--projects选项指定需要保留数据的项目路径:

$ dvc gc --workspace --projects /path/to/project1 /path/to/project2

DVC会读取这些项目的Git历史,确保它们引用的数据不会被删除。

清理的最佳实践

定期执行gc可以保持缓存大小可控,但过于频繁的清理可能会删除将来需要的历史数据。建议的策略是:

  1. 为重要里程碑创建Git标签,这样即使使用--all-tags也能保留这些数据
  2. 在清理前,确保所有重要的实验都已推送或保存
  3. 对于共享缓存,与团队协调清理时间,避免影响他人工作
  4. 使用--dry选项预览清理效果,确认无误后再执行
$ dvc gc --workspace --dry

这会列出将要删除的文件,但不会真正删除。

实验数据的清理

实验经常产生大量临时数据。如果实验未提交,这些数据不会被任何Git提交引用,容易被gc清理。要保留实验数据,使用--all-experiments

$ dvc gc --workspace --all-experiments

或者将重要实验转换为持久分支:

$ dvc exp branch awesome-exp awesome-exp-branch
$ git tag important-results awesome-exp-branch

这样实验数据就被Git标签保护起来了。

总结

远程存储和团队协作是DVC的核心价值所在。通过将数据存储与代码版本控制分离,DVC解决了大数据版本化的难题。配置远程存储让数据备份和共享变得简单,push和pull命令提供了类似Git的操作体验,缓存管理机制优化了存储效率,而垃圾回收则帮助控制存储成本。

掌握这些工具后,团队可以像管理代码一样管理数据,实现真正的机器学习项目版本控制。下一章将探讨数据的导入导出操作,进一步扩展DVC在数据获取方面的能力。