跳到正文
原文
Hugging Face Blog·· 2026-07-07精选AI 评分62

SkyPilot 与 Hugging Face 打通零出网费跨云存储

Run AI workloads on any cloud, store on Hugging Face: zero-egress storage with SkyPilot

AI 摘要

SkyPilot 与 Hugging Face 联合推出 store: hf 存储后端,可用一个 hf:// URL 和现有 HF_TOKEN 把 Hugging Face Bucket 或任意模型、数据集、Space 仓库挂载进 SkyPilot 任务,并在 20 多个云、Kubernetes、Slurm 和本地环境上运行。

正文 · AI 翻译

对大多数团队来说,模型和数据集都存放在某个云某个区域的存储桶里。而你能获取到的 GPU——无论是用于开发、训练还是推理——越来越多地分布在与你数据不同的云上。一旦这两者分离,仅仅是为了把你自己的数据读取到你自己的 GPU 上,你就要支付跨云传输税。

我们与 Hugging Face 携手,将这两半合二为一:你的模型和数据集留在 Hub 上,SkyPilot 则在任何拥有 GPU 的集群上运行计算(开发、训练或推理)。只需一个 hf:// URL 和你已有的 HF_TOKEN,就能将 Hugging Face Bucket 或任何 Hub 仓库挂载到 SkyPilot 任务中,然后在任何有容量的地方启动它。Hugging Face 不收取出口流量费,因此在任何云上,将数据读取到这些 GPU 上都不花一分钱。

以下是新变化:

  • 在任何任务中使用你的 Hub 数据。 store: hf 通过 MOUNT 或 COPY,用一个 hf:// URL 和你现有的 HF_TOKEN,将 Hugging Face Bucket(读写)或任何模型 / 数据集 / Space 仓库(只读)挂载到 SkyPilot 任务中。
  • 在任何云、任何 GPU 上运行。 SkyPilot 可在 20 多个云、Kubernetes、Slurm 和本地环境中寻找该任务的算力,因此同一次运行可以使用你预留的或按需的任意厂商 GPU,只要有可用资源。
  • 读取数据无需出口流量费。 Hugging Face Storage 不收取出口流量费或 CDN 费用,因此无论 SkyPilot 将任务落在哪里,它都直接从同一个存储桶读取你的模型和数据集,无需按云复制,也没有拉取数据的出口流量账单。
  • Xet 支持的去重。 存储桶基于 Xet 构建,因此增量检查点和模型变体只存储和传输发生变化的块。
  • 共同打造。 Hugging Face 和 SkyPilot 联合发布了这一功能,Hugging Face 团队向上游贡献了 hf-mount FUSE 修复,使其能在非特权容器中运行。

Hugging Face Storage 现已成为 SkyPilot 的一等后端

SkyPilot mounts Hugging Face models, datasets, and checkpoints into jobs running on reserved GPU clusters across CoreWeave, Nebius, GCP, and 20+ more, with zero-egress reads.

SkyPilot 任务已经可以通过将云对象存储(S3、GCS、Azure、R2 等)挂载到本地路径来读写它们。Hugging Face Storage 现在以 store: hf 的身份加入这一行列,通过 hf:// 方案访问:

file_mounts:
  # A Hugging Face Bucket, read-write, for checkpoints, logs, processed data.
  /checkpoints:
    source: hf://buckets/my-org/qwen-sft
    store: hf
    mode: MOUNT # or COPY
  # A model repo, mounted read-only.
  /base-model:
    source: hf://Qwen/Qwen3.5-4B
    store: hf
    mode: MOUNT
  # A dataset repo, pinned to a revision, read-only.
  /data:
    source: hf://datasets/my-org/my-dataset@main
    store: hf
    mode: MOUNT

这一个 hf:// 方案覆盖了整个生命周期:从仓库读取模型和数据集,训练时将检查点写入 Bucket,将完成的模型发布回仓库,并在推理服务时将其拉取到推理服务器上。大多数团队已经将模型和数据集保存在 Hub 上,因此无需迁移步骤,也无需创建新的存储账户。

