news 2026/9/27 1:33:35

PyTorch离线安装实战:版本选择、依赖打包到完整部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyTorch离线安装实战:版本选择、依赖打包到完整部署

PyTorch 离线安装这事儿,说简单是真简单,说恶心也是真恶心。简单在于它本质上就是“把安装包下载好,再拿到目标机器上装”,恶心在于 PyTorch 的依赖链又长又绕,CUDA 版本、Python 版本、显卡驱动、GCC 版本里任何一个不对,你就等着在报错里原地转圈吧。我这篇文章就是把这两年的离线安装经验全部倒出来,从准备工作到最终验证,一次性讲透,保证你照着做能少踩一半以上的坑。

先交代一下适用场景。你如果是在完全没外网的内网服务器、客户现场、保密机房,或者单位里网速烂得连 pip 都拉不下来的环境,这篇文章就是给你写的。当然,如果你只是在自己笔记本上想换个方式装,也能参考,但说实话联网环境直接 pip install 就完事了,不需要看那么多细节。这篇文章的目标是:让完全不懂离线依赖管理的人,也能在自己的机器上把 PyTorch 干干净净地装好,跑起来,并且在报错的时候知道自己在干什么。

我主要覆盖两种最主流的离线安装路线:纯 pip 离线包安装,以及 Anaconda/Conda 离线包安装。顺便把 CPU 版和 GPU 版之间的取舍也讲清楚。文章内容按我自己的实操顺序来写,你完全可以按章节顺序执行,也可以跳到自己关心的部分直接看。

1. 离线安装前的思想准备:搞清楚你要装什么版本

1.1 为什么版本选择是离线安装的头号难题

联网安装你出错了可以搜,离线安装出错了你连搜都得掂量掂量。所以我首先要说的不是“怎么装”,而是“装什么”。PyTorch 的安装包对 Python 版本、CUDA 版本、cuDNN 版本都有严格的对应关系,比如 PyTorch 1.13 对应的 CUDA 是 11.6/11.7 和 cuDNN 8.x,PyTorch 2.x 系列默认支持 CUDA 11.8/12.1。这个对应关系一旦搞错,就算你包下载全了,装完以后 import torch 直接给你来个段错误或者报找不到 libcudart.so,那心态直接爆炸。

我在给一台离线 CentOS 7.6 服务器装 PyTorch 的时候,第一次就因为没查 CUDA 和 PyTorch 的兼容矩阵,装了 PyTorch 1.12(默认对应 CUDA 11.3),结果机器上装的是 CUDA 11.6 的驱动,虽然理论上能跑,但 import 的时候告诉我找不到某个 cuDNN 符号,折腾了一下午才发现是版本配对的问题。从那以后我定了个规矩:离线装 PyTorch,第一件事永远是把兼容矩阵查清楚,第二件事是把自己机器的显卡驱动和 CUDA 版本确认清楚,第三件事才是去找安装包。

另外还有一个容易踩的坑:Python 3.11 之后,必须要 PyTorch 1.13 以上版本才支持,PyTorch 1.10 之类的老版本在 Python 3.11 上直接不能装。所以你在离线机器上如果只装了 Python 3.11 而没有别的版本,就只能装新版本 PyTorch。这一点在选版本前务必先确认。

1.2 确认目标机的 Python 和显卡驱动版本

在下载任何东西之前,先在目标离线机器上执行一系列命令,把所有版本信息摸清楚。我每次去新环境都会先跑一遍下面的命令,心里有数才能动手:

python --version python3 --version conda --version nvidia-smi

前三条看 Python 环境和 Conda,第四条看显卡驱动以及它支持的最高 CUDA 版本。这里有个很常见的误区:nvidia-smi输出的右上角那个CUDA Version: 12.4代表的是驱动支持的最高 CUDA 版本,而不是你机器上已经装好的 CUDA Toolkit 版本。真正决定要不要装 CUDA Toolkit,取决于你后续是否要用 nvcc 编译自定义算子。如果只是用 PyTorch 跑训练推理,PyTorch 里自带的 CUDA runtime 就够了,甚至可以不用额外装 CUDA Toolkit。但是驱动必须足够新,驱动版本太老而 PyTorch 对应的 CUDA 版本太高,是会直接报错的。

再一个就是查清楚显卡型号。nvidia-smi -L可以列出你所有的 NVIDIA 显卡,Ampere 架构和 Turing 架构的显卡在跑同一个 PyTorch 版本时,行为也会有一些细微差别,不过对多数用户来说,只要驱动够新就行。

