我最早意识到"默认目录"这个事有多坑,是在帮朋友排查一台 CentOS 7.9 服务器的时候。那台机器配置不算差,内存 64G,GPU 是 A100,根分区给了 120G,怎么看都够跑个 7B 模型。结果 snapshot_download 下载到一半直接报磁盘不足,df -h 一看,/ 已经 100% 占满,再一查,好家伙,ModelScope 默认把模型全下载到了 ~/.cache/modelscope/hub 下,而他是 root 登录,~ 就是 /root,一个 70 多 G 的模型文件直接把我拍死在沙滩上。
这个坑其实特别隐蔽。ModelScope 不像有些工具会在日志里打印"模型已下载到 /xx/xx 目录",它静默写到默认缓存路径,服务器跑到一半磁盘爆了才发现。所以这篇文章我打算把 CentOS 系统下 ModelScope 模型下载的默认目录规则、迁移方法、磁盘排查思路、以及一堆和下载目录相关的周边问题一次讲透。不管你是刚入门的小白,还是已经被磁盘搞到头秃的老运维,这份内容应该都能帮到你。
1. ModelScope 下载模型的默认目录到底在哪
先说结论,ModelScope Python SDK 安装后,默认模型缓存目录遵循一个固定的规则:
code复制~/.cache/modelscope/hub
其中 ~ 是当前执行 Python 脚本的操作系统用户的 HOME 目录。如果你是 root 执行,那就是 /root/.cache/modelscope/hub;如果是普通用户 work,那就是 /home/work/.cache/modelscope/hub。这一点和 Hugging Face 的 ~/.cache/huggingface/hub 非常像,ModelScope 在设计上明显参考了类似的缓存机制。
往下拆一层,hub 目录内部的布局也有规律。ModelScope 会按照模型 ID 的组织结构来分层存放。比如你下载模型 ID 为 qwen/Qwen2.5-7B-Instruct 的模型,那么实际文件会放在:
code复制~/.cache/modelscope/hub/models/qwen/Qwen2.5-7B-Instruct/
也就是说,模型 ID 中的"组织名/模型名"会被解析成目录层级,但在最前面加了一层 models。如果你下载的是某个数据集,则是 datasets,比如:
code复制~/.cache/modelscope/hub/datasets/zhangpeng/data_demo/
模型目录下还有快照版本的概念。ModelScope 借鉴了 Git LFS 和 Hugging Face 的快照机制,下载的模型会带一个版本目录或者快照标识,同一模型多次下载不同版本时,不同版本之间会分目录存放,避免相互覆盖。不过日常使用中,大多数用户只下载 master 分支或默认版本,所以看到的结构通常比较简洁。
如果你是第一次接触这个目录,建议先做一个自查操作,确认当前机器上的实际路径:
bash复制# 查看 modelscope 缓存根目录占用
du -sh ~/.cache/modelscope
# 查看已经下载了哪些模型
find ~/.cache/modelscope/hub -maxdepth 3 -type d | head -50
# 如果想看具体的模型文件大小
du -sh ~/.cache/modelscope/hub/models/*/*/
执行之后你会发现,模型文件的真实体积往往比你在模型主页看到的要大。因为很多模型页标注的是权重文件的大小,实际下载后还要算上分片文件、配置文件、tokenizer 文件、甚至是一些临时下载残留。多模型累积下来,缓存目录变成磁盘杀手一点都不奇怪。
还有一个容易误判的地方:ModelScope 的下载和支持库版本没关系。不管你是用 pip install modelscope 装的最新版,还是某个旧版本,默认缓存路径在逻辑上是一致的,都走 ~/.cache/modelscope 这个根。区别只是不同版本对目录内部的快照管理和临时文件清理策略不同,但大方向不变。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 为什么这个目录在 CentOS 上特别容易引发事故
默认目录在哪个系统上都存在,但 CentOS 环境下它尤其危险,我总结下来有三个现实原因。
第一,CentOS 服务器大多是传统分区习惯。很多运维老哥(包括我早年)安装系统时喜欢把 /boot 给 200M,/ 给 50G 或者 80G,/home 独立分区,然后单独挂一个 /data 大分区放业务数据。这种分区方案的出发点是好管理、好备份,但它有一个致命点:模型下载默认落到 /root 或 /home/xxx,也就是根分区上,而不是你的数据分区。于是根分区被悄悄写满,结果就是系统服务异常、日志写不进去、数据库崩、SSH 都异常卡顿。
第二,CentOS 的用户习惯带来权限上的"隐形陷阱"。很多人在服务器上长期用 root 操作,下载模型时顺手就 root 执行,模型全进了 /root/.cache。后来想改成普通用户跑服务,发现普通用户根本读不到 root 目录下的模型文件,又要重新下一遍。更麻烦的是,普通用户如果执行下载脚本,它会往 /home/用户/.cache 写,同一个模型在两处各存一份,磁盘白白翻倍。
第三,也是很多生产环境会踩的雷:systemd 服务启动的进程,默认 HOME 可能不是你想的那个。如果你用 systemd 管理模型推理服务,而 unit 文件里没有显式指定 Environment=HOME=/xxx,服务进程的 HOME 可能是 / 或者 /root,这取决于具体启动方式。ModelScope 的缓存目录就可能出现在极其诡异的位置。我在排查一台机器时,甚至见过模型下载到了 /root 下但服务日志显示运行用户是 nginx,这种错位问题不看进程环境变量根本无法定位。
CentOS 还有个现实背景:7.x 系列已经进入维护末期,很多团队还在坚持用 CentOS 7.9,它的默认文件系统是 XFS,分区扩容虽然支持,但根分区扩容需要重启或者在线操作,服务器承担业务时非常麻烦。相比之下,CentOS Stream 9 以及 Ubuntu Server 在分区和存储管理上要灵活不少。这也是为什么现在网上经常有人问"为什么 Ubuntu 比 CentOS 多"——除了生态和维护周期,存储管理和系统工具链的易用性也是重要因素。
对于还在用 CentOS 的同学,我的建议很简单:第一时间检查分区和默认缓存路径,要么迁移缓存,要么扩容分区,别等到磁盘满了再处理。
检查命令并不复杂:
bash复制# 确认磁盘占用情况
df -hT
# 看根分区和 /home 分区各自剩余
lsblk -f
# 查找占空间的大目录
du -x --max-depth=2 -h / 2>/dev/null | sort -hr | head -20
如果发现根分区已经用了 80% 以上,而模型还没下载,那就先别继续下载了,优先处理缓存迁移或扩容。
3. 修改默认下载目录的三种方法及我的推荐组合
既然默认目录不靠谱,那就要主动给它改到靠谱的位置。这里提供三种主流方案,我按推荐优先级排一下。
3.1 方案一:设置环境变量 MODELSCOPE_CACHE(最推荐)
ModelScope 官方支持一个环境变量:MODELSCOPE_CACHE。设置之后,模型缓存根目录就会从 ~/.cache/modelscope 变成你指定的路径。
一次性临时设置:
bash复制export MODELSCOPE_CACHE=/data/modelscope
python your_download_script.py
长期生效,写入 /etc/profile 或者 ~/.bashrc:
bash复制echo 'export MODELSCOPE_CACHE=/data/modelscope' >> ~/.bashrc
source ~/.bashrc
这个方案的优点是很"透明":你一眼就能看到模型下载到了哪,而且对所有使用 ModelScope SDK 的 Python 脚本全局生效。缺点是你需要确保目标目录存在且有写权限,否则 SDK 可能报错。
我推荐在生产环境为模型服务单独建一个系统用户,并在这个用户的 ~/.bashrc 或者 systemd unit 的 environment 里写入:
ini复制[Service]
Environment=MODELSCOPE_CACHE=/data/modelscope
这样从下载到推理,所有模型文件都固定在一个数据盘目录,不污染系统盘,方便备份也方便清理。
3.2 方案二:在 Python 代码中指定 cache_dir
调用 snapshot_download 时手动传 cache_dir 参数:
python复制from modelscope import snapshot_download
model_dir = snapshot_download(
model_id='qwen/Qwen2.5-7B-Instruct',
cache_dir='/data/modelscope',
revision='master'
)
print(model_dir)
这种方法只对当前这次调用生效,非常灵活。适合你只想临时把某个大模型放到另一个盘,而不想改全局环境变量的场景。
但这里有个坑要提醒你:如果你后面用 pipeline 或 AutoModelForCausalLM.from_pretrained 这类高层 API 加载模型,且不显式传 model_dir,它不会自动去 /data/modelscope 找,而是继续走 ~/.cache/modelscope/hub。所以"用 snapshot_download 下载到自定义目录 + 用 pipeline 加载"这套组合,前后路径必须手动对齐,不然它会重新下载一遍。
3.3 方案三:软链接(适合不想改代码的场景)
如果你不想设置环境变量,也不想改 Python 代码,可以直接用软链接把默认缓存目录指到数据盘:
bash复制# 先把现有的默认缓存目录整体搬走
mv ~/.cache/modelscope /data/modelscope
# 再建立一个软链接
ln -s /data/modelscope ~/.cache/modelscope
这样一来,任何脚本只要按默认路径访问 ~/.cache/modelscope,实际都会落到 /data/modelscope。系统层面的透明转发,对应用无感知。
不过这个方法对权限比较敏感。如果链接目标目录的属主和当前用户不一致,或者目标盘的挂载选项里有 noexec、访问控制列表限制,就可能导致写入失败。我曾经遇到一个很无语的问题:把缓存挪到 /data 后,pip 没问题,但模型下载时提示 Permission denied,排查半天才发现 /data 是另一个团队用 root 建的目录,目录权限是 700,普通用户根本进不去。所以做完软链接后,务必执行一下:
bash复制ls -ld /data /data/modelscope
chown -R work:work /data/modelscope
chmod -R 755 /data/modelscope
3.4 我的推荐组合
综合考虑到可维护性和易用性,我个人的习惯是:
- 新建一个专门的数据目录,比如
/data/modelscope,权限给到运行服务的用户。 - 在系统用户环境变量里设置
MODELSCOPE_CACHE,确保所有脚本、所有调用方式都统一走这个目录。 - 如果某些模型解析确实出现了缓存路径不一致,再辅以 Python 代码里的
cache_dir显式指定,双保险。
这个组合的好处是,模型文件的存放位置是显式的、可预期的、可管理的,而不是散落在各个用户的 HOME 里。
4. ModelScope 与 HuggingFace、Ollama、LM Studio、ComfyUI 的默认存储差异
很多同学在服务器上不只用一个 AI 工具链,ModelScope、HuggingFace、Ollama、LM Studio、ComfyUI 各种工具混着用。它们的默认存储位置各不相同,如果你不清楚这些差异,很容易出现"明明下载过模型,换个工具又下载一遍"的尴尬局面。
| 工具/框架 | 默认存储位置 | 修改方式 | 典型场景 |
|---|---|---|---|
| ModelScope SDK | ~/.cache/modelscope/hub |
MODELSCOPE_CACHE 环境变量或 cache_dir 参数 |
CentOS 上用 Python 下载模型,离线推理 |
| Hugging Face Hub | ~/.cache/huggingface/hub |
HF_HOME 或 HUGGINGFACE_HUB_CACHE |
从 HF 下载模型,transformers 生态 |
| Ollama | /usr/share/ollama/.ollama/models 或 ~/.ollama/models |
OLLAMA_MODELS 环境变量 |
一键部署大模型服务 |
| LM Studio | Linux 版本多在 ~/.cache/lm-studio/models,不同版本略有差异,也支持在软件界面改 |
图形界面设置 | 本地跑模型测试、开发调试 |
| ComfyUI | ComfyUI 安装目录下的 models/checkpoints、models/loras 等子目录 |
代码/启动参数手动指定 | 图像生成工作流 |
ModelScope 和 HuggingFace 的缓存结构比较接近,核心思路都是"根目录 + 模型 ID 分层",所以如果你在两者之间切换,最容易把 ~/.cache 彻底塞满。我见过一台开发机,/root/.cache 下面同时躺着 huggingface 和 modelscope 的缓存,加起来 200 多 G,因为两个工具都不约而同地往 root 目录塞。
Ollama 的存储路径要特别提一下。它默认会把模型下载到系统的共享目录(当以服务方式运行时),环境变量 OLLAMA_MODELS 可以指定模型位置。如果你用 systemd 管理 Ollama,注意改完环境变量后要重启服务,否则不生效。很多人问"ollama 模型下载后存放位置在哪",其实就是上面表里的路径,用 ollama list 看不到路径的话,可以直接 find / -name "*.bin" -size +1G 2>/dev/null 定位大文件。
LM Studio 在 Linux 下相对小众,但确实有同学在 CentOS 上折腾。这里我要说一个教训:LM Studio 的模型目录在不同版本之间差异很大,早期版本是 ~/.lmstudio/models,后来变了 ~/.cache/lm-studio/models。如果你手工下载了一些 GGUF 模型想放进去,却找不到目录,别慌,打开 LM Studio 的模型管理界面,左上角通常会显示当前模型目录的绝对路径。手工放模型时,注意目录结构要符合它的模型 ID 要求,通常需要建 发布者/模型名 这样的层级。
ComfyUI 的逻辑又不一样,它没有"缓存"的概念,模型就是存放在工作目录的 models 下,多个子目录各自独立。比如大模型放 checkpoints,LoRA 放 loras,VAE 放 vae。如果你用 ComfyUI 下载模型失败,大概率是网络问题或目录不存在,可以先手动创建目录、再单独下载模型文件放进去。
理解了这些工具的存储差异,你就能更好地规划一台 CentOS 服务器的磁盘布局。我个人的服务器上,现在是这样安排的:
/data/modelscope:ModelScope 下载的所有模型/data/huggingface:HuggingFace 下载的所有模型/data/ollama:Ollama 专用/data/comfyui/models:ComfyUI 工作流模型- 系统盘除了系统、软件和日志,不做任何模型存储
分区归置清楚,后续扩容和备份都省心。
5. 模型下载写满磁盘和下载变慢的实战排查思路
模型下载遇到问题,最典型的就是两类:磁盘满了、下载慢。这两类在 CentOS 服务器上都很常见,这里分享一套完整的排查思路。
5.1 磁盘满的排查链路
遇到模型下载途中报错,先别急着重试,按下面链路一步步查:
第一步,确认磁盘真实占用:
bash复制df -hT
看哪个分区 Use% 到了 100%。多数情况下是 /。
第二步,定位占空间的大文件:
bash复制# 找大于 1GB 的大文件
find / -xdev -type f -size +1G -exec ls -lh {} \; 2>/dev/null | sort -k5 -hr | head -20
第三步,确认是不是 ModelScope 缓存干的:
bash复制du -sh ~/.cache/modelscope 2>/dev/null
du -sh /root/.cache/modelscope 2>/dev/null
第四步,如果确定是缓存占满,清理思路是什么?先把已经成功下载并加载过的模型文件保留,把那些下载一半的临时文件删掉。ModelScope 下载过程中会生成临时文件,下载中断后会残留,这些残留文件经常占据大量空间。你可以用 ls -lah ~/.cache/modelscope/hub/models/*/*/ 查看是否有 .tmp、.incomplete 之类的残留,有就删掉。
还有一种情况:同一个模型下载了多个版本,或者用不同方式重复下载。比如先用 snapshot_download 下载到默认目录,后来因为调参指定了不同的 cache_dir,结果同一个模型在磁盘上存了两份。这种只能靠定期盘点和规范目录规划来避免。
第五步,如果磁盘确实不够,而模型又不能删,那就考虑扩容。CentOS 7.9 的 XFS 根分区支持在线扩容,但前提是你当时用的 LVM 分区。如果是普通分区,扩容往往需要重启进单用户模式操作。这属于运维层面的大工程,不在模型下载的讨论范围内,但遇到磁盘不足时,这是最快的治本方案。
5.2 下载慢和下载失败
ModelScope 本身是国内服务,正常网络环境下下载速度应该不差,但如果你下载慢,可能的原因有几个:
- 带宽被其他服务占满:服务器上可能同时有日志备份、数据库同步等任务,优先错峰下载大型模型。
- 磁盘写入速度是瓶颈:特别是机械硬盘,网络明明很快,但写入跟不上。可以用
iostat -x 1看磁盘 IO 使用率,如果%util接近 100%,说明写盘太慢,这时候可以换 SSD,或者用内存盘做临时下载再转存。 - 并发数过高导致限速:ModelScope 的下载工具默认支持并发分片,但并发太高可能触发服务端限制,反而更慢。建议先保持默认参数,观察速度;如果速度波动大,再考虑限制并发。
关于 ModelScope 下载加速,我的经验是:不要老想着找"加速工具",先确认基础网络和磁盘没问题,然后利用好官方 SDK 的机制。snapshot_download 本身有断点续传能力,一次没下完,重新执行命令会自动从断点继续,而不是从头开始。这比你自己写下载脚本硬扛要稳得多。
此外,下载完成后建议做个校验。大模型文件本身有哈希信息,ModelScope 下载工具通常会自动校验,但如果遇到文件损坏,模型加载时会报权重不匹配之类的错误。那种情况不要频繁重试,把对应的目录删了,重新 snapshot_download 一遍即可。
ComfyUI 下载模型失败也是同理。很多失败不是代码问题,而是网络中断、磁盘满、目录权限不足。先 df -hT 看磁盘,再手动把模型文件下载后放进正确目录,比反复在 UI 里点重试有效得多。
6. 我在服务器上踩过的和模型缓存路径有关的几个坑
最后分享几个我亲历的坑,都是和 ModelScope 默认下载目录相关的真实案例,希望能帮你节省几个小时的排查时间。
第一个坑:环境变量只写在了终端,没有写进 systemd。我当时需要把模型下载到一个大容量数据盘,于是在命令行 export 了 MODELSCOPE_CACHE,手动下载一切正常。然后我把同一个下载脚本写成了 systemd 服务,结果服务运行后模型还是下到了 /root/.cache。原因就是 systemd 服务不会自动读取你终端里的 ~/.bashrc,必须显式在 unit 文件里写上环境变量。这个坑非常具有迷惑性,因为你看日志好像一切正常,只有检查磁盘才发现路径不对。
第二个坑:软链接做完了,但忘了处理权限。有一次我把 ~/.cache/modelscope 软链到 /data/modelscope 之后,用普通用户跑下载,报 /data/modelscope 权限不够。查了一下,数据盘根目录是 root 建的,权限 700。解决办法是 /data 不能直接设成 755,最好建一个子目录然后授权给目标用户。这看起来是个很小的权限问题,但在生产环境里,你不可能让服务用 root 跑,所以必须把目录属主和权限在迁移后立刻处理干净。
第三个坑:多用户复用模型缓存时,目录结构错乱。部门有两台 CentOS 服务器,多个同事各自下载模型,有人用 root,有人用自己的账号,结果同一个 Qwen 模型在 /root/.cache、/home/alice/.cache、/data/modelscope 各有一份,总存储量比模型实际体积翻了三倍。后来我直接把模型目录收敛到一个统一的位置,全员通过只读访问共享模型,把散落各处的缓存全部清掉,磁盘占用立竿见影地降下来了。如果你的团队也是这样共用机器,强烈建议约定一个统一的模型缓存策略,别让每个人各下一遍。
第四个坑:下载中断后残留文件没清理。有一次下载一个很大的多文件模型时网络断了,ModelScope 提示失败。我重新执行了下载命令,看起来从断点续传了,但检查磁盘,发现临时文件占了不少空间。这类残留文件平时看不到,只有 du 扫目录才能发现。建议每次下载完成后,用 du -sh ~/.cache/modelscope 对比一下模型目录的实际大小,如果明显大于预期,就要检查是否有残留。
第五个坑:清理缓存时不小心删了还在用的模型。有些模型加载到内存后不再读磁盘文件,这时候删除磁盘占用是安全的;但如果服务还没完全加载完,删除文件会导致加载失败。最稳妥的做法是先停掉推理服务,再清理模型文件,别在高负载运行的时候直接 rm。
我现在处理模型下载问题时,已经形成了一套肌肉记忆:先 df -hT 看分区,再看 du -sh ~/.cache/modelscope 看缓存,随后环境变量确认,最后才执行下载。这套流程帮我在很多机器上快速定位了问题。说句实在话,大部分 AI 项目的报错,最后查来查去都是存储路径、磁盘空间、权限这三板斧。ModelScope 的模型下载默认目录说起来不是什么高深知识,但搞不清楚它,轻则磁盘写满,重则服务崩溃、模型重复下载浪费几天时间。希望这篇文章能让你少走一些弯路。
