如果你看到这个标题,多半和我前段时间的状态差不多:工作环境是Windows,外网连不上或者网速极不稳定,但项目又指明要用Pytorch,得在本地完成离线安装。网上关于Pytorch安装的教程确实多,但绝大多数是抱着联网环境写的,一行 pip install torch 就完事,到了没网的机器上完全跑不通。我花了一整天在这台Windows开发机上折腾,中间踩了不少坑,最后整理出几条靠谱的离线安装路径。这篇文章就把我完整的过程和踩坑经验写出来,给同样被这个问题卡住的读者当个参考,尤其是准备在无法访问外网的Windows环境里部署Pytorch的同学。
Pytorch离线安装这件事,难点不在"安装"本身,而在"怎么把对的东西提前准备好"。很多人以为离线安装就是把whl文件拷过去 pip install 一下,实际上版本不匹配、依赖缺失、GPU相关DLL加载失败这些问题,往往在安装完成后才集中爆发。所以我这篇不打算只给命令,而是把版本判断逻辑、依赖收集方法、避坑经验和验证手段串起来,按我实际操作的顺序一步步讲。
1. 先搞清楚你的离线属于哪种场景:方案选错了后面全是坑
1.1 离线安装的本质
绝大部分Python库的安装都依赖PyPI仓库,Pytorch也不例外。在线安装是一条链路:pip从远程仓库拉取包,自动解析依赖,再逐个安装。离线安装的本质,就是把这条链路拆成两段:第一段在能联网的机器上把包和依赖全部下载好,第二段把下载结果搬到目标机器上进行本地安装。
听起来不复杂,但Pytorch有个特殊的地方——它的安装包体积非常大,GPU版本的wheel解压后动辄三四个GB,而且它依赖的底层库(比如numpy、pillow、sympy、networkx、jinja2、fsspec这些)加起来也有不少。更麻烦的是,Pytorch官方源和普通PyPI源上的包并不完全一致,GPU版本还分cu118、cu121、cu124等不同CUDA编译版本。版本选错了,轻则装上不能用,重则直接DLL加载失败。
1.2 三类典型场景和对应的路线
我把离线安装的常见场景分成三类,你可以对照自己属于哪一种:
- 完全内网隔离:目标机器与外网完全隔绝,最多只能插U盘拷贝文件。这种场景下最稳妥的方案是"联网机器下载whl + 离线pip安装",或者"conda-pack整环境迁移"。
- 半隔离状态:目标机器无法访问外网,但能访问公司内网的软件源(比如内部搭建的PyPI镜像或conda镜像)。这种场景最简单,只需要把pip或conda的源地址指到内网镜像即可,本质上和在线安装没区别。
- 批量部署多台机器:需要在比赛机房、多人团队或多台测试机上安装相同版本的环境。这种场景强烈建议用conda-pack,把一套完整的环境打包复制到所有机器,避免一台一台重复配置。
我这次遇到的是第一种场景,完全内网隔离,所以下面重点讲两条路线:pip + whl离线安装和conda-pack整环境迁移。这两条路线在第二种场景下只要稍作调整就能用。
1.3 pip+whl 与 conda-pack 两种路线的取舍
先说结论:如果只是在一台机器上装Pytorch,选pip+whl就够了,轻量、直接、便于管理;如果是多台机器或者想连Python环境整个复制,用conda-pack更省事。
这两者的核心区别在于打包粒度。pip方案只打包Python包本身,目标机器上仍然需要预装Python,并且要保证Python版本、操作系统架构完全匹配。conda-pack则把整个conda环境打包,包括Python解释器、所有第三方库、甚至环境变量配置,目标机器上连Python都不用装,解压就能用。
我用一张表格归纳一下:
| 对比维度 | pip + whl 离线安装 | conda-pack 整环境迁移 |
|---|---|---|
| 目标机器是否需要预装Python | 需要 | 不需要 |
| 对版本匹配的要求 | 严格,Python版本/系统位宽必须匹配 | 宽松,环境内自带解释器 |
| 安装包体积 | 相对较小(仅Python包) | 较大(包含完整环境) |
| 适合场景 | 单台机器、已有Python环境 | 多台机器批量部署、无Python环境 |
| 版本可控性 | 高,可精确指定每个包 | 中,以打包时的环境为准 |
| 上手难度 | 低 | 中 |
如果你的目标机器上已经装好了Python且不想动它,无脑选pip路线;如果你要装很多台,或者目标机器连Python都要重装,conda-pack一次打包到处解压的效率会高得多。
2. 版本组合先对齐:Python、CUDA、显卡驱动一个都不能错
2.1 目标机器的信息收集:三行命令搞定
动手下载任何东西之前,先在目标机器上确认三件事:Python版本、显卡型号、显卡驱动支持的CUDA版本。这三项决定了你下载哪个版本的whl。
打开命令提示符或PowerShell,逐个执行:
python --version wmic path win32_VideoController get name nvidia-smi第一条显示Python版本。Pytorch的whl文件名里带cp310、cp311之类的标识,cp310对应Python 3.10,cp311对应Python 3.11,必须严格对应,否则pip会直接拒绝安装。
第二条列出显卡型号。如果输出里看不到NVIDIA显卡,说明这台机器没有可用的N卡,那就老老实实装CPU版本。
第三条是重点。注意看输出的右上角,会有一个 "CUDA Version" 字段。很多人在这里有个误解,以为这个数字表示当前系统已经安装了CUDA,其实不是——这个数字表示当前显卡驱动最高支持到哪个CUDA版本。举个例子,如果nvidia-smi显示CUDA Version 12.4,意思是你的驱动支持12.4及以下所有版本的CUDA运行时。
为什么这个区别重要?因为Pytorch的GPU版本安装包内部是带CUDA运行时(runtime)的,不需要你另外安装完整的CUDA Toolkit。只要驱动支持的CUDA版本高于等于Pytorch要求的CUDA版本,就能正常运行。
2.2 驱动支持的CUDA版本和Pytorch要求的CUDA版本是什么关系
Pytorch官方发布的GPU版本,文件名通常带绿色标记,比如 torch-2.8.0+cu121-cp310-cp310-win_amd64.whl 里的 cu121 表示这个包是用CUDA 12.1编译的。它对显卡驱动的最低要求就是能够支持CUDA 12.1。
关键规则:驱动支持的CUDA版本 >= Pytorch要求的CUDA版本,就能用;小于则不能用。
举个例子,你的驱动支持CUDA 12.4,那么你装cu121、cu118都能跑,因为驱动是向下兼容的。但是反过来,如果驱动只支持11.8,你非要去搞一个cu121的包,装是能装上,一运行涉及GPU的操作就会报错,轻则CUDA error: no kernel image is available,重则进程直接崩溃。
所以在你下载离线包之前,必须先在目标机器上跑一次nvidia-smi,记住那个CUDA Version的数字,再决定下载哪个CUDA编译版本的Pytorch。
2.3 一个经过验证的组合:Python 3.10 + Pytorch 2.8.0 + CUDA 12.1
我在这次离线安装中使用的组合是 Python 3.10.11 + Pytorch 2.8.0 + CUDA 12.1,这也是目前很多实际项目中稳定跑过的组合。
为什么选这个组合?首先,Python 3.10是一个兼容性非常好的版本,大多数第三方库都有对应的wheel包,不会出现找不到匹配编译版本的情况。其次,Pytorch 2.8.0是较新的稳定版本,支持CUDA 12.1,而CUDA 12.1对驱动的要求是522.06及以上,目前绝大多数NVIDIA显卡驱动都满足这个条件。从性能和支持度两个角度来说,这个组合都很均衡。
对应的三个核心包版本如下:
- torch-2.8.0+cu121-cp310-cp310-win_amd64.whl
- torchvision-0.23.0+cu121-cp310-cp310-win_amd64.whl
- torchaudio-2.8.0+cu121-cp310-cp310-win_amd64.whl
torchvision和torchaudio这两个包是Pytorch生态里常用的附属库,一个管图像处理,一个管音频处理。如果你的项目用不到它们,可以只装torch,但建议顺手都装上,因为很多项目的依赖方会间接需要它们,到时候缺了又要重新拷贝一次,很麻烦。
2.4 用CPU方案兜底:无独显机器的版本选择
如果你的目标机器没有NVIDIA独显,或者驱动版本太老无法升级,那就用CPU版本。CPU版本的wheel文件没有cu121这个标识,文件名类似 torch-2.8.0-cp310-cp310-win_amd64.whl,体积比GPU版本小很多,大概只有后者的一半左右。
CPU版本不需要关心CUDA版本,也不依赖显卡驱动,装好后用torch.cuda.is_available()检查会返回False,这是正常的,你的模型会老老实实跑在CPU上。如果你的场景是简单的模型推理、小规模训练或者代码调试,CPU版本完全够用。如果目标是跑大模型训练,那CPU版本只是没办法中的办法,建议尽早解决显卡和驱动的问题。
3. 联网机器收集离线包:pip download的正确姿势
3.1 为什么不能用浏览器直接点下载
很多人的第一反应是,用浏览器打开pytorch官网或者PyPI页面,把whl文件下载下来。这种思路没有错,但有一个很关键的问题:Pytorch有一堆运行时依赖。就算你手动把torch的whl文件下载好了,装的时候pip还是会提示缺少numpy、pillow、sympy等依赖库,你还是得一个个找、一个个下载。这个过程中一旦某个包的版本选错,连锁反应就是安装失败。
正确的做法是用pip自带的下载功能,让pip帮你收集全部依赖。pip在下载时会自动解析依赖关系,把所有需要的依赖包一起拉下来。你只需要一条命令,它会把wheel文件和依赖项全部放进指定目录。
3.2 GPU版的正确下载姿势:注意官方源,不是PyPI默认源
联网机器上先确保安装了pip,然后执行下面的命令下载GPU版Pytorch(假设你选择了CUDA 12.1版本):
mkdir offline_packages pip download torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 \ --index-url https://download.pytorch.org/whl/cu121 \ -d ./offline_packages注意这里的--index-url参数,这是GPU版本离线包下载最容易踩的坑。如果你不加这个参数,默认从PyPI官方源下载,拿到的通常是CPU版本(或者不带+cu121后缀的版本),因为PyPI源上的torch默认是不带CUDA编译标识的。必须显式指定Pytorch官方的whl源地址,才能拿到带cu121标识的GPU版本。
命令执行后,offline_packages目录下会多出一批文件,除了torch、torchvision、torchaudio这三个主包,还有它们的依赖包,比如:
- numpy、pillow、sympy、networkx、jinja2、fsspec、filelock、typing-extensions
- cross-platform相关的多个whl文件
看到这些文件就说明依赖收集成功了。建议在下载完之后数一下文件数量,如果只有三五个,大概率漏了依赖;正常情况下这个目录里应该有十几个文件。
3.3 CPU版的下载方式:国产镜像源更省事
如果你的方案是CPU版,下载方式更简单,用国内镜像源就行。清华、阿里、腾讯的PyPI镜像都行,速度远比Pytorch官方源快。以清华源为例:
pip download torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 \ -i https://pypi.tuna.tsinghua.edu.cn/simple \ -d ./offline_packages这里用-i参数指定了清华PyPI镜像,下载速度通常在几MB每秒以上。无论用什么方式下载,下载完成后建议把offline_packages目录检查一遍,确认没有.tar.gz格式的源码包(如果有,说明该依赖在Windows平台没有预编译的wheel包,需要换Python版本或换源重新下载,用--only-binary=:all:参数可以强制只下载二进制包,从源头避免源码包)。
3.4 目标机器上的离线安装:--no-index 与 --find-links 的配合
把整个offline_packages目录拷贝到目标机器后,执行安装命令:
pip install --no-index --find-links=./offline_packages torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0这段命令的参数很重要,我拆开讲:
--no-index告诉pip不要访问任何远程索引(包括PyPI默认源和内网源),只从本地找包。--find-links=./offline_packages指定本地包目录的位置。
如果你的目录里同时有CPU和GPU版本的多个whl文件,npm还支持指定文件名直接安装,更精确一些:
pip install --no-index --find-links=./offline_packages torch-2.8.0+cu121-cp310-cp310-win_amd64.whl torchvision-0.23.0+cu121-cp310-cp310-win_amd64.whl torchaudio-2.8.0+cu121-cp310-cp310-win_amd64.whl提示:整个安装过程会持续几分钟,主要时间花在写入几个G的文件上,看到进度条停住不动不用慌,等它跑完即可。
4. conda-pack整环境搬家:更适合多机器部署的备选方案
4.1 conda-pack适合什么样的场景
如果你不是在一台机器上装,而是要在一批机器上重复配置,或者目标机器连Python都没有装,那pip方案就有点力不从心了。从头装Python、建虚拟环境、逐台执行pip命令,工作量大且容易出错。这种情况下,conda-pack能让你提前把整个conda环境打包成一个压缩文件,拷到任何同架构的Windows机器上解压即用,连环境变量都不用配。
另外还有一类场景也适合conda-pack:你的项目依赖了Pytorch之外的一堆库,比如onnxruntime、opencv、requests等,用pip方案你得一个个把依赖列出来,用conda-pack直接打包你自己已经在用的一套环境,一次搞定所有依赖。
4.2 在联网机器上完成打包
假设你在联网机器上已经能用conda,我们重新创建一个干净的环境:
conda create -n pytorch_offline python=3.10 -y conda activate pytorch_offline pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 --index-url https://download.pytorch.org/whl/cu121 pip install conda-pack上面三步完成后,当前pytorch_offline环境里已经包含Python 3.10、GPU版Pytorch全家桶和它们的依赖。接着用conda-pack打包:
conda pack -n pytorch_offline -o pytorch_offline.tar.gz执行之后会在当前目录生成一个压缩包。这个压缩包的大小可能会比较感人,GPU版Pytorch加依赖打包后通常有4GB以上,建议用移动硬盘或高速U盘拷贝。
4.3 目标机器上的解压与激活
目标机器不需要先装conda或Python,直接解压这个压缩包即可。假设你把它放到了D:\pytorch_offline:
tar -xzf pytorch_offline.tar.gz -C D:\pytorch_offline解压完成后,进入目录,找到Scripts\activate.bat并执行:
D:\pytorch_offline\Scripts\activate.bat这时候你的命令行前面应该会出现(pytorch_offline)前缀,说明已成功激活环境。直接用python命令进入交互式界面,import torch验证一下就能用了。
需要注意:conda-pack打包的环境是"位置敏感"的,如果打包时环境路径是C:\Users\admin\anaconda3\envs\pytorch_offline,解压到D:\pytorch_offline后路径变了,conda-pack已经在压缩包里放了一个conda-unpack.exe工具来修复路径。解压后第一次使用时执行:
conda-unpack.exe它会更新环境内的所有硬编码路径,之后各种工具才能正常工作。这一步很容易被忽略,但不做的话后面可能出现一些莫名其妙的路径错误。
4.4 两种方案的对比和我的建议
我自己的使用体验是:单机离线安装首选pip+whl,因为目标机器上已经有Python环境,管理起来也更透明;批量部署或多机器复制场景,直接上conda-pack,省时省力。
再补一个场景:如果目标机器有内网conda镜像,那连打包都不用,直接改.condarc文件指向内网channel,然后用conda在线安装,和公网体验几乎一样。这种方案适合半隔离状态的内网环境,效率最高。
5. GPU版本翻车重灾区:驱动、DLL、运行库逐个排查
5.1 torch的GPU版自带CUDA运行时,是真的吗
先说结论:是真的。从Pytorch官方whl源下载的带cu121标识的GPU版本,包内部封装了CUDA运行时(runtime)库,包括cudart、cublas、cudnn等关键动态链接库。所以你在目标机器上不需要安装完整版的CUDA Toolkit,只需要一个足够新的显卡驱动,torch运行时就能从自带库中加载所需组件。
这也解释了为什么有些人的机器上从没装过CUDA,但torch.cuda.is_available()却返回True。Pytorch为了降低用户的安装成本,把所有CUDA依赖都塞进了自己的包目录里。
不过"自带CUDA运行时"不意味着完全不需要排查问题。实际运行中,GPU版本翻车的概率远高于CPU版本,下面几个问题是我实测下来最常见的。
5.2 nvlddmkm事件ID 153:这个错误和Pytorch有没有关系
如果你在Windows事件查看器里看到无法找到来自源 nvlddmkm 的事件 ID 153 的描述,先不用慌。这个事件源是NVIDIA显卡驱动,事件ID 153通常表示显卡驱动遇到了异常或GPU暂时从系统中移除,和Pytorch本身没有直接关系,也就是说不是torch的安装问题。
但它在Pytorch使用场景中会以间接方式影响你:一旦GPU驱动挂起,训练过程中可能会出现CUDA error: an illegal memory access was encountered或者程序无响应。排查这一类问题,我建议按下面的顺序来:
- 用
nvidia-smi查看驱动是否响应,如果不输出内容,说明驱动已经挂掉,直接重启机器,然后用DDU(Display Driver Uninstaller)在安全模式下彻底卸载旧驱动,再安装最新稳定版驱动。 - 检查显卡温度。长时间满载训练导致过热会触发GPU保护机制,出现nvlddmkm错误。用MSI Afterburner或HWMonitor看温度曲线,超过85度就要考虑清灰或者降低功耗墙。
- 检查电源计划。Windows的"平衡"电源计划可能会限制PCIe总线供电,改成"高性能"电源计划,再重启试一次。
这个错误不直接对应Pytorch,但在我这次离线部署时折腾了最久,所以专门提一下。如果你在事件查看器里看到这个ID,并且Pytorch的GPU操作频繁失败,优先排查驱动和硬件。
5.3 DLL加载失败的常规解法:Microsoft Visual C++运行库
G了GPU版本后,最常见的一个报错是ImportError: DLL load failed while importing torch,或者更详细的提示找不到torch_python.dll的依赖项。
这个问题的经典原因之一是目标机器缺少Microsoft Visual C++ Redistributable运行库。torch的wheel包在Windows上编译时依赖了MSVC的运行时DLL,比如msvcp140.dll、vcruntime140.dll。这些DLL在开发机上通常都有,但很多精简版Windows或服务器系统默认没有。
解决办法很直接:在联网机器上下载vc_redist.x64.exe(微软官方Visual C++ 2015-2022 Redistributable包),拷到目标机器上双击安装,装完重启命令行,重新执行import torch。
还有一种情况也容易遇到:目标机器是Windows Server系统,缺少某些桌面版本的运行库组件。这时在安装vc_redist后仍然报DLL缺失的话,用Dependencies工具(一个绿色的DLL依赖分析工具)打开 torch 目录下的DLL文件,查看具体缺失的DLL名称,再针对性补齐。比如常见的libomp140.x86_64.dll缺失,这个文件实际是OpenMP运行时,在电脑上不太好找,网上搜一套对应版本的拷进去就行。
5.4 torch.cuda.is_available()返回False的排查次序
装完GPU版后第一件事就是验证CUDA是否可用。如果返回False,按照以下顺序排查:
- 先查驱动版本:运行
nvidia-smi,确认驱动支持的最高CUDA版本是否大于等于你装的torch要求的CUDA版本。比如你的包是cu121,驱动显示最高CUDA版本必须大于等于12.1。不满足就升级驱动,这是最常见的返回False的原因。 - 确认装的是GPU版:执行
pip show torch,看安装路径和版本号。版本号里如果没有+cu后缀,说明你从PyPI源装成了CPU版,必须重装。检查命令:python -c "import torch; print(torch.__version__)",如果输出2.8.0而不是2.8.0+cu121,那就装错了。 - 确认Python是64位:torch的GPU版本只支持64位Python,如果你装的是32位Python,想都不要想。
python -c "import platform; print(platform.architecture())"看输出是否为('64bit', 'WindowsPE')。 - 检查环境是否混用:如果你在conda环境里用pip装了torch,但启动时用的是系统Python,那导入的可能是另一个环境里的包。注意
where python看当前优先级。
6. 安装完成后的验证流程与高频报错速查
6.1 一套完整的验证步骤
离线安装完成不代表真正搞定,环境配好后的验证往往才是问题的开始。我在每次装完后固定跑一段脚本,快速确认所有功能正常:
import torch print("torch版本:", torch.__version__) print("CUDA是否可用:", torch.cuda.is_available()) if torch.cuda.is_available(): print("GPU型号:", torch.cuda.get_device_name(0)) print("显存大小:", torch.cuda.get_device_properties(0).total_memory / 1024**3, "GB") # 跑一个简单的张量操作,确认GPU计算与CPU之间的数据迁移正常 x = torch.rand(3, 3).cuda() y = torch.mm(x, x) print("GPU矩阵运算结果:\n", y)这段脚本如果全部正常输出,说明torch的CPU计算和GPU计算都可用。如果你的项目用到torchvision或torchaudio,再加一行import torchvision; print(torchvision.__version__)一起验证。
另外建议用torch.utils.collect_env生成一份环境诊断报告,它会把Python版本、Pytorch版本、CUDA可用性、显卡驱动、cuDNN版本这些信息一次性打印出来,方便排错。执行:
python -m torch.utils.collect_env在离线环境下这个工具完全可用,输出信息非常详细。
6.2 高频报错速查表
把我这次安装过程和以往帮别人排错时遇到的高频问题整理成一张速查表:
| 报错现象 | 可能原因 | 解决方向 |
|---|---|---|
No matching distribution found for torch | pip在指定目录里找不到匹配的whl | 确认Python版本和wheel文件名是否匹配;确认为GPU源指定了--index-url |
ERROR: torch-xxx.whl is not a supported wheel on this platform | 系统架构或Python版本与whl不匹配 | 确认是64位系统、64位Python,cp310的包只能装到3.10 |
ImportError: DLL load failed while importing torch | 缺少VC运行库或某个依赖DLL | 安装vc_redist.x64.exe,用Dependencies工具查缺失DLL |
torch.cuda.is_available()返回False | 驱动版本不够 / 装成了CPU版 | 先跑nvidia-smi,再确认torch版本号带cu121后缀 |
训练时报错CUDA out of memory | 显存不够 | 调小batch size,或用torch.cuda.empty_cache()手动释放缓存 |
运行时报CUDA error: no kernel image is available | 驱动版本低于torch要求的CUDA版本 | 升级显卡驱动,或换用更低CUDA版本的torch |
Illegal instruction异常 | CPU指令集过老 | 换用CPU版本或更新CPU平台 |
表格里没有覆盖到其他问题的话,可以再用python -m torch.utils.collect_env把诊断信息贴出来,按照输出里的提示一步步排查。
我在实际踩过几次坑之后学到的最大教训是:离线安装和中转机上的版本一定要完全一致,Python版本、系统架构、CUDA版本三者任何一个对不上,装在目标机器上就会像拼图缺了一块,怎么都拼不上。宁可最开始多花几分钟把环境信息核对清楚,也不要装到一半甚至装完后才发现问题。如果你也正被Windows下的Pytorch离线安装卡住,按上面这套流程走下来,基本能省下大半天的折腾时间。