使用 dvc 从 Azure 存储资源管理器下载数据



我有一个 azure blob 容器,其中包含我自己尚未上传的数据。数据不在我的计算机上本地。 当我没有使用 dvc 上传数据时,是否可以使用 dvc 将数据下载到我的计算机?dvc import-url 可以吗? 我尝试过使用 dvc 拉取,但只有在我已经在计算机上本地拥有数据并使用了 dvc add 和 dvc push 时,才能让它工作。 如果我这样做,那么 azure 上的文件夹就不是人类可读的。是否可以以人类可读的格式上传它们? 如果不可能,那么有没有另一种方法可以从 azure 自动下载数据?

我将以@Shcheklein的出色答案为基础 - 特别是"外部依赖项"提案 - 并专注于您的最后一个问题,即"从Azure自动下载数据的另一种方法"。

假设

让我们假设以下内容:

  • 我们使用的是在现有dvc.yaml文件中指定的 DVC 管道。当前管道中的第一阶段称为prepare
  • 我们的数据存储在某个 Azure blob 存储容器中,位于名为dataset/的文件夹中。此文件夹遵循我们希望保持完整的子文件夹的结构。
  • Azure blob 存储容器已在 DVC 环境中配置为 DVC"数据远程",名称为myazure(有关 DVC"数据远程"的详细信息,请单击此处)

高层次的理念

一种可能性是通过将本地dataset/文件夹与远程容器上的dataset/文件夹同步来启动 DVC 管道。

这可以通过一个名为azcopy的命令行工具来实现,该工具可用于 Windows、Linux 和 macOS。 如此处的建议,最好将azcopy添加到您的帐户或系统路径中,以便您可以从系统上的任何目录调用此应用程序。

高层次的思想是:

  1. 初始update_dataset阶段添加到 DVC 管道,用于检查是否已在远程dataset/目录中进行了更改(即文件添加、修改或删除)。 如果检测到更改,update_datset阶段应使用azcopy sync [src] [dst]命令将 Azure Blob 存储容器([src])上的更改应用到本地dataset/文件夹([dst])
  2. 使用"虚拟"文件在update_dataset和后续的 DVC 管道阶段prepare之间添加依赖关系。这一文件应添加到(a)update_dataset阶段的产出中;(b) 阶段的产出;(c) 阶段的产出;(c) 阶段的产出。以及(b)prepare阶段的依赖关系

实现

此过程已在 Windows 10 上进行了测试。

  1. 通过运行以下命令将简单的update_dataset阶段添加到 DVC 管道:
$ dvc stage add -n update_dataset -d remote://myazure/dataset/ -o .dataset_updated azcopy sync "https://[account].blob.core.windows.net/[container]/dataset?[sas token]" "dataset/" --delete-destination="true"

请注意我们如何指定.dataset_updated的"虚拟"文件作为阶段的输出。

  1. 直接编辑dvc.yaml文件以修改update_dataset阶段的命令。修改后,该命令应 (a) 在azcopy命令 -touch .dataset_updated- 之后创建.dataset_updated文件,以及 (b) 将当前日期和时间传递给.dataset_updated文件,以保证不同更新事件 -echo %date%-%time% > .dataset_updated之间的唯一性。
stages:
update_dataset:
cmd: azcopy sync "https://[account].blob.core.windows.net/[container]/dataset?[sas token]" "dataset/" --delete-destination="true" && touch .dataset_updated && echo %date%-%time% > .dataset_updated # updated command
deps:
- remote://myazure/dataset/
outs:
- .dataset_updated
...

我建议直接编辑dvc.yaml文件以修改命令,因为我无法想出一个完整的dvc add stage命令来一次性处理所有事情。 这是由于使用了由&&、Azure 连接字符串中的特殊字符以及需要动态计算的echo表达式链接的多个命令。

  1. 要使prepare阶段依赖于.dataset_updated文件,请直接编辑dvc.yaml文件以添加新的依赖项,例如:
