使用 Git + DVC 管理 AI 数据

Why Version Control for AI

AI 场景的开发涉及大量迭代工作,开发人员需要在修改超参数、代码和数据的过程中优化模型性能。AI 工作流中的主要组成部分包括:

  • 代码

    • 训练代码:用于构建模型、训练和优化。
    • 推理代码:用于部署和生产环境中的预测。
  • 数据

    • 包含不同类型的多模态数据(如图像、文本、音频)。数据集可能会不断更新、清洗或扩展,管理不同版本的数据尤为重要。
  • 模型

    • 包括模型结构、训练后的权重、超参数及依赖的环境配置。

版本控制确保以下关键目标:

  • 可再现性:通过追踪数据、模型和代码的版本,确保结果的准确性。
  • 可迭代:AI 工程师需要循环数据准备、开发、训练和评估的过程。版本控制可以追踪记录整个开发的生命周期。
  • 协作:管理多人协作中的版本冲突,提高团队效率。
  • 错误恢复:在代码缺陷或数据污染时,支持快速回滚和恢复。

Why Git

+ 轻量级且广泛使用的版本控制系统。
+ 大部分交互可以在本地执行
+ 与代码开发的工具链(如 CI/CD)集成良好。

- Git 将文件的版本存储为 blob。这些 blob 是经过 diff 压缩的,因此仅存储差异,不适合管理大文件和二进制数据(如数据集和模型)。
- 在数据密集型项目中,Git 仓库易膨胀且性能下降。

Why Not Git-LFS

+ Git-LFS 提供了一个解决方案,通过将旧版本的大型二进制文件存储在存储库之外的位置(远程)并用指针文件替换它。
+ 如果需要旧版本,则客户端从远程获取它。因此,如果设计者从远程拉取最新状态,他只会下载最新状态和指针文件。

- 需要额外的服务(插件)支持远程(本地)存储。
- 仅通过 HTTP 传输数据。

Why DVC

+ 将大文件与 Git 仓库分离,避免仓库过度膨胀。
+ 实现数据、模型和代码的版本绑定,确保一致性。
+ 无服务依赖,仅通过命令行交互。

- 额外的知识依赖

基本方案

Git 负责 DVC 元数据的版本管理。
DVC 负责所有数据的版本控制和外部存储。

如何实现

图示

Git+DVC

初始化数据目录

从其他地方拷贝一个数据集并初始化版本管理

1
2
3
4
5
6
7
8
# cd /dataset_dir
# git init
# dvc init
# dvc add *
# dvc remote add -d dvcstore /share/dvcstore/
# dvc push
# git add .
# git commit -m 'Initial commit'

git init:初始化 git 环境(包含 .gitignore.git 目录 等)
dvc init:初始化 dvc 环境(包含 .dvcignore.dvc 目录 等)
dvc add *:将所有数据交由 dvc 版本控制

  • 数据会缓存到 .dvc/cache
  • 每个文件/文件夹会生成一个 .dvc 结尾的元数据文件
    dvc remote add -d dvcstore /share/dvcstore/:添加 dvc 的远程存储(本地路径),用于在集群各处通过 .dvc 元数据获取数据文件
    dvc push:将 dvc 数据推送到远程存储
    git add .:添加所有改动到 git 暂存区(数据文件本身已经被加入到 .gitignore 中)
    git commit -m 'Initial commit':git 提交

版本控制(基于 tag)

1
2
3
4
5
6
7
# git tag v0.1
# # 改动操作
# find . -maxdepth 1 -type f ! -name ".*" ! -name "*.dvc" | xargs -d '\n' dvc add
# dvc push
# git add .
# git commit -m 'test'
# git tag v0.2
  • find ... 把当前目录下非 .dvc 结尾的非隐藏文件交给 dvc 管理版本

下载到个人目录

1
2
3
$ git clone /share/dataset/fund_mkt_art
$ cd fund_mkt_art
$ dvc pull

切换到指定版本

1
2
3
4
$ git clone /share/dataset/fund_mkt_art
$ cd fund_mkt_art
$ git checkout v0.1
$ dvc pull
  • 在目录执行 dvc install 可以配置在 git checkout 之后自动跟随 dvc checkout 的 git hook

下载指定版本(纯本地方案不适用)

1
2
$ git clone --depth 1 --branch v0.1 /share/dataset/fund_mkt_art
$ dvc pull

数据目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/  
├── image
│ ├── public
│ │ ├── dataset1/
│ │ ├── dataset2/
│ │ └── dataset3/
│ └── private
│ ├── user1/
│ │ └── data/
│ ├── user2/
│ │ └── data/
│ └── user3/
│ └── data/

├── dataset
│ ├── public
│ │ ├── datasetA/
│ │ ├── datasetB/
│ │ └── datasetC/
│ └── private
│ ├── user1/
│ │ └── data/
│ ├── user2/
│ │ └── data/
│ └── user3/
│ └── data/

└── code
├── public
│ ├── project1/
│ ├── project2/
│ └── project3/
└── private
├── user1/
│ └── project_code/
├── user2/
│ └── project_code/
└── user3/
└── project_code/

效率测试

测试文件:

1
-rw-r--r-- 1 root root 11G Oct 21 14:51 nvidia_pytorch_21_04_py3.sqsh

cp

1
2
3
4
5
6
# time cp nvidia_pytorch_21_04_py3.sqsh dvc_image/

real 0m52.593s
user 0m0.013s
sys 0m12.595s

git add

1
2
3
4
5
# time git add .

real 12m54.593s
user 12m20.955s
sys 0m17.390s

lfs track

1

dvc add

1
2
3
4
5
6
7
8
9
10
11
# time dvc add *
Computing md5 for a large file 'nvidia_pytorch_21_04_py3.sqsh'. This is only done once.
100% Adding...|██████████████████████████████████████████████████████|1/1 [01:20, 80.53s/file]

To track the changes with git, run:

git add nvidia_pytorch_21_04_py3.sqsh.dvc .gitignore

real 1m21.884s
user 0m25.767s
sys 0m18.406s

dvc push

1
2
3
4
5
6
# time dvc push
Everything is up to date.

real 0m1.247s
user 0m0.410s
sys 0m0.096s

dvc pull

1
2
3
4
5
6
7
8
$ time dvc pull
A nvidia_pytorch_21_04_py3.sqsh
1 file added and 1 file fetched

real 1m39.710s
user 0m7.523s
sys 0m27.715s

已知问题

DVC

  • DVC 并不能实现类似 git add . 的方式以将所有改动暂存或提交,目前只能配合 find 命令处理根目录的文件并分别执行 dvc add
  • 当(根目录的)文件被删除时,DVC 可以追踪到变更但不会自动提交,目前需要通过 dvc status 过滤并分别执行 dvc remove
  • DVC 对于每个追踪的文件(仅根目录)会生成 .dvc 文件,需要在文件接口过滤,并且不好防止用户无意删除
  • 远程本地存储时,权限在 root,普通用户无法 push,得单独配置私有远程存储,或改变公共目录权限

Git-LFS

  • 当从 Git 下载大数据时,通常仍需要使用 git-lfs 来拉取大文件
  • git lfs track 类型需要维护
  • 纯本地兼容性差,有损坏风险

参考资料