ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

HuggingFace模型下载全攻略:CLI、Python API与国内镜像加速

HuggingFace模型下载全攻略:CLI、Python API与国内镜像加速 去年这个时候我被同事问得最多的问题还不是“怎么写训练代码”而是“这个模型怎么从HuggingFace拖下来”。明明import torch都学会了卡在下载这一步上的人一抓一大把——有人用浏览器一个个点文件有人直接git clone拉仓库结果少则等半小时多则卡在LFS大文件上下到一半就断。后来我发现一个规律凡是下载HuggingFace资源很痛苦的人几乎都是把“从网站拿文件”和“从Hub批量取数据”这两件事混为一谈。这篇文章我打算直接按“能跑通”的标准来写覆盖用huggingface-cli下单个文件、用Python API把下载逻辑嵌进训练脚本、以及通过社区镜像做访问加速这几条路。读完之后你不需要再搜索“huggingface国内访问”“huggingface模型下载”这些词照着命令抄就行。1. HuggingFace仓库的真实文件结构LFS才是下载慢的病根1.1 一个文件夹、三类文件的存储逻辑先花一分钟搞清楚HuggingFace仓库里到底存了什么。任何一个模型仓库比如openai/clip-vit-base-patch32点进Files页面看到的不只是一堆pytorch_model.bin、config.json那么简单。本质上分三类常规小文件config.json、tokenizer.json、vocab.txt、README.md这些加起来通常不超过几MB走普通HTTP就能拉。Git LFS大文件权重文件比如.bin、.safetensors、.onnx、.gguf一个就是几百MB甚至几十GB。这些文件不直接存在Git仓库里Git仓库里放的只是一个“指针”真正的内容在LFS存储节点上。目录结构本身注意HuggingFace仓库允许有子目录比如lm-community/llama3-chinese-8b-instruct-v3-1下面还有original子目录里面是原始权重。这套设计本身没毛病Git仓库只负责管理版本和小文件大文件走LFS。问题出在一半人下载时根本不知道这个结构于是踩了两个坑——第一用git clone以为能一次拖全结果LFS大文件要么没有触发下载只拉到指针文件要么触发之后因为Git本身的传输机制问题反复失败第二浏览器下载时只看到文件列表对着几十个分片权重文件一个个点保存中途断了还得从头再来。记住一句话HuggingFace Hub的下载入口不是网页也不是git而是HTTP/HTTPS API和配套的CLI工具。网页只是给你“看”的不是给你“拖”的。1.2 为什么git clone和浏览器下载都不推荐先给结论不到万不得已不要用git clone拉模型库。原因1Git的仓库对象比你想象的大。一个仓库只要有过几次版本更新.git目录里就会留存历史对象拉下来之后你看到的是“文件总大小×2甚至×3”的磁盘占用。有些仓库历史里放过旧的.bin文件删了但Git历史还在你git clone等于把坟也刨出来。原因2LFS文件在Git里的传输是串行校验的单线程拉到一半断了重来很麻烦。虽然Git LFS官方支持断点续传但实际体验中慢、卡、死锁的概率依然偏高。原因3仓库有submodule时比如一些多模态仓库会引用其他仓库git clone默认不拉子模块你拉完发现少了关键文件还得再git submodule update --init --recursive补一次。浏览器下载的问题更直接你点开.bin文件浏览器开始跑一个动辄几个GB的下载任务中途网络波动、页面关闭、磁盘空间满了全部前功尽弃而且还要一个个文件地确认文件大小。更麻烦的是有些模型仓库的文件虽然大但文件名并不是你认知里那种规则的编号比如model-00001-of-00002.safetensors你根本不知道缺哪个文件才能正常加载。跳过这两条弯路直接进入正题。2. 用huggingface-cli一套命令覆盖单文件与整仓2.1 两种高频命令的完整参数现在主流版本中CLI命令是hf不是老的transformers-cli。如果你的环境里还只有transformers-cli建议先升级pip install -U huggingface_hub[cli]装好后两个命令覆盖绝大多数场景下载整个仓库模型/数据集都行hf download repo_id --local-dir /path/to/save只下载仓库中的某一个文件hf download repo_id --include *.safetensors --local-dir /path/to/save但--include是通配符过滤它适合“批量挑选”如果你只想要一个明确路径的文件更精准的办法是hf download repo_id --local-dir ./saved --include config.json --include model.safetensors注意--include后面可以用多个匹配规则是文件名后缀通配不是目录路径精确定位。如果你要下载子目录里的特定文件通配符里要带路径比如--include original/*.safetensors。常用参数对照表参数作用我的建议--local-dir下载到指定目录别用默认的~/.cache/huggingface否则后面找文件会怀疑人生--revision指定分支或commit id下载带-dev、-rc后缀的模型分支时必用--include只下载匹配的文件省流量、省磁盘的神器--exclude排除匹配的文件适合“只不要某一个格式”时用--force-download覆盖本地已有文件更新权重时用平时别滥用--quiet隐藏进度条写脚本时建议打开日志会清爽很多2.2 断点续传与按需过滤下载40GB模型的实际操作来一段我实际跑过的例子。之前下载一个7B模型仓库里同时有.bin格式和.safetensors格式加起来接近40GB但如果只跑推理.safetensors就够了。我的命令长这样hf download internlm/internlm2_5-7b-chat \ --include *.safetensors \ --include *.json \ --include *.txt \ --exclude *.bin \ --local-dir /data/models/internlm2_5-7b-chat \ --quiet这里有个细节值得展开--include *.json不只会拉config.json会把仓库里所有JSON文件比如generation_config.json、special_tokens_map.json都拉下来这正是加载模型时需要的。而.txt通常是词表说明或者licence顺手拉下来不吃亏。至于.bin我们明确排掉因为transformers加载时优先读safetensors你只要确保没有.bin格式也能正常加载即可。断点续传方面huggingface-cli底层是huggingface_hub库天然支持。下载过程中如果中断不用删掉重来直接再跑一次相同命令它会检查本地文件进度只补未完成的分片。实测下来只要是同一个--local-dir中断重跑后不会从零开始。唯一的坑是如果你同时开多个hf download进程写到同一个目录会互相锁文件建议要么串行要么用HF_HUB_ENABLE_HF_TRANSFER1配合hf_transfer做多线程分片。2.3 指定版本与多卡场景的小经验模型仓库不是只有main分支。比如一些模型发布前会有v1.0、dev分支。指定版本hf download meta-llama/Llama-3.2-3B \ --revision v1.0 \ --local-dir /data/models/llama-3.2-3B多卡场景一般是多台机器各存一份副本。我的经验是先在1号机器上下完整然后直接分发整个local-dir目录不要在每台机器上重复下载。目录拷贝完把HF_HOME或本地路径指对就行。如果你非要每台机器都走网络下载记得错开时间避免同一时刻涌向Hub端点。3. Python API把下载嵌进训练脚本3.1 snapshot_download与hf_hub_download的取舍CLI适合人工操作但如果你要写训练脚本、自动化流水线就得用Python API。官方提供两个核心函数snapshot_download和hf_hub_download。snapshot_download拉整个仓库或者按过滤规则拉一批文件返回的是本地目录字符串。hf_hub_download只拉单个文件返回本地文件路径。二者都能自动走缓存、断点续传也都支持revision、token等参数。什么时候用哪个用transformers的from_pretrained加载模型前建议snapshot_download一次到位把目录准备好。只需要某一个tokenizer.json做分词实验用hf_hub_download。仓库里有大量非必要文件比如onnx、flax权重用snapshot_download ignore_patterns精准拉取。3.2 一个可直接复制的参数配置示例这是一个模板化的下载代码改仓库名就能用import os from huggingface_hub import snapshot_download # 国内镜像加速下一节详细说放在import之后、下载之前 os.environ[HF_ENDPOINT] https://hf-mirror.com save_dir snapshot_download( repo_idopenai/clip-vit-base-patch32, local_dir/data/models/clip-vit-base-patch32, revisionmain, ignore_patterns[*.onnx, *.msgpack, *.h5], tokenNone, # 公开模型不需要token私有模型填 hf_token ) print(f模型下载到: {save_dir})几个参数说清楚local_dir下载文件存放路径。不传的话默认放~/.cache/huggingface/hub下的snapshots目录里路径自动带hash反而不好找。ignore_patterns传入通配符列表跳过不需要的文件。这里跳过onnx和msgpack因为PyTorch推理用不到。token私有模型或需要鉴权才让下的仓库传登录后的access token。公开模型不传即可。local_dir_use_symlinks这个参数在新版里已经废弃旧教程里还总出现不用管它。3.3 下载到一半断了怎么办缓存目录与续传机制下载中断后你的本地目录里会出现一个.cache或者.incomplete开头的文件。以huggingface_hub默认缓存结构来看它实际上是先下载到~/.cache/huggingface/hub下的blobs目录完成后才往snapshots里放。如果你显式指定了local_dir断点文件会放在local_dir/.cache/huggingface/download/下面。接续续传逻辑是重新调用snapshot_download或hf download时它会自动检查.incomplete文件对应的etag判断远端是否一致一致则就地续传。所以遇到中断别删文件直接重跑脚本。如果你非要手动验证某个文件是否完整可以查sha256。HuggingFace每个LFS文件在API的元数据里都有sha256字段from huggingface_hub import hf_hub_download import hashlib file_path hf_hub_download( repo_idopenai/clip-vit-base-patch32, filenameconfig.json, local_dir/tmp/clip ) with open(file_path, rb) as f: digest hashlib.sha256(f.read()).hexdigest() print(digest)实际项目中我一般不会逐文件校验sha256太浪费时间。只有加载模型报错、怀疑文件损坏时才会这么干。4. 国内下载提速镜像环境变量是最高效的一招4.1 一个环境变量解决90%的慢速问题聊到HuggingFace就绕不开国内访问速度问题。这两年社区维护了hf-mirror.com镜像站点把模型、数据集的下载流量调度到国内边缘节点速度提升非常显著。用法极其简单——设一个环境变量export HF_ENDPOINThttps://hf-mirror.com只要你设置了HF_ENDPOINThuggingface_hub库、huggingface-cli、transformers的自动下载逻辑都会把这个地址当成API根节点。没错它的兼容性覆盖了所有基于huggingface_hub的工具链不需要改代码、不需要额外代理、不需要改hosts文件。速度快到什么程度之前我在默认源下Qwen2.5-7B的safetensors权重单线程大概稳定在几百KB/s切到hf-mirror.com之后能跑到几MB/s起步高峰期甚至能到10MB/s以上差距是量级级的。这条路径也叫“huggingface国内镜像源”很多教程里把它叫做“镜像网站”或者“镜像地址”。我的评价是这是目前国内下载HuggingFace模型最省事、最不建议绕过的方案。4.2 为什么开了镜像仍然“慢”的两个隐蔽原因我见过不少同学环境变量也设了还是慢于是得出结论“镜像没用”。排查下来真正原因往往不是镜像站本身的问题而是下面两个隐蔽因素原因一Python脚本内使用镜像的时机太晚。如果你在Jupyter Notebook里写import huggingface_hub os.environ[HF_ENDPOINT] https://hf-mirror.com这时huggingface_hub已经在import时把默认endpoint缓存到内部状态了后面再改环境变量可能不生效。正确做法是把os.environ设置写在import huggingface_hub之前或者直接放在代码第一行import os os.environ.setdefault(HF_ENDPOINT, https://hf-mirror.com) from huggingface_hub import snapshot_downloadCLI命令则不受这个时序问题影响因为你在shell里export之后才启动python进程。原因二DNS解析结果不稳定。偶尔遇到过设了HF_ENDPOINT但下载时部分请求仍然走到了官方域名可以通过日志看到cdn-lfs.huggingface.co字样。这种时候检查一下是不是有多个下载工具比如curl直连脚本、网页端下载同时混用它们并不都认HF_ENDPOINT。curl和浏览器需要自己指向镜像地址属于“绕开官方工具链”的玩法不在本文范围。4.3 镜像地址该写在哪三类配置位置的区别配置HF_ENDPOINT有三种写法效果和使用场景完全不同配置方式写法适用场景临时shell变量export HF_ENDPOINThttps://hf-mirror.com然后运行CLI一次性的手工下载写入shell配置文件在~/.bashrc或~/.zshrc里加同一行长期使用CLI希望所有会话生效Python脚本内os.environ[HF_ENDPOINT] https://hf-mirror.com训练脚本、自动化流水线我个人建议如果你只是偶尔下载用第一种如果你和我一样整天跟模型仓库打交道直接写进~/.bashrc。写进~/.bashrc之后打开终端就能用无感加速。另外注意HF_ENDPOINT只影响huggingface_hub的API请求不影响git clone https://huggingface.co/xxx这类操作。所以别把git的地址也改掉git走的还是官方地址速度就不行。这也是为什么我前文说“不要用git clone拉模型”——镜像方案对git clone无效而CLI/Python API却能百分之百吃到镜像红利。再补一个细节如果需要镜像站上不存在的仓库比如企业内部私有模型HF_ENDPOINT指向公共镜像自然拉不到需要设置HF_TOKEN并使用官方源或者自建内部Hub实例。这种情况走的是另一套路数这里就不展开了。5. 高频报错排查从SSL到文件缺失的实战处理5.1 SSL证书相关报错在Ubuntu环境下载HuggingFace数据集或模型时偶尔会遇到CERTIFICATE_VERIFY_FAILED Failed to establish a new connection这个错误看着唬人但大部分情况下跟你的网络环境没关系是Python环境自带的证书链不完整。常见触发场景用miniconda/pyenv创建的虚拟环境证书路径指向了系统openssl目录而那个目录缺CA证书。我的处理方法很固定pip install --upgrade certifi然后再看看openssl是否能正常读到证书python -c import ssl; print(ssl.get_default_verify_paths())如果输出里的capath路径不存在可以在~/.bashrc里补一下环境变量export SSL_CERT_FILE$(python -c import certifi; print(certifi.where())) export SSL_CERT_DIR$(python -c import certifi; print(certifi.where()))还有一种更隐蔽的情况公司内网要求走统一网关网关会替换证书。这时候上面所有方法都可能失灵需要把网关的CA证书加到系统信任链里。这个属于企业网络策略问题配合运维处理好证书导入就行不做展开。5.2 “unexpected endpoint or method”这类报错怎么回事有同学贴过类似这样的报错unexpected endpoint or method. (options /v1/models). returning 200 anyway先说结论这个报错和HuggingFace官方下载流程关系不大更多出现在你使用某些第三方下载脚本、或者把某个API封装工具用错地址时。常见于有人想用类似OpenAI兼容接口的方式去调用一个非OpenAI服务或者下载脚本本身写死了某个不存在的接口路径。处理思路很简单确认你用的下载工具是不是官方huggingface_hub。如果是这个报错基本不该出现出现了就优先怀疑版本太旧。如果是第三方封装工具去它的repo页面看是否适配目标仓库类型模型、数据集、Space有些工具对数据集下载支持不完整。还有种情况请求对象不是标准/api/models路径而是某个网关返回的统一提示。这时候别在报错文本里绕直接换成hf命令行工具实测能下就说明工具问题不能下再查网络层。这里也提醒一句不要拿requests.get(https://huggingface.co/api/models/xxx)这类手写请求去下载大文件。直接使用官方SDK或CLI文件分片、校验、续传这些脏活普通人自己写很容易写坏。5.3 断点续传失效、磁盘空间与文件校验断点续传失效的常见场景你下到一半手动终止了进程然后改了--include参数再重跑。此时本地的.incomplete文件和新的下载计划对不上续传逻辑可能会认为文件不匹配重头开始。处理方式如果改动了过滤规则建议先把本地目录里残留的.cache/huggingface/download清空再重新下载rm -rf /data/models/xxx/.cache/huggingface/download磁盘空间不够是一个被严重低估的问题。出现下载到一半报“No space left on device”删点缓存重试即可。但我更建议下载前先估算大小。可以在HuggingFace仓库的Files页面把所有LFS文件的大小手动加一遍也可以直接访问APIcurl -s https://huggingface.co/api/models/openai/clip-vit-base-patch32 | python -c import sys,json; djson.load(sys.stdin); print([ (s[rfilename], s[size]) for s in d.get(siblings,[]) if s.get(size)])这个命令能列出仓库内文件与字节大小提前心里有数。LFS文件的总大小基本就是模型权重的大小。文件校验如果你的模型从镜像下载后加载时提示不兼容或shape对不上先别怀疑镜像有问题。检查一下是不是没下载全——safetensors.index.json里记录了每个分片文件的映射缺一个分片transformers加载阶段就会报FileNotFoundError。这种时候重新跑一遍hf download补全即可。6. 实战完整下载一个CLIP模型并用本地文件加载6.1 从仓库选型到命令执行拿openai/clip-vit-base-patch32当例子走一遍完整流程。这个仓库很小不到600MB适合当练习对象。打开仓库页面先看Files列表确认包含以下文件config.jsonpreprocessor_config.jsontokenizer.jsonvocab.jsonmerges.txtmodel.safetensorspytorch_model.bin考虑到我们只用PyTorch推理.bin可以不要。执行export HF_ENDPOINThttps://hf-mirror.com hf download openai/clip-vit-base-patch32 \ --include *.safetensors \ --include *.json \ --include *.txt \ --exclude *.bin \ --local-dir /data/models/clip-vit-base-patch32实测在镜像源下这个仓库的safetensors权重文件能在大约一分钟内完成下载速度与带宽强相关。下载完成后/data/models/clip-vit-base-patch32目录里就是完整的模型文件。可以用ls检查一下ls -lh /data/models/clip-vit-base-patch326.2 本地文件校验与离线加载下载完还不能直接说“万事大吉”先做个完整性验证。写一个小Python脚本对每个预测要用的文件做哈希比对这一步不用每次下载都做但第一次从新镜像站下载时建议跑一遍import os import hashlib from huggingface_hub import HfApi repo_id openai/clip-vit-base-patch32 local_dir /data/models/clip-vit-base-patch32 api HfApi() siblings api.model_info(repo_id).siblings for s in siblings: remote_name s.rfilename local_path os.path.join(local_dir, remote_name) if not os.path.exists(local_path): print(f[Missing] {remote_name}) continue # 只对大文件做sha256校验小文件意义不大 if s.size and s.size 5 * 1024 * 1024: sha256 hashlib.sha256(open(local_path, rb).read()).hexdigest() expected s.lfs.get(sha256) if s.lfs else None if expected and sha256 ! expected: print(f[Hash mismatch] {remote_name})这个脚本逻辑很简单遍历仓库的远程文件列表检查本地文件是否存在大文件则比对sha256。如果全绿就可以进入下一步。离线加载import os from transformers import CLIPModel, CLIPProcessor model_dir /data/models/clip-vit-base-patch32 model CLIPModel.from_pretrained(model_dir, local_files_onlyTrue) processor CLIPProcessor.from_pretrained(model_dir, local_files_onlyTrue) print(model.config.hidden_size) # 能看到配置就说明加载成功注意这里的local_files_onlyTrue是个好习惯——它会强制transformers不联网只用本地文件避免它悄悄去官方Hub验证而拖慢加载。如果你想验证模型真能跑随便准备两张图片做一次图文匹配推理或者直接用模型生成文本特征向量对比一下两个句子的相似度。只要能顺利执行整个下载流程就算完全通了。7. 这套方案还能怎么扩展最后分享几个下载之外的延伸心得。如果你要下载的对象是数据集而不是模型方法几乎一样——hf download对数据集仓库同样生效只是仓库地址要写datasets/xxx/yyy。数据集里通常有大量小文件比如jsonl、parquet直接整个仓库拖下来可能会浪费大量时间建议用--include *.parquet只拉实际训练的格式。至于如何在本地加载这些数据集文件并划分train/test那是datasets库的范畴了下载阶段做到“文件完整落地”就够。如果你有批量下载多个模型的需求别一个个敲命令。写个for循环for repo in openai/clip-vit-base-patch32 openai/clip-vit-large-patch14; do hf download $repo --include *.safetensors --include *.json --local-dir /data/models/$(basename $repo) done这是最朴素的写法但实用。还有人问我“下载时要不要指定HF_HOME”。我的建议是如果你不想让缓存塞满系统盘下载时尽量用--local-dir别让文件进默认的~/.cache。如果已经有大量文件进了默认缓存清理时直接删~/.cache/huggingface/hub即可不影响已下载到local_dir的内容。这篇文章写到这里基本把HuggingFace模型和数据集下载的几种主流方法、镜像加速、常见报错都过了一遍。你可能会发现真正的问题从来不是“不会下载”而是“用错了下载姿势”。先把工具链统一到huggingface_hub再配好HF_ENDPOINT最后根据仓库类型决定拉全量还是过滤拉取——这个流程跑顺之后下载模型这件事在你未来项目里会变成一个几乎没有存在感的常规操作而这也正是它该有的样子。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进