stages:
prepare:
cmd: <some command>
deps:
- .dataset_updated # add new dependency here
- ... # all other dependencies
...
  1. 最后,您可以在远程端测试不同的场景 - 例如,添加,修改或删除文件 - 并检查运行DVC管道直到prepare阶段时会发生什么:
$ dvc repro prepare

笔记

  • 上面介绍的解决方案与DVC的外部依赖项文档中给出的示例非常相似。 它使用azcopy sync代替az copy命令。azcopy sync的优点是它只应用本地和远程文件夹之间的差异,而不是在检测到差异时"盲目"地从远程端下载所有内容。

  • 此示例依赖于具有 SAS 令牌的完整连接字符串,但如果使用凭据配置azcopy或从环境变量中提取适当的值,则可能无需它

  • 在定义 DVC 管道阶段时,我故意省略了本地dataset/文件夹(即-o dataset部分)的输出依赖项,因为它导致azcopy命令失败。我认为这是因为当您重现阶段时,DVC 会自动清除指定为输出依赖项的文件夹。

  • 定义azcopy命令时,我包含了--delete-destination="true"选项。这允许同步已删除的文件,即如果在 Azure 容器上删除,则会删除本地dataset文件夹中的文件。

请耐心等待,因为你有很多问题。答案需要一点结构和背景才能有用。或者跳到最后,找到一些新的Is it possible to upload them in a human-readable format?:)方法。无论如何,如果这解决了您的问题,请告诉我,一般来说,最好在最后更好地描述您要完成的任务(高级描述)。


您是对的,默认情况下,DVC以内容可寻址的方式构建其遥控器(这使得它不可读)。这有利有弊。删除重复数据很容易,很容易强制执行不变性并确保没有人可以直接触摸它并删除某些内容,项目中的目录名称使其连接到实际项目及其含义等。

关于这方面的一些材料:版本控制数据和模型,我对DVC如何构建其数据的回答,即将推出的数据管理用户指南部分(WIP仍然)。

话虽如此,很明显这种方法有缺点,尤其是在管理云中的大量对象(例如数百万张图像等)时。仅举几个我经常看到的模式问题:

  • 数据已由其他人创建(和更新)。有一些ETL,第三方工具等。我们需要保持这种格式。
  • 第三方工具希望以"人类"可读的方式获得数据。它不与DVC集成,无法通过Git间接访问它。(其中一个示例 - 标签工作室需要直接链接到 S3)。
  • 将所有
  • 数据移动到 DVC 是不切实际的,将所有文件一次实例化为一个目录是没有意义的。用户需要切片,通常基于一些注释(元数据)等。

因此,DVC具有多种功能来处理其原始布局中的数据:

  • dvc import-url- 它将下载对象,缓存它们,默认情况下会将 (dvc push) 推送到远程以再次保存它们以保证可重现性(这可以更改)。此命令创建一个特殊的文件.dvc,用于检测云中的更改,以查看 DVC 是否需要再次下载某些内容。它应涵盖"从 azure 自动下载数据"的情况。
  • dvc get-url- 这或多或少wgetrcloneaws s3 cp,等具有多云支持。它只是下载对象。

有点高级的东西(如果你DVC管道):

  • import-url类似,但对于 DVC 管道 - 外部依赖项

第三个(新)选项。它处于测试阶段,它被称为"云版本控制",本质上它试图保持存储的人类可读性,同时如果你需要它们引用数据的确切版本,仍然可以从使用 Git 中的.dvc文件中受益。

使用 DVC 进行云版本控制(当我写这篇文章时是 WPI,如果 PR 被合并,这意味着您可以在文档中找到它

该文档很好地总结了该方法:

DVC 支持在用户希望在远程存储中保留其原始文件名和目录层次结构的情况使用云对象版本控制,以换取失去内容可寻址存储的重复数据消除和性能优势。启用云版本控制后,DVC 将根据文件的原始目录位置将文件存储在远程中,并且 文件名。然后,文件的不同版本将作为相应对象的单独版本存储在云存储中。