MOUNT 使用 Hugging Face 的 hf-mount FUSE 后端,因此存储桶或仓库会作为本地路径出现在 SkyPilot 的其他 FUSE 挂载(gcsfuse、blobfuse2、rclone、goofys)旁边。获取发生在文件系统层:当你的代码发出 read() 时,驱动只从 Xet 后端拉取那些字节,因此只有你实际接触的数据会通过网络传输,而 hf-mount 会保留磁盘缓存,使重复读取保持在本地。这种磁盘缓存正是 SkyPilot 在 MOUNT_CACHED 下为其其他后端提供的行为,而在那里,普通的 MOUNT 会改为从存储桶流式读取每次读取,不在本地保留任何内容。对于 hf 存储,MOUNT 和 MOUNT_CACHED 行为相同,因此两种模式都会保留缓存。

由于读取是惰性的,进程可以在整个文件下载完成之前就开始处理大文件,而不必先阻塞等待完整副本。这让 GPU 几乎立即保持忙碌,在数据流入时就开始训练,而不是在数据集或检查点下载期间闲置(并计费)。这在第一个 epoch 时收益最大,因为此时还没有任何缓存。COPY 走的是另一条路,通过 huggingface_hub 预先下载,没有特殊要求。

认证用的就是你已有的 token。在环境中设置 HF_TOKEN,并通过 --secret HF_TOKEN 将其交给运行;无论作业落在哪个云上,SkyPilot 都会用它进行挂载。一个 token 就能用,无论作业落在 AWS、GCP、Azure、Nebius、Lambda 还是你自己的 Kubernetes 集群上,因此无需为每个云管理不同的存储桶密钥。

无出口流量费:存储不再决定你在哪里运行

GPU 容量如今很少来自单一来源。为了获得足够的 H100 和 H200,团队会同时在多个供应商处持有预留和承诺容量(在超大规模云上的一块资源、在新云上的一个集群,也许还有本地机架),并在有配额的地方运行。SkyPilot 正是为此而构建:一份作业规范,跨 20 多个云、Kubernetes 和本地环境调度,落在任何空闲的预留集群上。

对象存储一直是症结所在。对象存储是按区域和按云划分的,因此要为位于不同供应商数据中心的 GPU 或推理服务器提供数据,就意味着要么在每个供应商的存储桶中保留一份数据副本,要么付费跨云拉取。大多数云在数据离开其网络的那一刻就收取出口流量费(AWS 约为 $0.09/GB),而且同一云内跨区域也常常收费。将基础模型拉取到每个推理节点,或从另一个云上的集群对数据集迭代多个 epoch,都会在你已预留的 GPU 之上增加一笔高昂账单。团队最终只能将每次运行固定到持有数据的供应商那里,让其余容量闲置。

Hugging Face Storage 在成本最痛的地方——读取侧——消除了这笔费用。凭借 无出口流量费或 CDN 费用 以及 $12-18/TB/月的存储价格(相比 AWS S3 约 $23/TB 外加出口流量费),同一个存储桶可以从所有这些集群访问,而且无论 GPU 在哪里运行,读取都是免费的。写回仍然需要支付你计算云通常的出口流量费,与写入任何云外存储一样,但对大多数 AI 工作负载来说,读取占主导:数据集要流式传输多个 epoch,或者模型权重要被拉取到每个新的训练或推理节点。因此,你不再需要将每次运行固定到持有数据副本的供应商那里。

一个快速基准测试

为了收集一些基准数据,我们运行了一个小型微调:在 HuggingFaceH4/Multilingual-Thinking 数据集上使用 TRL 的 SFTTrainer 运行 Qwen/Qwen3.5-4B,从 Hub 仓库以只读方式挂载模型,并将每个检查点写入 Hugging Face Bucket。相同的 SkyPilot YAML 在 AWS、GCP 和 Lambda 上运行,只更改了 --infra。SkyPilot 将每个作业放置在 GPU 空闲的地方,三者都读写同一个存储桶。

