为什么我的模型无法部署到 Hugging Face Spaces(以及 Git LFS 实际的作用)
Source: Dev.to
为什么我的模型无法部署到 Hugging Face Spaces,以及 Git LFS 实际上在做什么
在尝试把一个大型模型推送到 Hugging Face Spaces 时,我遇到了让人抓狂的错误信息。经过一番调查,我发现问题根源在于 Git Large File Storage (Git LFS) 的使用方式不当。下面我把整个排查过程、错误表现以及最终的解决方案整理成了一篇小文,供大家参考。
1. 现象:部署失败的错误信息
当我在本地运行 git push 把模型文件(约 1.2 GB)推送到仓库时,终端输出类似下面的内容:
error: RPC failed; curl 56 GnuTLS recv error (-54): Error in the pull function.
fatal: The remote end hung up unexpectedly
随后,在 Hugging Face Spaces 的部署日志里看到:
Traceback (most recent call last):
File "/workspace/app.py", line 12, in <module>
from transformers import AutoModel
...
OSError: [Errno 2] No such file or directory: 'model.bin'
简而言之,模型文件根本没有被正确上传,导致 Space 启动时找不到模型。
2. 为什么会出现这种情况?
2.1 Git LFS 的工作原理
- Git LFS 并不把大文件直接存储在普通的 Git 对象库里,而是把它们替换成指向 LFS 服务器 的指针文件(
.gitattributes中会标记哪些文件走 LFS)。 - 当你执行
git push时,Git 会先把指针文件推送到普通的 Git 服务器,然后再把真实的大文件上传到 LFS 端点(在 Hugging Face 上是https://huggingface.co/<repo>.git/info/lfs)。 - 如果本地没有正确安装或配置 LFS,或者 LFS 上传过程被中断,指针文件会被提交上去,但实际的大文件根本没有被上传。
2.2 常见的误区
| 误区 | 解释 |
|---|---|
只执行 git add、git commit、git push,认为 LFS 会自动生效 | 必须先 安装 Git LFS 并运行 git lfs install,否则指针文件会被当作普通文本提交。 |
把模型文件直接放在仓库根目录,而不在 .gitattributes 中声明 | 没有声明的话,Git 会把模型当作普通文件处理,导致仓库体积爆炸或推送被拒绝。 |
以为一次 git push 就能把所有大文件全部上传 | LFS 上传是 分块 进行的,网络不稳定时可能只上传了部分块,导致文件不完整。 |
3. 解决方案:一步步让模型成功部署
下面是我最终采用的完整流程,确保模型文件能够正确走 LFS 并在 Spaces 中被加载。
3.1 安装并初始化 Git LFS
# 如果系统里没有 LFS,先安装
# macOS (Homebrew)
brew install git-lfs
# Ubuntu/Debian
sudo apt-get install git-lfs
# Windows (Chocolatey)
choco install git-lfs
# 初始化(只需要在每台机器上执行一次)
git lfs install
注意:
git lfs install会在全局或当前仓库的.git/config中写入钩子,确保后续的git add能自动把匹配的文件交给 LFS。
3.2 在 .gitattributes 中声明要走 LFS 的文件类型
在项目根目录创建(或编辑).gitattributes,加入类似下面的规则:
# 将所有模型权重文件走 LFS
*.bin filter=lfs diff=lfs merge=lfs -text
*.pt filter=lfs diff=lfs merge=lfs -text
*.pth filter=lfs diff=lfs merge=lfs -text
这一步非常关键:没有这条规则,模型文件会被当作普通文件提交。
3.3 把模型文件重新添加到 Git(确保走 LFS)
如果之前已经提交过模型文件,需要先 撤回(reset)再重新添加:
# 让 Git 重新识别 LFS 规则
git rm --cached path/to/model.bin
git add path/to/model.bin
git commit -m "Add model.bin via Git LFS"
3.4 推送到 Hugging Face(包括 LFS 内容)
git push origin main
在推送过程中,你会看到类似的输出:
Uploading LFS objects: 0% (0/10), 0 B | 0 B/s
Uploading LFS objects: 100% (10/10), 1.2 GB | 12.3 MB/s, done.
如果网络不稳定导致中断,可以使用 git lfs push --all origin main 强制重新上传所有 LFS 对象。
3.5 在 Spaces 中验证模型是否可用
部署完成后,打开 Space 的 Settings → Files,确认模型文件已经显示为 LFS(文件大小会被正确显示)。随后在 app.py(或其他入口文件)里使用常规的 transformers 加载方式:
from transformers import AutoModel, AutoTokenizer
model = AutoModel.from_pretrained("./")
tokenizer = AutoTokenizer.from_pretrained("./")
如果一切正常,日志中不再出现 “No such file or directory” 的错误。
4. 小贴士:避免以后再次踩坑
- 始终在克隆新仓库后第一时间运行
git lfs install。即使你已经在本地装了 LFS,新的机器上也需要执行一次。 - 在
.gitignore里不要把模型文件排除,否则即使声明了 LFS,Git 也会直接忽略它们。 - 使用
git lfs ls-files检查已被 LFS 管理的文件,确保没有遗漏。 - 如果模型体积超过 5 GB,Hugging Face 仍然支持,但需要在仓库设置里开启 “Large File Storage” 并可能需要付费计划。
- 网络不佳时,可以把 LFS 对象先上传到本地缓存(
git lfs fetch --all),再在网络好时一次性推送。
5. 结语
这篇文章的核心信息是:模型部署失败往往不是 Hugging Face 本身的 bug,而是 Git LFS 配置不当导致的大文件没有真正被上传。只要按照上面的步骤——安装 LFS、声明文件类型、重新添加并推送——就能让模型顺利出现在 Spaces 中,后续的推理服务也会如期运行。
如果你在部署过程中仍然遇到奇怪的错误,建议先检查:
.gitattributes是否生效(git check-attr filter path/to/file)- LFS 对象是否完整(
git lfs ls-files) - Space 的日志里是否还有 “LFS pointer” 的提示
祝大家玩得开心,模型部署顺利! 🚀
Source: …
我尝试了什么(以及为什么一直失败)
当我尝试推送仓库时,Git 返回了以下错误:
remote: -------------------------------------------------------------------------
remote: Your push was rejected because it contains files larger than 10 MiB.
remote: Please use https://git-lfs.github.com/ to store large files.
remote: See also: https://hf.co/docs/hub/repositories-getting-started#terminal
remote:
remote: Offending files:
remote: - model.pkl (ref: refs/heads/main)
remote: -------------------------------------------------------------------------
To https://huggingface.co/spaces/chloezhoudev/minima
! [remote rejected] main -> main (pre-receive hook declined)
error: failed to push some refs to 'https://huggingface.co/spaces/chloezhoudev/minima'
我能看出 Git 在抱怨——model.pkl 太大了——但我并不真正明白这为什么会是个问题,或者 “Git LFS” 实际上意味着什么。我以前从未使用过它。
于是,我按照错误信息中的指示一步步尝试修复。
1️⃣ 安装并初始化 Git LFS
brew install git-lfs # Install Git LFS (macOS via Homebrew)
git lfs install # Initialise Git LFS and register Git hooks
git lfs version # Confirm Git LFS installation
2️⃣ 跟踪模型文件并推送
git lfs track "model.pkl"
git add model.pkl
git commit -m "Track model file with Git LFS"
git push
推送再次失败——错误完全相同。
3️⃣ 尝试从索引中移除该文件
git rm --cached model.pkl
git lfs track "model.pkl"
git commit -m "Store model file using Git LFS"
git push
同样的错误。 😅
4️⃣ 创建一个孤立分支
git checkout --orphan clean-main
git add .
git commit -m "Initial deployment with Git LFS model"
git branch -M main
git push -f origin main
这一次,推送终于成功了。
Source: …
我最终对 Git 和 Git LFS 的认识
为什么 Git 一直拒绝我的推送?
Hugging Face 仓库会强制执行 pre‑receive hook,它会扫描 你本次推送的所有提交,如果 任何提交中包含大于 10 MiB 的文件,就会 拒绝推送。
如果大文件以普通 Git blob 的形式存储在某个提交中,即使你随后为其添加了 LFS 跟踪,钩子仍会拒绝该推送。
Git LFS 实际上做了什么?
- 普通 Git 将文件内容存为 blob 对象。每个你添加的文件(大致)会以原始大小保存在仓库历史中。对于二进制文件,这意味着每一次修改该文件的提交都会保存完整的数据。
- Git LFS 用 指针文件(极小的文本文件)取代大文件,并把真实的二进制数据存放在专用的 LFS 服务器上。当你
git add一个符合 LFS 规则的文件时,Git LFS 会生成一个指针,将该指针交给 Git,并把实际文件上传到 LFS 存储。
为什么 git rm --cached 没有起作用?
git rm --cached model.pkl 只会把文件从当前工作树的 索引 中移除。大的 blob 已经存在于你尝试推送的之前的提交中,所以 pre‑receive hook 仍然会看到包含超大 blob 的提交并拒绝推送。
为什么创建孤立分支就能解决问题?
git checkout --orphan clean-main 开启了一个 全新的历史,没有任何之前的提交。随后在已经配置好 LFS 的情况下添加文件并只提交一次,仓库唯一的提交里只包含 LFS 指针,而不是大 blob。于是 pre‑receive hook 没有检测到超大 blob,推送得以通过。
关键要点
-
在大文件进入仓库历史之前必须先使用 LFS 进行跟踪。
在大文件已经提交后再添加 LFS 跟踪并不会 retroactively 重写该提交。 -
.gitattributes文件决定 LFS 跟踪。
Hugging Face Spaces 会自动添加类似以下内容的行:*.pkl filter=lfs diff=lfs merge=lfs -text这告诉 Git 将任何
*.pkl文件视为 LFS 对象,前提是 在首次添加文件时已安装 LFS。 -
从索引中移除文件并不会把它从历史中抹掉。
若要真正删除超大 blob,需要重写历史(例如使用git filter-repo,或创建一个全新的孤立分支)。 -
孤立分支是快速获得干净状态的办法。
当你有一个小项目并希望确保没有大 blob 时,在设置好 LFS 后创建孤立分支,可保证第一次提交是干净的。
TL;DR
- 在添加任何大文件之前先安装 Git LFS。
- 确保
.gitattributes中包含相应的模式。 - 如果不小心提交了大文件,要么重写历史,要么创建新孤立分支并在启用 LFS 跟踪的情况下重新提交。
现在模型被高效存储,Space 部署不再报错,我也终于明白了 Git LFS 的作用以及孤立分支技巧为何有效。
关于 git rm — cached 怎么办?
⚠️ 重要
git rm --cached 只影响后续提交。它 不会 从现有的 Git 历史中删除文件。
- 该命令会把文件从暂存区移除,并在后续提交中停止跟踪它,同时保持工作目录中的文件完整。
- 但是,它并不会删除最初添加该大文件的那个提交。
因为原始提交仍然把 model.pkl 作为普通的 Git blob 保存,问题文件仍然存在于仓库历史中——于是 Hugging Face 仍然会拒绝推送。
有效的解决方案
创建一个没有历史记录的新分支(git checkout — orphan)解决了所有问题,因为它 从一张干净的白纸开始,根本没有任何提交。
-
创建孤立分支
git checkout --orphan new-main -
添加文件(已配置 Git LFS)
git add . git commit -m "Add files with LFS" -
将分支重命名为
main并强制推送git branch -M main git push -f origin main
警告: 使用
--orphan,尤其是git push -f,在有多个协作者使用同一分支时非常危险,因为这会替换分支的历史记录。就我而言,Space 仓库仅用于部署,所以这样做没问题,但在团队环境中需要格外小心。
💡 额外提示:Git LFS 已不再是唯一选择
Hugging Face 现在也推荐 git‑xet,这是一种专为大型机器学习制品设计的更新后端。
- Git LFS 将大文件 移出 Git。
- git‑xet 重新思考 Git 对大型内容的整体存储方式。
经过所有调试后,模型终于部署成功并按预期工作。你可以在 此处 试用实时演示。
感谢阅读。 😊