目标机器上如果没有 Python 或者没有 Conda,那你的离线安装方案里还要额外带一个 Python/Conda 的离线安装包,这就涉及“先有鸡还是先有蛋”的问题。我建议最简单友好的办法是:提前在一台联网的机器上,把整个 Anaconda/Miniconda 离线安装包下载好,拷到目标机器装上,然后在 Conda 环境里装 PyTorch。这样 Python 版本问题就变得可控,而且 Conda 会把 Python 作为依赖自动匹配好,少掉一大堆版本冲突的麻烦。

1.3 在联网机器上收集环境信息

这里有个小技巧:不是直接盲目去官网下载,而是先在联网机器上装一个和离线目标机相同 Python 版本的虚拟环境,然后在里面执行你要装的那个 PyTorch 的 pip 安装,把依赖自动解析出来,再用pip download把这些依赖全部下载成 whl 文件。这样你不需要手动一个个去查 PyTorch 到底依赖了 numpy 那个版本、typing-extensions 哪个版本,pip 会自动帮你决定。

这个方法听起来绕,但实际非常省事。我在帮朋友内网摸服务器环境的时候,就是这么干的:先把 conda 或 venv 环境建好,Python 版本调成和离线机一致,然后执行:

pip download torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 -d ./pytorch_offline_packages

它不光会下载 PyTorch 三件套,还会把 torch 依赖的 numpy、typing-extensions、networkx、jinja2 等等全部下到同一个目录。这时候你再看目录下生成的文件,就有底了:原来 PyTorch 装个 GPU 版要拉这么多东西。

不过这么做有个潜在问题,就是你联网机器上的 Python 版本和操作系统必须跟离线机器一致或者非常接近。如果联网机是 Ubuntu 20.04 装的 Python 3.8,离线机是 CentOS 7 的 Python 3.8,那 wheel 文件基本是通用的,绝大多数纯 Python 和带 C 扩展的 wheel 在同一 Python 版本内可以跨 Linux 发行版使用。但如果你联网机是 Windows,离线机是 Linux,那就完全不能这么干,需要换一台同样操作系统的联网机。

2. 依赖包的收集:找全并校验 PyTorch 所需的全部文件

2.1 分离 PyTorch 本体和依赖包

很多人离线装 PyTorch 失败,不是败在 PyTorch 本体,而是败在依赖包缺失。PyTorch 这个库对 Python 科学计算生态的依赖相当沉,你能想到的 numpy、pillow、typing-extensions,不能想到的 sympy、networkx、jinja2、filelock、fsspec,还有带 CUDA 版本时依赖的 nvidia- 开头的若干库,加起来少说十几二十个。手动在官网只下载 torch、torchvision、torchaudio 三个包,装的时候必然在某个依赖上报错。

所以我的做法是把“PyTorch 本体包”和“通用依赖包”分开收集。用上一节讲的pip download方式拉取依赖当然最稳,因为 pip 会按需下载。但如果你没有现成的联网 Linux 环境,就只能去 PyPI 官网一个个找,那么请记住下面这个依赖清单的顺序,照着抓基本不会漏:

PyTorch 2.x 系列常见依赖(Linux + CUDA 版):

  • torch、torchvision、torchaudio 本体
  • numpy(1.21 以上,具体版本看 PyTorch 版本要求)
  • typing-extensions
  • pillow
  • sympy
  • networkx
  • jinja2
  • filelock
  • fsspec
  • packaging
  • pyyaml
  • requests
  • triton(Linux 版 PyTorch 2.x 特有)
  • nvidia-cublas-cu11 / nvidia-cudnn-cu11 / nvidia-cufft-cu11 / nvidia-curand-cu11 / nvidia-cusolver-cu11 / nvidia-cusparse-cu11 / nvidia-nccl-cu11 / nvidia-nvtx-cu11 / nvidia-cuda-runtime-cu11 等(具体以版本对应为准)

要特别说明的是,pip 不会自动帮你安装 nvidia 开头的这些 CUDA 依赖,除非你直接用 PyTorch 官方仓库的 index-url。也就是上一节里pip download torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118的写法才保证把 nvidia 相关依赖一并解析下载。如果你从 pypi.org 下载 torch 的 whl,会发现它不强制拉取这些 nvidia 库,装完以后 import torch 会报 CUDA 不可用,因为 core library 里的 CUDA runtime 加载不到。

2.2 手动用 pip download 收集离线安装包

在自己的联网 Linux 机器上,复制下面这套流程,就能在十分钟之内拿到全部离线包:

mkdir -p ~/pytorch_offline cd ~/pytorch_offline python -m venv temp_env source temp_env/bin/activate pip install --upgrade pip # 下载 CPU 版 pip download torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu -d ./cpu_packages # 或者下载 CUDA 11.8 版 pip download torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 -d ./cu118_packages