# qwen-sft.yaml. Launch anywhere: sky launch qwen-sft.yaml --infra aws|gcp|...
resources:
  accelerators: H100:1 # or whatever the cloud has

file_mounts:
  /base-model:
    source: hf://Qwen/Qwen3.5-4B # read-only, lazy-mounted from the Hub
    store: hf
    mode: MOUNT
  /checkpoints:
    source: hf://buckets/my-org/qwen-sft # read-write Bucket
    store: hf
    mode: MOUNT

run: |
  python train.py --model /base-model --output_dir /checkpoints

我们测量到的结果:

  • 模型在每个云上都是免费加载的。惰性读取只拉取 from_pretrained 触及的内容,因此它在大约 30 秒内就准备好训练(速度最高约 500 MB/s)。由于 Hugging Face 不收取出口流量费,这次拉取没有成本;如果模型存放在 S3 中,每次从另一个云上的 GPU 读取都会被收取出口流量费(AWS 上约 $0.09/GB)。
  • 检查点直接流式传输到存储桶,速度最高约 170 MB/s(每个权重文件 8.43 GB),并在 GPU 实例结束后持久保留。

在各云平台上,检查点写入存储桶的速度为:

云平台 GPU 检查点写入
AWS (us-east-2) L40S ~168 MB/s
GCP (us-central1) L4 ~123 MB/s
Lambda (us-west-3) H100 ~112 MB/s

基于 Xet 的存储:检查点和模型变体的去重

Hugging Face Buckets 构建于 Xet 之上,它使用内容定义分块将文件切分为约 64 KB 的块,并将每个唯一块只存储一次。由于分块边界跟随内容,一次编辑只会改变它触及的块,其余部分会被识别为已存储。这在几个方面带来收益:

  • 增量检查点和适配器检查点。当你冻结层、训练适配器,或在两次保存之间让大部分权重保持不变时,只有发生变化的块会被上传,而不是整个检查点。
  • 共享同一基座的模型变体。同一基座模型的微调和量化版本之间高度重叠,因此共享的块在所有版本中只存储一次。
  • 持续追加的数据集。诸如对话轨迹或推理输出之类的日志,是通过向大型 Parquet 文件追加行来增长的。已有的行组保持字节完全一致,因此只有新行会被传输:在 Hugging Face 的测试中,向一个 10 万行的表追加 1 万行,只移动了约 10 MB,而不是完整的约 106 MB。(如果你要就地编辑或删除行,请使用 use_content_defined_chunking=True 写入,以将变更限制在局部。)
  • 重新上传会跳过已存储的内容。在我们的测试中,重新上传一个已存在于存储桶中的 8.43 GB 数据块大约耗时 8 秒,而首次上传耗时 24 秒,因为只有块哈希需要传输。同样的机制让服务端的 hf buckets cp 在仓库和存储桶之间通过引用复制,而不是重新上传字节。

节省的多少取决于你的产物重叠程度,但去重是自动的:你照常写入检查点,只有新的块会离开机器。

开始使用

pip install "skypilot[huggingface]"
hf auth login  # or: export HF_TOKEN=<your-token>

向任意 SkyPilot 任务添加一个 hf:// 挂载并启动。MOUNT 需要带有 glibc 2.34+ 的基础镜像以及 /dev/fuse。

共同构建:Hugging Face 与 SkyPilot

最初的 store: hf 支持始于 Nikhil Jha 的贡献。Hugging Face 团队将其推进,并向上游提交了 hf-mount FUSE 修复,使其能够在非特权容器中挂载——这是许多 Kubernetes 集群的默认配置。SkyPilot 团队将其接入存储后端。整条链路都是开源的:SkyPilot、Hugging Face 的 hf-mount 以及 huggingface_hub 客户端。

资源

来源:Hugging Face Blog · huggingface.co

00