Linux 软连接 - 移动 huggingface 模型文件

文章目录

  • [🔗Hugging Face 模型缓存标准布局分析](#🔗Hugging Face 模型缓存标准布局分析)
    • [📁 整体结构说明](#📁 整体结构说明)
    • [🔍 详细解析](#🔍 详细解析)
      • [1. `refs/main`](#1. refs/main)
      • [2. `snapshots/<commit-id>/`](#2. snapshots/<commit-id>/)
      • [3. `blobs/`](#3. blobs/)
    • [📦 模型文件类型解读(OCRFlux-3B)](#📦 模型文件类型解读(OCRFlux-3B))
    • [✅ 为什么你的程序现在能运行了?](#✅ 为什么你的程序现在能运行了?)
    • [💡 小技巧:清理缓存 or 多版本管理](#💡 小技巧:清理缓存 or 多版本管理)
    • [✅ 总结](#✅ 总结)
  • [🔗移动 huggingface 模型文件 到项目目录/指定目录](#🔗移动 huggingface 模型文件 到项目目录/指定目录)
    • 实操步骤如下
    • [✅ 操作步骤(3 步搞定)](#✅ 操作步骤(3 步搞定))
      • [第 1 步:复制模型到项目目录](#第 1 步:复制模型到项目目录)
      • [第 2 步:修改你的 Python 代码](#第 2 步:修改你的 Python 代码)
      • [第 3 步(可选但推荐):验证文件完整性](#第 3 步(可选但推荐):验证文件完整性)
    • [📌 为什么这样更可靠?](#📌 为什么这样更可靠?)
    • [🐳 Docker 部署示例(Bonus)](#🐳 Docker 部署示例(Bonus))
    • [⚠️ 注意事项](#⚠️ 注意事项)
    • [✅ 最终效果](#✅ 最终效果)
  • [🔗Linux 软连接](#🔗Linux 软连接)
      • [🔗 基本概念](#🔗 基本概念)
      • [✅ 创建 symlink](#✅ 创建 symlink)
      • [🔍 查看 symlink](#🔍 查看 symlink)
      • [🧪 使用 symlink](#🧪 使用 symlink)
      • [⚠️ 注意事项](#⚠️ 注意事项)
      • [🆚 symlink vs hard link](#🆚 symlink vs hard link)
      • [💡 常见用途](#💡 常见用途)
      • [✅ 总结](#✅ 总结)
    • [❤️ 一起学AI](#❤️ 一起学AI)

🔗Hugging Face 模型缓存标准布局分析


📁 整体结构说明

Hugging Face 使用 "内容寻址存储"(Content-Addressable Storage) 机制管理模型文件,核心思想是:

  • 所有原始文件(如权重、配置)都存放在 blobs/ 目录下,以 SHA256 哈希命名
  • snapshots/ 下是按版本(commit)组织的符号链接(symlink) ,指向 blobs/ 中的实际文件
  • refs/ 存储分支/标签对应的 commit ID

这种设计支持:

  • 多版本共存
  • 避免重复下载相同内容
  • 快速切换版本

🔍 详细解析

1. refs/main

text 复制代码
refs/
└── main
  • 这是一个纯文本文件 ,内容是一个 commit ID (例如 e68592278bbc8ab32edf7b65e6e411f1d878ef72
  • 表示 main 分支当前指向哪个快照(snapshot)
  • 你可以用 cat refs/main 查看其内容

✅ 这个 commit ID 就是 snapshots/ 下目录的名字


2. snapshots/<commit-id>/

text 复制代码
snapshots/
└── e68592278bbc8ab32edf7b65e6e411f1d878ef72/
    ├── config.json -> ../../blobs/47eadf3d...
    ├── model-00001-of-00002.safetensors -> ../../blobs/1d2640c3...
    └── ...
  • 这是模型在 特定 commit(版本)下的完整文件视图
  • 所有文件都是 符号链接(symlink) ,指向 blobs/ 中的实际数据
  • 当你用 from_pretrained("ChatDOC/OCRFlux-3B") 加载模型时,Hugging Face 会:
    1. 读取 refs/main 获取最新 commit
    2. 进入对应的 snapshots/<commit>/ 目录
    3. 通过 symlink 读取真实文件

💡 你可以用 ls -l snapshots/... 查看链接指向


3. blobs/

text 复制代码
blobs/
├── 075aa21db84b26db9c87f0fd0254ad7bd5cbe86f1b55bebad04020e2a56a5130
├── 1d2640c387e5bdce004e2a77b08ac714d39a6c49a2f088853e2ecf05a398d137
└── ...
  • 每个文件名是一个 SHA256 哈希值(通常是 64 位 hex)
  • 文件内容就是原始模型文件(如 config.jsonmodel.safetensors 等)
  • 相同内容不会重复存储(节省空间)

🔍 举例:
tokenizer.json 的内容哈希是 075aa21d...,所以它被存为 blobs/075aa21d...


📦 模型文件类型解读(OCRFlux-3B)

从你的目录看,这是一个 视觉-语言多模态模型(用于 OCR + 文档理解),包含:

文件 作用
config.json 模型架构配置(层数、隐藏维度等)
model-*.safetensors 模型权重(分片存储,共 2 个文件)
model.safetensors.index.json 权重分片索引(说明哪些张量在哪个文件)
tokenizer.json / vocab.json / merges.txt 文本 tokenizer(可能是 BPE 或 WordPiece)
preprocessor_config.json 图像预处理器配置(尺寸、归一化等)
chat_template.json 对话模板(用于格式化输入)
added_tokens.json / special_tokens_map.json 特殊 token(如 `<
generation_config.json 文本生成参数(temperature, max_length 等默认值)
LICENSE / README.md 模型许可证和说明文档

关键点

  • 权重使用 safetensors 格式 (比 PyTorch .bin 更安全、更快)
  • 支持 多模态输入(图像 + 文本)
  • 专为 文档 OCR 和结构化理解 设计(ChatDOC 项目)

✅ 为什么你的程序现在能运行了?

因为你已经成功下载了完整模型

tree 输出可见:

  • 所有必需文件都已存在(包括两个权重分片)
  • snapshots/ 指向有效 commit
  • 无需再访问网络(即使断网也能加载)

所以你现在运行:

python 复制代码
llm = LLM(model="ChatDOC/OCRFlux-3B", ...)

直接从本地缓存加载 ,不会再去请求 hf-mirror.com


💡 小技巧:清理缓存 or 多版本管理

  • 清理旧版本 :删除 snapshots/ 下不用的 commit 目录(blobs/ 会被自动 GC)

  • 查看所有模型缓存

    bash 复制代码
    huggingface-cli scan-cache
  • 指定缓存目录 (避免占满 home):

    bash 复制代码
    export HF_HOME=/your/big/disk/.cache/huggingface

✅ 总结

目录 作用
refs/main 指向当前最新 commit
snapshots/<commit>/ 模型文件的"虚拟视图"(全是 symlink)
blobs/ 实际存储文件内容(按哈希命名)

你的模型已完整缓存,可离线运行!

无需再担心 hf-mirror.com 问题 (只要不删缓存)

这是 Hugging Face 的标准缓存机制,设计合理且高效


如果你后续要部署到其他机器,只需打包整个 models--ChatDOC--OCRFlux-3B 目录,放到目标机器的相同缓存路径下即可,无需重新下载 👍

🔗移动 huggingface 模型文件 到项目目录/指定目录

实操步骤如下

huggingface 仓库 ChatDOC/OCRFlux-3B 模型下载默认路径格式如下

  • 我这里想把该模型复制到我的项目路径下 或者 某个特定存放模型的路径
bash 复制代码
~/.cache/huggingface/hub/models--ChatDOC--OCRFlux-3B$ tree
.
├── blobs
│   ├── 075aa21db84b26db9c87f0fd0254ad7bd5cbe86f1b55bebad04020e2a56a5130
│   ├── 1d2640c387e5bdce004e2a77b08ac714d39a6c49a2f088853e2ecf05a398d137
│   ├── 31349551d90c7606f325fe0f11bbb8bd5fa0d7c7
│   ├── 328a2f00f1fc98de5f17b8c110ec49d7b7ff7c6e
│   ├── 40b8054d8c7fc56685d114549a96ac50a408c231
│   ├── 4783fe10ac3adce15ac8f358ef5462739852c569
│   ├── 47eadf3df97c16abb7639b954043cad370abcd98
│   ├── 52373fe24473b1aa44333d318f578ae6bf04b49b
│   ├── 732bd68bc5427d1fb6c06a59b3bf2456b2155d24
│   ├── 7f3b746825e5eef53ed8ed57a91df9e86ee62c0a
│   ├── 7f808729bc011fc09a46bdcff0bc61c97ddae217
│   ├── 87f48cf86671d627b4dd4b8e5189b8e32ae11dd8
│   ├── ac23c0aaa2434523c494330aeb79c58395378103
│   ├── d8ae1343faae6b4be5a6c4733791ba5ed0586291
│   ├── e1ddaffaa0dc63e4e6aa4a9de8515ea3935d862b6474a198d9697999113ff5c9
│   └── f8eb226e871c5398876c230944fda4081903bc26
├── refs
│   └── main
└── snapshots
    └── e68592278bbc8ab32edf7b65e6e411f1d878ef72
        ├── added_tokens.json -> ../../blobs/40b8054d8c7fc56685d114549a96ac50a408c231
        ├── chat_template.json -> ../../blobs/732bd68bc5427d1fb6c06a59b3bf2456b2155d24
        ├── config.json -> ../../blobs/47eadf3df97c16abb7639b954043cad370abcd98
        ├── generation_config.json -> ../../blobs/f8eb226e871c5398876c230944fda4081903bc26
        ├── LICENSE -> ../../blobs/87f48cf86671d627b4dd4b8e5189b8e32ae11dd8
        ├── merges.txt -> ../../blobs/31349551d90c7606f325fe0f11bbb8bd5fa0d7c7
        ├── model-00001-of-00002.safetensors -> ../../blobs/1d2640c387e5bdce004e2a77b08ac714d39a6c49a2f088853e2ecf05a398d137
        ├── model-00002-of-00002.safetensors -> ../../blobs/e1ddaffaa0dc63e4e6aa4a9de8515ea3935d862b6474a198d9697999113ff5c9
        ├── model.safetensors.index.json -> ../../blobs/7f808729bc011fc09a46bdcff0bc61c97ddae217
        ├── preprocessor_config.json -> ../../blobs/7f3b746825e5eef53ed8ed57a91df9e86ee62c0a
        ├── README.md -> ../../blobs/d8ae1343faae6b4be5a6c4733791ba5ed0586291
        ├── special_tokens_map.json -> ../../blobs/ac23c0aaa2434523c494330aeb79c58395378103
        ├── tokenizer_config.json -> ../../blobs/328a2f00f1fc98de5f17b8c110ec49d7b7ff7c6e
        ├── tokenizer.json -> ../../blobs/075aa21db84b26db9c87f0fd0254ad7bd5cbe86f1b55bebad04020e2a56a5130
        └── vocab.json -> ../../blobs/4783fe10ac3adce15ac8f358ef5462739852c569

4 directories, 32 files

具体复制命令示例如下

bash 复制代码
# 进入项目目录
cd ~/project/deploy/domain_image_ocr/models/OCRFlux-3B 

mkdir -p models/OCRFlux-3B/
cd models/OCRFlux-3B/

cp -rL /home/mo/.cache/huggingface/hub/models--ChatDOC--OCRFlux-3B/snapshots/e68592278bbc8ab32edf7b65e6e411f1d878ef72/* .

(ocrflux) ~/project/deploy/domain_image_ocr/models/OCRFlux-3B$ ls

added_tokens.json   config.json             LICENSE     model-00001-of-00002.safetensors  model.safetensors.index.json  README.md                tokenizer_config.json  vocab.json
chat_template.json  generation_config.json  merges.txt  model-00002-of-00002.safetensors  preprocessor_config.json      special_tokens_map.json  tokenizer.json

我的测试代码运行成功'

python 复制代码
from vllm import LLM
from ocrflux.inference import parse

# file_path = 'test.pdf'
file_path = '1.jpg'
llm = LLM(model="models/OCRFlux-3B",gpu_memory_utilization=0.8,max_model_len=8192)
result = parse(llm,file_path)
print('-' * 100)
print(f'result : ', result)
print('-' * 100)

完全可以!而且这是生产部署中的推荐做法 ✅

你不需要依赖 ~/.cache/huggingface/hub/ 缓存机制,可以把模型完整复制到你的项目目录下,然后直接通过本地路径加载。这样:

  • ✅ 完全离线运行(不依赖网络、不查 HF)
  • ✅ 路径清晰可控(便于 Docker 打包、团队共享)
  • ✅ 避免缓存污染或版本混乱
  • ✅ 加载速度更快(无 symlink 跳转)

✅ 操作步骤(3 步搞定)

第 1 步:复制模型到项目目录

bash 复制代码
# 假设你的项目目录是 ~/my_ocr_project/
mkdir -p ~/my_ocr_project/models/OCRFlux-3B

# 复制 snapshots 下的实际文件(不是 symlink!要用 -L 解引用)
cp -rL ~/.cache/huggingface/hub/models--ChatDOC--OCRFlux-3B/snapshots/e68592278bbc8ab32edf7b65e6e411f1d878ef72/* \
       ~/my_ocr_project/models/OCRFlux-3B/

🔑 关键参数:-L 表示 "跟随符号链接,复制真实文件"

如果不用 -L,你会复制一堆无效的 symlink,导致加载失败!


第 2 步:修改你的 Python 代码

将模型路径改为本地绝对路径或相对路径

python 复制代码
from vllm import LLM
from ocrflux.inference import parse
import os

# 方式1:使用绝对路径
MODEL_PATH = "/home/mo/my_ocr_project/models/OCRFlux-3B"

# 方式2:使用相对路径(推荐,便于迁移)
# MODEL_PATH = os.path.join(os.path.dirname(__file__), "models", "OCRFlux-3B")

file_path = '1.jpg'

# 关键:传入本地路径,而不是 HF repo id
llm = LLM(
    model=MODEL_PATH,  # 👈 不再是 "ChatDOC/OCRFlux-3B"
    gpu_memory_utilization=0.8,
    max_model_len=8192,
    trust_remote_code=True  # 如果模型需要自定义代码(OCRFlux 可能需要)
)

result = parse(llm, file_path)
print('-' * 100)
print(f'result : ', result)
print('-' * 100)

第 3 步(可选但推荐):验证文件完整性

确保复制后的目录包含以下关键文件:

bash 复制代码
ls -1 ~/my_ocr_project/models/OCRFlux-3B/

应包含:

复制代码
config.json
model-00001-of-00002.safetensors
model-00002-of-00002.safetensors
model.safetensors.index.json
tokenizer.json
preprocessor_config.json
...

没有 blobs/snapshots/refs/ ------ 只有真实文件!


📌 为什么这样更可靠?

对比项 HF 缓存路径 本地项目路径
是否需要网络 首次需要,后续可能检查 完全不需要
路径是否稳定 可能被 huggingface-cli 清理 你完全控制
是否依赖环境变量 HF_HOMEHF_ENDPOINT 影响 无依赖
Docker 打包 需挂载缓存目录 直接 COPY 到镜像
团队协作 每人需重新下载 git-lfs 或共享存储即可

🐳 Docker 部署示例(Bonus)

Dockerfile 复制代码
FROM nvidia/cuda:12.1-runtime

# 安装依赖
RUN pip install vllm ocrflux

# 复制模型(假设模型已放在 ./models/OCRFlux-3B)
COPY models/OCRFlux-3B /app/models/OCRFlux-3B
COPY API_infer.py /app/

WORKDIR /app
CMD ["python", "API_infer.py"]

✅ 镜像自包含模型,无需任何外部依赖!


⚠️ 注意事项

  1. 不要复制 symlink,要用 cp -Lrsync -L

    bash 复制代码
    # 正确
    cp -rL source/ target/
    
    # 错误(会复制无效链接)
    cp -r source/ target/
  2. 如果模型包含自定义代码(如 modeling_xxx.py

    • 确保 trust_remote_code=True
    • 或手动将代码文件放入项目(OCRFlux 可能需要)
  3. 磁盘空间

    • OCRFlux-3B 约 6~7GB,确保项目目录有足够空间

✅ 最终效果

你的项目结构变成:

复制代码
my_ocr_project/
├── API_infer.py
├── 1.jpg
└── models/
    └── OCRFlux-3B/
        ├── config.json
        ├── model-00001-of-00002.safetensors
        ├── model-00002-of-00002.safetensors
        ├── tokenizer.json
        └── ...

运行:

bash 复制代码
cd my_ocr_project
python API_infer.py

完全离线、稳定、可移植!


如果你需要,我还可以帮你写一个 自动复制模型的脚本Dockerfile 模板,欢迎继续问!

🔗Linux 软连接

在 Linux 中,symlink (symbolic link,符号链接)是一种特殊类型的文件,它指向另一个文件或目录,类似于 Windows 中的"快捷方式"。


🔗 基本概念

  • symlink 本身不包含实际数据 ,只存储目标文件/目录的路径
  • 可以跨文件系统(跨磁盘分区)创建。
  • 如果目标被删除,symlink 会变成"悬空链接"(dangling link),访问时会报错 No such file or directory
  • 硬链接(hard link) 不同:硬链接指向 inode(物理数据),不能跨文件系统,也不能指向目录(通常)。

使用 ln -s 命令:

bash 复制代码
ln -s <目标路径> <链接名称>
示例:
bash 复制代码
# 创建指向文件的 symlink
ln -s /home/user/documents/report.pdf my_report.pdf

# 创建指向目录的 symlink
ln -s /var/www/html website

现在:

  • my_report.pdf 是一个 symlink,指向 report.pdf
  • website 是一个 symlink,指向 /var/www/html

bash 复制代码
ls -l

输出示例:

text 复制代码
lrwxrwxrwx 1 user user 25 Sep 28 10:00 my_report.pdf -> /home/user/documents/report.pdf
lrwxrwxrwx 1 user user 13 Sep 28 10:01 website -> /var/www/html
  • 开头的 l 表示这是一个 符号链接(link)
  • -> 后面是目标路径

  • 访问 symlink 就像访问原文件一样:

    bash 复制代码
    cat my_report.pdf    # 实际读取的是 report.pdf
    cd website           # 进入 /var/www/html
  • 删除 symlink 不会影响原文件

    bash 复制代码
    rm my_report.pdf     # 只删链接,report.pdf 仍在

⚠️ 注意事项

情况 行为
删除原文件 symlink 变成"悬空",访问时报错
重命名原文件 symlink 失效(除非你更新链接)
symlink 指向相对路径 路径是相对于 symlink 所在目录的
相对路径示例:
bash 复制代码
cd /opt/app
ln -s ../config/settings.conf config_link
# config_link 指向 /opt/config/settings.conf

特性 Symbolic Link (symlink) Hard Link
跨文件系统 ✅ 支持 ❌ 不支持
指向目录 ✅ 支持 ❌ 通常不支持
删除原文件后 ❌ 链接失效 ✅ 数据仍可访问(inode 引用计数 > 0)
占用空间 极小(存路径) 无额外空间(共享 inode)
权限 自身权限(通常 rwxrwxrwx) 与原文件完全一致

💡 常见用途

  • 为常用程序创建简短别名:
    ln -s /usr/local/bin/python3.12 py
  • 管理多版本软件:
    ln -s node-v18.17.0 node → 切换版本只需改链接
  • Docker 或 Web 项目中链接配置文件
  • 避免重复拷贝大文件/目录

✅ 总结

symlink = 指向另一个文件/目录的"指针文件"

它轻量、灵活、可跨分区,是 Linux 系统管理和开发中非常实用的工具。

创建命令记住:

bash 复制代码
ln -s 目标 链接名

❤️ 一起学AI


  • ❤️ 如果文章对你有些许帮助、蟹蟹各位读者大大点赞、评论鼓励博主的每一分认真创作
相关推荐
shizidushu19 天前
Hugging Face NLP课程学习记录 - 3. 微调一个预训练模型
人工智能·学习·自然语言处理·微调·huggingface
HuggingFace2 个月前
Hugging Face 开源 HopeJR 机器臂!今日直播带你深入技术核心
开源·机械臂·huggingface
_Meilinger_4 个月前
碎片笔记|PromptStealer复现要点(附Docker简单实用教程)
docker·huggingface·tmux·promptstealer·hf-mirror
Uncertainty!!6 个月前
在huggingface上制作小demo
开发语言·python·机器学习·huggingface
leo03086 个月前
修改HuggingFace模型默认缓存路径
人工智能·大模型·llm·huggingface
mask哥7 个月前
huggingface NLP主要知识点以及超级详解使用
pytorch·python·自然语言处理·大模型·huggingface
伪_装7 个月前
Linux服务器部署Deepseek、Dify、RAGflow实战教程
linux·服务器·docker·huggingface·dify·ollama·ragflow
熊文豪7 个月前
轻松微调大模型:利用 Colab 和 Unsloth 实现高效训练
lora·huggingface·ollama·unsloth·googlecolab·ai微调·医疗ai
GarryLau8 个月前
huggingface/pytorch-image-models
pytorch·python·huggingface