这里的关键参数是--index-url。PyTorch 官方提供了一组独立的仓库地址,分别是cpu、cu118、cu121等分支。直接用 pypi 源下载的 torch 通常默认不绑定 CUDA,你会发现包体积只有 200MB 左右,而官方 CUDA 版的包动辄 2GB 以上。这也是为什么很多人在内网试着装 torch GPU 版,最后装成了 CPU 版还不自知的常见原因。

收集完成以后,在~/pytorch_offline目录下会看到一堆.whl文件。建议你在打包拷贝之前,先做几件事:

ls -lh pip download 也会顺带下载依赖的依赖,所以目录里有几十个文件是正常的。

我见过不少同行直接把torch-2.0.1+cu118-cp38-cp38-linux_x86_64.whl单独拷走了,忽略了旁边的torchvision-0.15.2+cu118-cp38-cp38-linux_x86_64.whl以及一堆依赖。结果在内网 pip install 的时候直接报ERROR: Could not find a version that satisfies the requirement ...。奉劝一句:打包整个目录,别只挑大的拿。

2.3 离线包的正确传输方式和校验

离线包下载好以后,怎么传到目标机器上也是一门学问。通常用 U 盘拷贝或局域网共享目录。为了安全起见,我强烈建议你在联网机器上先做一次完整性校验:

md5sum *.whl > checksums.md5

然后连把 checksums.md5 一起拷到离线机器上,执行:

md5sum -c checksums.md5

这一步不是形式主义。有一次我从官网下载一个 2.4GB 的 torch wheel,拷 U 盘的时候断了一次,第二次拷贝完成后没有校验,直接拿去装,结果安装过程到一半就报错说 zip 文件校验失败。排查了二十分钟才发现是传输过程中文件损坏。有了校验文件,基本能排除这种低级但让人抓狂的问题。

另一个注意点:不要通过压缩软件二次压缩.whl 文件。whl 本身就是一个 zip 格式包,你把它压成tar.gz再解压没问题,但如果使用某些 Windows 上的压缩工具,会对内部文件重新编码,可能破坏符号链接或者修改权限位,导致安装时报无法安装的错误。用标准tar或zip打包是安全的,但用 7-Zip 的安卓版/特殊版本就要小心了。

3. 两种离线安装路线:pip 离线装法与 Conda 离线装法

3.1 路线一:pip 离线安装,主推官方 wheel 批量装

到了目标机器以后,离线环境的安装步骤不多,但顺序很重要。先把所有 wheel 文件上传到目标机的某个目录,比如/home/user/pytorch_packages,然后在这个目录下执行:

pip install --no-index --find-links=/home/user/pytorch_packages torch torchvision torchaudio

如果目标环境用的是 Python 虚拟环境,记得先激活虚拟环境:

source venv/bin/activate pip install --no-index --find-links=/home/user/pytorch_packages torch torchvision torchaudio

--no-index的意思是告诉 pip 不要访问 PyPI 仓库,只用本地目录里的文件。--find-links则指定本地目录是查找源。这两个参数配在一起,就能实现完全纯离线的安装。如果你执行的时候看到 pip 还在尝试访问外网地址,那多半是漏写了--no-index。

如果安装过程中报某个包找不到,不要慌,大概率是你收集包的时候漏掉了某个依赖。解决办法是回到联网机器上,单独补下这一个包装到离线包里,再重新执行上述命令。因为 pip 遇到已安装的依赖会跳过,所以重复执行同一个安装命令是安全的。

另外有个更省事的路线:如果你收集到的依赖都已经比较全了,也可以直接:

pip install /home/user/pytorch_packages/*.whl

但我不推荐这个做法,因为*.whl的通配符在 Linux bash 下会扩展成所有文件名,如果文件名过多,单行命令可能超出 shell 的参数长度限制,而且在文件名带空格等特殊字符时会奇奇怪怪地失败。还是显式列出要装的包名更可靠,让 pip 去解析依赖。

还有一个长期实战中发现的细节:离线安装完成后,不要立刻删掉 wheel 文件。因为后续你可能要装更多的 PyTorch 生态库,比如torch-geometric、timm、transformers,它们的依赖里有一部分跟 torch 重复,如果 wheel 文件还在,你直接再跑一次--find-links安装,就能保持完全的离线状态,不用到网上找依赖。

3.2 路线二:Conda 离线安装,解决 Python 版本冲突的神器

如果你在离线机器上有 Conda 环境,那么离线安装 PyTorch 其实有另一条更省心的路。核心思路是先在联网机器上用conda拉取 PyTorch 的离线包和所有依赖,再拷到目标机器上通过conda install --offline安装。

第一步,在联网机器上执行:

conda create -n offline_env python=3.9 -y conda activate offline_env

然后下载 PyTorch 的 conda 包:

conda install torch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia --download-only

注意--download-only参数。这个参数让 conda 只把包下载到本地缓存,不做实际安装,这样你可以把缓存目录下的文件全部拷走。不同机器的 conda 缓存位置一般在~/anaconda3/pkgs或~/miniconda3/pkgs。

理论上也可以这样操作:联网机器和目标机器都安装 Miniconda 并指定同样的环境,然后用conda-pack打包整个环境目录,复制到目标机器上解压即可。但conda-pack打包出来的东西对操作系统的依赖还是有的,而且如果目标机器处理器架构不同,会直接不兼容。所以我更推荐的方式是:conda 只用来管理 Python 和基础依赖,PyTorch 本体依然用 pip 装。原因很简单,conda 的依赖解析在离线时会有很多锁版本的情况,而 pip 对纯 wheel 目录的使用要直接得多。

如果非要完全走 conda 离线路线,注意以下几点:

第一,conda install --offline的参数是--offline,但它只表示不从远程仓库拉取包,还是会从你本地的 pkgs 缓存目录或者你指定的--channel路径去找包。所以离线机器上也要保留完整的 pkgs 目录。

第二,conda 的包是带时间戳的压缩包,如果联网机器的缓存里有旧版本和新版本混在一起,conda 在离线解析时可能会选一个你并不想要的版本。最好在联网机器上先创建好环境并实际安装成功一次,再把整个pkgs目录复制过去,这样缓存里留下的就是已成功安装的那一组版本,离线机照着同样的解析路径大概率可以成功。

3.3 两种路线的对比和我的个人建议

说到 pip 离线安装和 conda 离线安装,每次都有朋友问我哪个更好。我把两种方式的优缺点列成一张表,你看一眼就明白:

对比项pip 离线安装conda 离线安装
依赖收集难易度中,pip download 自动拉取高,conda 离线包需要整个 pkgs 同步
Python 版本管理需要单独处理conda 环境自带 Python,自动匹配
CUDA 库集成PyTorch 官方 wheel 自包含通过 pytorch-cuda 包单独装
安装后体积相对小相对大,conda 有自己的库目录
在无网环境成功率高(只要 wheel 齐全)中,依赖解析容易因缓存版本混乱失败
推荐场景绝大多数内网服务器已有 conda 环境且需要精确管理 Python 版本

我个人的习惯是:能 pip 就不 conda。特别是完全离线的服务器上,pip 配合官方--index-url下载下来的 wheel 包有天然的版本自洽性,因为 PyTorch 官方已经把你的 CUDA、cuDNN 这些底层库全部编译打包进去了,你根本不用管。而 conda 路线里,你还要手动指定pytorch-cuda的版本,略微麻烦。

4. 版本兼容矩阵与 GPU 版安装的关键细节

4.1 PyTorch、Python、CUDA 官方兼容矩阵速查

这个矩阵是我必查的一张表,每次换新版本都得翻一遍,顺手把关键结论整理在下面:

PyTorch 版本稳定版对应 Python支持的 CUDA 版本示例备注
PyTorch 1.10.x3.7-3.9CUDA 10.2 / 11.3老项目还在用
PyTorch 1.12.x3.7-3.10CUDA 10.2 / 11.6早期常见版本
PyTorch 1.13.x3.7-3.10CUDA 11.6 / 11.7首次支持 macOS M1
PyTorch 2.0.x3.8-3.11CUDA 11.7 / 11.8大规模编译重构
PyTorch 2.1.x3.8-3.11CUDA 11.8 / 12.1常用稳定版
PyTorch 2.2.x3.8-3.11CUDA 11.8 / 12.1推荐内网使用
PyTorch 2.3.x3.8-3.12CUDA 11.8 / 12.1 / 12.4新卡支持更好

这里值得多说一句:选择 PyTorch 2.1/2.2 的 CUDA 11.8 版本,是目前内网部署最稳妥的方案。原因有几个:一是 CUDA 11.8 对老卡如 V100、T4、P4 都有很好支持,二是 PyTorch 官方对 cu118 分支维护期长,下载源稳定,三是用户环境里大部分显卡驱动哪怕是一年多前的版本也能兼容 CUDA 11.8。反过来,CUDA 12.x 需要相对较新的驱动,在驱动不敢随便更新的内网环境,容易引入麻烦。

4.2 GPU 版安装时容易忽略的 CUDA 依赖库

装 GPU 版 PyTorch 最让人头疼的一个坑是:你明明按照官方命令装了torch的 CUDA 版 wheel,torch.cuda.is_available()却返回 False。排查下来最常见的原因是libcudnn.so或libcublas.so找不到。为什么会出现这个情况?

如果你是通过--index-url https://download.pytorch.org/whl/cu118走官方源的,那 torch 会把nvidia-cublas-cu11等依赖自动带上,整个运行时是自包含的。但如果你的 torch wheel 是从 pypi 主源下载的,它默认是 CPU 版,或者没有拉全 NVIDIA 的库。在离线安装场景下,如果你用的 wheel 是从 pypi 下载的,请务必检查 whl 文件名里有没有+cu118或者类似的 CUDA 标识,没有的话直接换包。

还有一个细节是triton库。PyTorch 2.0 以上的 Linux 官方 wheel 要求triton这个库,而且它不在 pypi 主源,而是在 PyTorch 自己的 index 里。如果你在pip download时没有带官方--index-url,triton 很可能没下来,安装时就会报错。处理方式依然是回到联网机器,从官方源拉一次triton的 wheel,一起放到离线目录里就行。

验证 GPU 是否可用的终极命令就三步:

python -c "import torch; print(torch.__version__)" python -c "import torch; print(torch.version.cuda)" python -c "import torch; print(torch.cuda.is_available())"

如果最后一条输出 True,说明 GPU 版环境基本可用。如果 False,再往后排查:

nvidia-smi # 确认驱动是否正常 ldconfig -p | grep cudnn # 检查系统级 CUDA 库

这里有个容易混淆的概念:PyTorch 的 CUDA 版本和系统的 CUDA 驱动是解耦的。PyTorch 自带大部分 CUDA 库,所以系统里不需要额外安装完整的 CUDA Toolkit,但驱动版本太低也会让 PyTorch 因为CUDA driver version is insufficient报错。这个错误会在torch.cuda.is_available()时打印警告并返回 False。

4.3 CPU 版离线安装:轻量但别忽略底层指令集

如果你只是做一些模型推理、数据处理或不依赖 GPU 的开发调试,CPU 版 PyTorch 是离线安装里最快最省事的。收集包时只需要:

pip download torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu -d ./cpu_packages

CPU 版的 wheel 体积小很多,通常只有一两百兆,依赖也少,没有 nvidia 系列库。不过有个隐藏问题:PyTorch 的 CPU 版对底层指令集有一定要求,尤其是 2.x 以后,官方 wheel 默认启用了 AVX/AVX2 指令集。如果你拿它跑在非常老的 CPU 上(比如 2012 年前的 Core 2 架构,或者某些低端赛扬),可能遇到Illegal instruction (core dumped)的错误。解决办法是选择更早的 PyTorch 1.x 版本或自行从源码编译,但对绝大多数内网服务器来说,现代 Xeon 或 EPYC 处理器都不会有这个问题。真遇到这种老机器,建议直接放弃编译,改用官方老版本。

5. 离线环境下 Anaconda 环境的搭建与激活

5.1 离线装 Miniconda 到目标机器

很多内网服务器上既没有 Python 也没有 Conda,那就需要把环境管理工具也做成离线安装。Miniconda 的离线安装包只有一个.sh文件,官网有Miniconda3-latest-Linux-x86_64.sh直接下载,大概不到 100MB。拷到目标机器上以后执行:

bash Miniconda3-latest-Linux-x86_64.sh -b -p /opt/miniconda3

-b是无交互静默安装,-p指定安装路径。装完后需要把 conda 加到 PATH:

echo 'export PATH=/opt/miniconda3/bin:$PATH' >> ~/.bashrc source ~/.bashrc conda --version

成功的话就能看到 conda 版本号。这一步没有网络也能完成,因为安装脚本不需要联网。

5.2 在离线内网创建独立 Python 虚拟环境

conda 装好了,接下来用 conda 创建虚拟环境。但有个问题:conda create默认会去远程仓库下载 Python 包,离线的时候会卡在Solving environment或提示网络错误。所以离线场景下不能直接从零创建一个新环境,除非你手里有 Python 的离线 conda 包。

最简单的做法是,在联网机器上用 conda 建好一个环境并安装好所有你想要的东西,然后用conda env export或直接复制pkgs缓存文件。不过如果你只是想用系统自带的 Python 环境(假设系统里已经装了 Python 3.9),也可以不创建 conda 虚拟环境,直接用系统 Python 配合 pip 安装 PyTorch 离线包,这样反而少一层复杂度。

如果确实需要纯净环境且没有 Python 包缓存,那就只能先在联网机器上提前抓 Python 的 conda 包:

conda create -n offline_env python=3.9 --download-only

然后去~/miniconda3/pkgs目录里把python-3.9*.conda和相关的openssl、pip、setuptools等包一起拷到离线机的 conda pkgs 目录,然后在离线机上执行:

conda create -n offline_env python=3.9 --offline

这一套流程是可以跑通的,但说实话非常繁琐。我一般不推荐离线环境从零创建 conda 虚拟环境,更建议直接用已有的系统 Python,因为 PyTorch 的 wheel 是二进制包,对 Python 小版本的要求没那么苛刻,只要主版本匹配(比如 3.8、3.9、3.10、3.11),通常都能跑。

5.3 离线环境下 pip 源配置的禁忌

很多朋友习惯在pip.conf里配一个镜像源,比如清华源或者阿里源,但这在离线环境是无效的,而且可能产生一个副作用:pip 在解析依赖时如果发现--index-url指向一个连不通的地址,它会反复重试,消耗大量时间后才报错。所以在离线机器上用 pip 的时候,我建议显式加上--no-index参数,直接在命令行上把网络功能关死,免得 pip 在那里傻等超时。

另一个要注意的是环境中可能存在用户级pip.conf或系统级pip.conf,里面对index-url的配置会影响你的离线安装。你可以用pip config list查看当前配置。如果有配置了远程源,建议临时设置环境变量:

export PIP_NO_INDEX=1 export PIP_FIND_LINKS=/home/user/pytorch_packages

这样即使有配置文件也能强制进入离线模式。

6. 实操全记录:从零到 PyTorch 跑通的完整流程

6.1 一次性操作明细:我的动手步骤

下面这套流程是经过多次内网部署验证过的,讲实话,照着这个来,成功率很高。

预备操作,全部在联网机器上执行:

# 1. 工作目录 mkdir -p /data/offline_setup/pytorch_packages cd /data/offline_setup/pytorch_packages # 2. 创建临时虚拟环境(Python 版本必须与目标机一致) python3.9 -m venv temp_env source temp_env/bin/activate pip install --upgrade pip # 3. 下载 PyTorch GPU 版(建议 cu118) pip download torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 --index-url https://download.pytorch.org/whl/cu118 -d ./cu118 # 4. 生成校验文件 md5sum ./cu118/*.whl > ./cu118/checksums.md5 # 5. 打包(保留目录结构) tar -czf pytorch_cu118_offline.tar.gz ./cu118

然后到离线目标机器上操作:

# 1. 上传并解压 tar -xzf pytorch_cu118_offline.tar.gz # 2. 进入某个存在的 Python 环境,或直接用系统 python python -m venv /opt/pytorch_env source /opt/pytorch_env/bin/activate # 3. 校验文件完整性 cd cu118 md5sum -c checksums.md5 cd .. # 4. 离线安装 pip install --no-index --find-links=./cu118 torch torchvision torchaudio # 5. 验证 python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())"

这五步做完,如果输出2.1.2+cu118和True,那恭喜你,PyTorch 离线环境已经成了。如果输出2.1.2+cpu不代表你装错了,而是你有可能下载到了 CPU 版,回去重新看你的--index-url是不是带了cu118,torch 的版本标识后缀会写清楚。

6.2 常见报错点及我的排查方法

离线安装的过程中,我踩过的坑多到能开一个专栏,这里挑几个最高频的讲一下。

第一个是ERROR: Could not find a version that satisfies the requirement ...。这个报错出现在安装时 pip 找不到某个依赖的匹配版本。最常见原因是离线目录里缺失了对应依赖的 wheel。排查方法是用pip install --no-index --find-links=... --dry-run去解析依赖,它会告诉你缺少哪些包。也可以用grep搜索报错信息里的包名,看看目录里有没有它的.whl文件。

第二个是OSError: [Errno 30] Read-only file system,这个报错比较诡异,通常出现在你把离线包放在只读挂载目录(比如某些公司的只读共享盘)然后直接执行 pip install。解决办法是把离线包先复制到本地可写目录,再执行安装。

第三个是安装过程中报ModuleNotFoundError: No module named 'torch',但明明刚安装过。这种情况往往是环境不对。比如你在系统 Python 环境下用 pip 安装,但激活了虚拟环境后去执行 import,或者反过来。搞清楚当前用的是哪个 Python、哪个 pip,我的习惯是在每个操作前先执行:

which python which pip python -c "import sys; print(sys.executable)"

这三个命令能让你知道自己到底在操作哪个环境。

第四个是安装完 import torch 报Segmentation fault。这类问题九成以上是 Python 版本和 PyTorch 版本不匹配导致二进制接口不一致。比如 PyTorch 1.12(针对 Python 3.10 编译)装在 Python 3.11 的环境上,或者反过来。解决办法就是重选与你的 Python 版本匹配的 PyTorch 版本,wheel 文件名里的cp310、cp311就是对应的 Python 版本标识。

6.3 安装后必做的三件检查事项

装完不管有没有报错,都建议花两分钟做一次检查,把问题扼杀在摇篮里。

第一件,检查 PyTorch 到底用的什么版本和 CUDA:

python -c "import torch; print(torch.__version__); print(torch.version.cuda); print(torch.backends.cudnn.version())"

输出里三个数字缺一不可。torch.version.cuda是空的话说明 CUDA 运行时没带上,torch.backends.cudnn.version()返回 None 说明 cuDNN 没配上。

第二件,测试一个小矩阵的 GPU 运算:

import torch x = torch.randn(3, 3).cuda() y = torch.randn(3, 3).cuda() print((x @ y).sum().item())

如果这段代码可以正常输出一个数,GPU 计算链路就是完整的。注意这里x @ y的结果是一个 CUDA 张量,你调用.item()才能拿到标量,不然可能会碰到不同类型之间比较的问题。

第三件,检查torch.utils.cmake_prefix_path是否指向正确位置。如果你后续要编译 C++ 扩展,这个路径错误会很麻烦。检查命令:

python -c "import torch; print(torch.utils.cmake_prefix_path)"

正常情况下它会输出一个包含 PyTorch 和 CUDA 版本的路径。如果报错或者路径里找不到 PyTorch 的 cmake 文件,说明 PyTorch 安装残缺,重装一遍比修它更快。

7. 常见问题速查:经验值排名靠前的坑与解法

我把自己和周围同事在离线装 PyTorch 过程中遇到的高频问题整理成了一张速查表,你可以直接贴在手边用。

问题现象可能原因解决办法
pip install时一直卡住不动pip 在尝试连接远程源加--no-index,并在离线目录内安装
import torch 报ModuleNotFoundError激活的环境和安装环境不一致用which python和which pip确认
安装时缺nvidia-*依赖wheel 来自 pypi 而不是 pytorch 官方源用--index-url https://download.pytorch.org/whl/cu118重新下载
torch.cuda.is_available()返回 False驱动版本过旧或 CUDA 相关库缺失检查nvidia-smi,更新驱动到至少 450.x 以上
安装时报Illegal instructionCPU 指令集太老,不支持 AVX换用旧版 PyTorch 或源码编译
Segmentation fault崩溃Python 小版本不匹配 PyTorch 编译版本查看 whl 文件中的cp310等标记,匹配 Python 版本
conda 离线安装时提示找不到包pkgs 缓存目录不完整或版本不匹配从联网机器复制完整pkgs目录
安装 torchvision 时找不到 torchtorchvision 和 torch 版本对应关系不匹配按官方版本对应表选同版本的 torchvision

还有一个大坑值得单独讲:把 whl 文件从 Windows 拷到 Linux 后文件名末尾多了一个\r或权限变化。这个现象主要出现在用某些 FTP 客户端传输的时候。解决办法是在 Linux 上重新命名文件,或者干脆在 Linux 上用 tar 打包再传。如果文件名已经乱了,用find . -name "*\r"找出来改回去就行。

8. 离线安装后的环境锁定与下一次复用

8.1 导出当前环境的精确版本信息

当目标机器上的 PyTorch 装好、确认能跑之后,我强烈建议你顺手把环境导出,留个备份。这样下次再遇到同样需求的离线服务器,就能少走弯路。

pip freeze > requirements_offline.txt

requirements_offline.txt里会把所有已安装包的精确版本列出来。下次在新机器上装的时候,可以先按这个文件里的版本去下载 wheel,再批量安装。不过注意pip freeze会把一些不是必须的包也列进去,比如pip本身、setuptools。我一般会做一个清理,只保留与 PyTorch 相关的包。写一个简单地过滤命令:

pip freeze | grep -E "torch|numpy|nvidia|triton|pillow|sympy|networkx|jinja2|filelock|fsspec|packaging|pyyaml|requests|typing" > requirements_torch_only.txt

这个文件里的内容就是下一次离线安装要下载的全部依赖列表了。配合pip download -r requirements_torch_only.txt使用,一条命令搞定所有依赖收集。

8.2 复用同一套离线包的其他注意事项

同一套离线包在一个环境装成功后,并不意味着在所有环境都能通用。下面几个边界情况要特别注意:

  • 目标机器的操作系统不同,wheel 的兼容范围受限。Linux 上的 wheel 在 Linux 发行版之间通常通用,但 Windows 上编译的 wheel 天然不能用。
  • glibc 版本过低的系统(比如 CentOS 7 自带的 glibc 2.17)在跑新版本 PyTorch 时可能报GLIBCXX_3.4.22 not found。这时可以尝试用老版本 PyTorch 或者从源码编译。
  • 如果要装到 Docker 容器里,尽量选择与制作镜像时相同的 CUDA 基础镜像,否则容器里缺了 NVIDIA 驱动相关库,torch.cuda.is_available()也会返回 False。

我遇到过最头疼的情况,就是同一个 wheel 包在 CentOS 7.6 上装得好好的,换到 CentOS 7.2 上就报GLIBCXX缺少符号。两个系统的 glibc 版本不同,但 PyTorch 官方在 2.x 版本已经提高对 glibc 的要求。遇到这种老系统,不要犹豫,直接选 PyTorch 1.10 或 1.12 老版本,别跟它较劲。

8.3 离线部署脚本的编写思路

如果你需要给多台内网机器批量部署 PyTorch 环境,手打命令已经不现实了。可以写一个简单的 Shell 脚本来减少重复劳动。下面是个精简版的示例,你可以根据自己的目录和版本修改:

#!/bin/bash # offline_pytorch_deploy.sh # 用法: ./offline_pytorch_deploy.sh /data/pytorch_packages PACK_DIR=${1:-/data/pytorch_packages} TARGET_ENV=${TARGET_ENV:-/opt/pytorch_env} echo "[1/4] 解压离线包目录..." mkdir -p "$PACK_DIR" && cd "$PACK_DIR" && tar -xzf pytorch_cu118_offline.tar.gz echo "[2/4] 创建虚拟环境 $TARGET_ENV ..." python -m venv "$TARGET_ENV" source "$TARGET_ENV/bin/activate" echo "[3/4] 离线安装 PyTorch ..." pip install --no-index --find-links="$PACK_DIR/cu118" torch torchvision torchaudio echo "[4/4] 验证安装 ..." python -c "import torch; print('torch version:', torch.__version__, 'cuda available:', torch.cuda.is_available())"

脚本里用--find-links的路径是相对目录,实际使用环境可能会因为路径不同而报错,所以建议在脚本开头用cd或PACK_DIR做好路径切换。部署多台机器时,除了跑脚本,还要注意每台机器自身的 Python 版本是否一致。如果不一致,脚本里创建虚拟环境的步骤就会失败。

我一般会在脚本的最后加一个输出日志的文件,把每台机器的安装结果记录下来,方便后续维护:

echo "`date` deploy result: $?" >> /var/log/pytorch_deploy.log

这样哪台机器装成功了、哪台出问题了,一目了然。

9. 我个人在多次离线安装后积累的几条经验

文章写到这里,把主要流程讲完了。最后分享几条只有亲手折腾过的人才攒得出来的心得,也许能让你的离线安装之路顺一点。

第一,离线安装最贵的成本不是下载,而是反复试错。试错成本全在版本不匹配和依赖缺失上,所以下载之前多花十分钟查兼容矩阵、多看一眼 wheel 文件名里的标记,比漏装一个包之后在目标机器上干瞪眼要划算得多。

第二,收集离线包时尽量选择和你目标机相同的操作系统和 Python 版本。一个 Linux 下能用的 wheel,拿到 macOS 上就是废品;一个 Python 3.10 的 wheel,拿到 Python 3.11 里也装不上。如果不知道目标机器的精确 Python 小版本,那就先用python --version确认,再去联网机器下载,别凭感觉猜测。

第三,别一口气装最新版本,除非你真的需要。PyTorch 最新版虽然功能新,但它对驱动、glibc、Python 的要求往往也更高。在内网这种静态环境里,稳定比新功能重要得多。我日常给客户部署时,首选永远是发布半年以上的稳定版本,比如目前主推 PyTorch 2.1.2+cu118。等环境稳定了再考虑升级,这样最省事。

第四,离线安装完成之后,一定把这个环境的安装方式记录下来。我当时就是为了图省事没记录,三个月后要给同样的一台机器再装一遍的时候,发现自己早就忘了当初到底从哪个目录拷的包、用的是哪一组命令,只能重新摸索了一遍。血的教训。

最后再说一个很小的技巧:安装完 PyTorch 后,建议执行一次python -c "import torchvision, torchaudio"确认这两个包也正常导入。很多时候 torch 装好了,但 torchvision 和 torch 的版本不匹配,要到真正用的时候才暴露。提前检查能帮你少一次深夜被叫醒的机会。就这些,祝你的离线环境一次装通。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 1:33:28

车载TBOX功能测试全流程:从单元测试到整车验证的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:32:48

UR5与D435i手眼标定实战:从ROS环境搭建到精度验证完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:32:11

STM32F407 USB CDC虚拟串口高速通信实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:31:49

STM32G4+DMA+VOFA+实现电机实时波形监控

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:31:40

C#面试题体系化整理:从基础语法到高级特性核心解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:31:32

AD9361多片同步实战:内部LO与外部LO选型、调试与相位误差控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华