用 SkyPilot 在任意云运行 AI 工作负载,用 Hugging Face 实现零读出流量费存储

对多数团队而言,模型和数据集位于某一个云、某一个区域的存储桶里,而能够拿到的 GPU——无论用于开发、训练还是服务——越来越多地位于另一个云上。当计算和数据分开时,仅仅把自己的数据读取到自己的 GPU,就要支付跨云传输费用。

SkyPilot 与 Hugging Face 一起连接了这两部分:模型和数据集留在 Hub,开发、训练或服务的计算则由 SkyPilot 放到有 GPU 的集群上。只需一个 hf:// URL 和已有的 HF_TOKEN,就能将 Hugging Face Bucket 或任意 Hub 仓库挂载到 SkyPilot 作业,再在有容量的地方启动。Hugging Face 不收取读出流量费,因此无论 GPU 位于哪个云,将数据读取过去都不会产生这项费用。

这次更新提供了以下能力:

  • 任何作业都能使用 Hub 数据。store: hf 配合一个 hf:// URL 和现有 HF_TOKEN,通过 MOUNT 或 COPY,将读写的 Hugging Face Bucket,或只读的模型、数据集、Space 仓库接入 SkyPilot 任务。
  • 在任何云的 GPU 上运行。SkyPilot 能在20多个云、Kubernetes、Slurm 和本地部署环境中寻找计算资源,让同一作业使用任意厂商当前可用的预留或按需 GPU。
  • 读取数据不收取读出流量费。Hugging Face Storage 不收取读出流量或 CDN 费用,作业无论落在哪个云,都直接从同一个存储桶读取模型与数据集,不必为每个云保存副本,也不会因拉取数据产生读出账单。
  • 基于 Xet 去重。Bucket 使用 Xet,增量检查点和模型变体只存储并传输发生变化的数据块。
  • 联合构建。Hugging Face 和 SkyPilot 共同交付;Hugging Face 团队还将 hf-mount FUSE 的修复贡献至上游,使其能在非特权容器中工作。

Hugging Face Storage 成为 SkyPilot 的一等存储后端

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
SkyPilot 将 Hugging Face 模型、数据集与检查点挂载到跨云预留 GPU 集群,读取不产生 Hugging Face 读出流量费。
模型、数据集和检查点可以从同一存储体系供给不同云上的 GPU 作业。

一个 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 预先完整下载,没有特殊要求。

身份验证使用已有令牌。在环境中设置 HF_TOKEN,并通过 --secret HF_TOKEN 传给运行任务。无论作业落在哪个云,SkyPilot 都会用它完成挂载。AWS、GCP、Azure、Nebius、Lambda 或自有 Kubernetes 集群共用一个令牌,无需管理各云不同的存储桶密钥。

没有读出流量费:存储不再决定计算运行地点

GPU 容量很少再来自单一地点。为了获得足够的 H100 和 H200,团队会同时向多家供应商预留或承诺容量,例如大型云的一块容量、新型云的一组集群,或者本地机架,然后在有资源配额的地方运行。SkyPilot 为此而设计:一个作业规格可在20多个云、Kubernetes 和本地环境调度,落到当前空闲的预留集群。

对象存储一直是限制。它通常具有区域性,并与特定云绑定。要为另一供应商数据中心里的 GPU 或推理服务器提供数据,就必须在每家供应商的桶中留一份副本,或者付费将数据拉出。多数云在数据离开其网络时就收取读出流量费,AWS 约为每 GB 0.09 美元;同一云内部跨区域也常会收费。

将基础模型拉取到每个推理节点,或者在另一云的集群上反复读取数据集训练多个 epoch,都会在已预留的 GPU 成本之外增加显著费用。团队最终把作业固定在数据所在的供应商上,使其他容量闲置。

Hugging Face Storage 去掉了其中影响最大的读取侧费用。原文给出的价格为每 TB 每月12至18美元,没有读出流量或 CDN 费用;相较之下,AWS S3 约为每 TB 23 美元,另加读出流量费。同一个桶可供所有这些集群访问,无论 GPU 在哪里运行,从桶中读取都免费。

一个简短的基准测试

为取得基准数据,原文团队进行了一个小规模微调:使用 TRL 的 SFTTrainer,在 HuggingFaceH4/Multilingual-Thinking 数据集上微调 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

原文团队测得:

  • 每个云上的模型加载都未产生 Hugging Face 读出流量费。惰性读取只拉取 from_pretrained 实际访问的数据,约30秒后即可开始训练,吞吐最高约500 MB/s。如果模型位于 S3,每次向其他云的 GPU 读取都会产生读出流量费,AWS 约为每 GB 0.09 美元。
  • 检查点直接流式写入桶,速度最高约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 Bucket 使用 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 原文;作者:Nikhil Jha、Zhanghao Wu、Hope Wang、Adrien Carreira、Julien Chaumond;发布于2026年7月7日。依据转载授权提供中文翻译。性能数字与价格保留原文条件,未在本地复测。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容