☰
Python 3.6下torch 1.6.0与Pillow 6.2.2版本兼容及环境搭建指南
2026/10/15 16:33:45 网站建设 项目流程

简介:面向在英伟达 Jetson TX1 等 ARM 平台部署 PyTorch 的用户,这份资源整理了安装 torch v1.9.0、torchvision v0.10.0 时适配的 Pillow 6.2.2 包及完整依赖文件。作者基于 JetPack 4.6.2、Ubuntu 18.04 环境完成验证,专门解决了因网络问题与版本不匹配导致的安装失败,适合遇到相似版本兼容难题的开发者直接下载使用。压缩包共 1079 个文件,约 36.06MB,内部包含 Python 源码、C 扩展、动态库、配置脚本及大量图像测试样本,文件类型覆盖 py、c、h、sh、png、tiff、jpg 等,既可作为 Pillow 运行环境组件,也能用于图像处理功能验证与源码阅读。目前已有 526 人学习下载,对在嵌入式平台搭建深度学习环境、排查依赖版本问题的开发者具有直接参考价值。

1. 老项目重建环境时,翻车十次有九次在 Pillow:先把版本组合焊死

在 Python 3.6 环境里装 torch、torchvision,再配上对应的 Pillow 6.2.2,表面看只是几条 pip 命令的事。实际动手复现过老项目的人都知道,真正的翻车点往往不在 torch 本身,而在 Pillow 的版本漂移:pip 一解析依赖,Pillow 就被悄悄升到 9.x,老代码里那些图像处理逻辑开始报错,或者更隐蔽地,图像尺寸、通道顺序全变了但没有任何提示。这篇文章把 python3.6 + torch 1.6.0 + torchvision 0.7.0 + Pillow 6.2.2 这个组合从头拆到尾,覆盖安装顺序、参数选择、验证链路和五个高频踩坑。新手照抄能装通,熟手也能直接拿这份环境清单去对齐旧项目。

2. 版本兼容矩阵:为什么是 torch 1.6.0 + torchvision 0.7.0 + Pillow 6.2.2

先说结论:这套组合不是某个人的偏好,而是 Python 3.6 这个解释器版本在 PyTorch 生态里能拿到的最后一组稳定 wheel。理解为什么是这三个版本号,后面装起来才不会在报错面前一头雾水。

2.1 torch 1.6.0 是 Python 3.6 生态里最容易装到通用 wheel 的版本

Python 3.6 的生命周期在 2021 年底就正式结束了,之后发布的 PyTorch 版本不再为 cp36 提供预编译 wheel。这意味着你在 Python 3.6 下想装 torch,可选的版本其实被限定在 1.8.0 之前的几代。1.8.0 虽然名义上还支持 Python 3.6,但从它开始官方 wheel 的系统底限要求明显抬高,很多老服务器、老容器根本进不了安装这一步。

在 1.4.0、1.5.0 和 1.6.0 这一排候选里,我一般直接选 1.6.0。理由有三条:一是 1.6.0 的 PyPI wheel 是 manylinux1 标准,对旧系统的 glibc 要求低,几乎只要 Linux x86_64 就能直接装上;二是 1.6.0 对应的 C++ ABI 稳定,和 torchvision 0.7.0 的扩展包咬合得紧;三是社区里大量旧项目都是用 1.6.0 训练的,加载旧权重时不会有算子层面的兼容问题。如果你选 1.5.0 也不是不行,但它搭配的 torchvision 0.6.0 有些 transforms 接口缺参数,后面要补兼容层,折腾。

2.2 torchvision 版本必须严格跟 torch 配对,错配从 import 就开始爆

torchvision 不是一个独立工具包,它的 C++ 扩展是从 PyTorch 源码树里单独检出版本后编译的,所以它只认对应的小版本。torch 1.6.0 只能配 torchvision 0.7.0,torch 1.5.0 只能配 0.6.0,torch 1.7.0 配 0.8.1,跳一个数字都可能出问题。

这个配对关系在官方文档里有明确表格,我整理成常用版本对照:

torchtorchvision
1.5.00.6.0
1.6.00.7.0
1.7.00.8.1

错配时最典型的报错是 import torchvision 直接抛ModuleNotFoundError: No module named 'torchvision._C',或者更隐蔽的undefined symbol。这种错不是你重新装一遍 torch 就能解决的,必须两边版本一起锁。我在实际项目里见过有人把 torch 升到 1.7.0 而 torchvision 还留在 0.7.0,结果所有加载图片的 pipeline 全部崩掉,最后花了半天排查才发现是版本矩阵没对齐。所以安装之前先把这张表写在 requirements 里,别靠记忆。

2.3 Pillow 6.2.2 的定位不是“旧版”,而是老项目实际锁定的唯一版本

Pillow 6.2.2 发布于 2019 年底,正好和 PyTorch 1.5、1.6 处于同一生态时期。那个年代训练出来的检测、分割、OCR 项目,requirements.txt 里写的几乎都是Pillow==6.2.2。为什么集体锁这个版本?因为 Pillow 7.0 开始对 resize 的滤波行为、PNG 16 位灰度图的读取方式都做了调整,而这些调整会直接影响 torchvision 的 transforms 输出。

你可能会想,Pillow 新版本修复了 bug,应该更稳才对。问题在于老模型训练时的图像预处理链路是基于旧版本行为的,比如某张图在 6.2.2 下读出来是 mode "RGB",在 9.1.0 下可能还是 "RGB",但里面某些像素的记录方式变了,最后送进模型的数据分布就和训练时不一致。这种差异不在 torch 层报错,而是静默地改变推理结果,属于最讨厌的那种玄学 bug。所以 pytorch 和 Pillow 的版本不是独立的,torch 负责网络,Pillow 负责图片进入网络之前的最后一公里,这一公里必须和训练时完全一致。

3. 安装三连:venv、torch 1.6.0、Pillow 6.2.2 的可复现步骤

安装顺序有一个硬性约束:先装 torch 和 torchvision,最后再降级 Pillow 到 6.2.2。顺序反了,pip 会为了满足 torchvision 的依赖约束把 Pillow 再升回去,你等于白忙一场。下面按我的实际操作习惯完整走一遍。

3.1 先建一个干净的 Python 3.6 虚拟环境

不要直接在系统 Python 里装这套东西。系统环境里可能已经有其他项目锁了不同版本的 Pillow、numpy,一装必冲突。我习惯用 venv 而不是 conda,因为 venv 更轻,且标准库自带,不引入额外运行时。

# 确认当前机器可用的 python3.6 which python3.6 python3.6 --version # 创建虚拟环境,目录名用项目名 python3.6 -m venv /opt/venvs/py36_old_project source /opt/venvs/py36_old_project/bin/activate # 验证当前解释器确实是 3.6 python --version

第一步先which python3.6是为了避免系统里同时存在多个 Python 版本时,直接用python3却指向 3.8 的问题。venv 创建成功后,所有 python 命令都要在激活状态下执行。如果你在创建时报ensurepip is not available,说明系统缺少 python3.6-venv 的辅助包,需要先安装系统包,这在精简版 Linux 上很常见。

3.2 锁版本装 torch 与 torchvision

虚拟环境建好后,第一件事是升级 pip。Python 3.6 自带的 pip 版本通常很老,解析 torch 这种带大量元数据和 CUDA 依赖的包时效率极低,甚至会错误地判定找不到可用版本。我一般把它升到 20.2.4,这个版本是 Python 3.6 还能正常使用的比较靠后的 pip 版本。

python -m pip install --upgrade pip==20.2.4 # 安装锁定的 torch 和 torchvision,一条命令装齐 python -m pip install torch==1.6.0 torchvision==0.7.0

--upgrade pip==20.2.4中的==起到固守版本的作用,因为最新的 pip 23.x 已经不再支持 Python 3.6,硬升上去反而跑不了。安装 torch 和 torchvision 时,如果你是国内网络,建议在命令末尾追加-i https://pypi.tuna.tsinghua.edu.cn/simple这类镜像源来加速下载,否则 torch 的 wheel 体积有上百兆,很容易下到一半超时。这步安装的 torch 1.6.0 Linux wheel 自带 CUDA 10.2 运行时,机器没显卡也能装,跑起来自动走 CPU,不影响后续验证逻辑。

3.3 最后降级 Pillow 到 6.2.2,顺序不能反

这时候如果直接查 Pillow 版本,大概率已经是 9.1.0 了,因为 torchvision 0.7.0 的依赖声明是Pillow>=4.1.1,pip 解析时会自动去选当前 Python 3.6 下可用的最高版本。这正是需要手动降级的原因。

# 强制安装 Pillow 6.2.2,并禁止解析依赖 python -m pip install Pillow==6.2.2 --no-deps

这里的--no-deps很关键。Pillow 本身没有第三方运行依赖,所以跳过依赖解析完全安全,同时能阻止 pip 顺手把其他包升级。很多人在这一步会踩坑:不加--no-deps时,pip 看到当前环境里有 torchvision,会重新检查 torchvision 的依赖约束,发现 Pillow 6.2.2 不“够新”,然后自动升回去。加了--no-deps后,pip 只管安装指定的 Pillow,不碰其他包,这才是唯一可靠的锁版本方式。

安装完看一眼版本矩阵:

python -c "import torch, torchvision, PIL; print(torch.__version__, torchvision.__version__, PIL.__version__)"

结果应该是1.6.0 0.7.0 6.2.2三行对齐。到这一步,环境就搭起来了。

提示:如果系统网络环境必须走代理,pip 下载时加上--proxy http://代理地址:端口,不要用export https_proxy,因为 pip 对 https 代理变量的兼容性在不同版本里有差异。

4. 验证链路:从三个版本号到 transform 输出的四步检查

很多人装完环境只验一下版本号就开跑模型,这是不够的。版本号对不代表整套图像链路真的通了,尤其是 Pillow 这种负责底层图像解码的库,它的升级往往不表现在 import 错误上,而是表现在图片模式的细微变化上。所以我每次装完都会跑一遍完整验证脚本,四步走完心里才有底。

4.1 用一条命令打出版本矩阵

第一步还是验版本,但不是只验一个包,而是把 Python、torch、torchvision、Pillow 四个版本一次性打出来。

python -c "import sys, torch, torchvision, PIL; print('python', sys.version.split()[0]); print('torch', torch.__version__); print('torchvision', torchvision.__version__); print('Pillow', PIL.__version__)"

看输出时注意三点:Python 必须是 3.6.x,torch 和 torchvision 必须严格对上第 2 章那张表,Pillow 必须精确到 6.2.2。如果 Pillow 显示 6.2.2+nsp 这种带本地版本后缀的,也可以接受,只要主版本号对齐就行。如果 torchvision 显示 0.7.0+cu102 之类的后缀,说明带 CUDA 版本标签,这没问题。

4.2 走一遍读图、缩放、转 Tensor 的 smoke test

版本号只是必要条件,真正能说明环境可用的,是一张假图能不能正常从 PIL Image 变成 torch Tensor。我平时用的验证脚本固定放在项目根目录,叫 check_env.py,内容如下:

import numpy as np import torch import torchvision from PIL import Image # 用 numpy 生成一张 4x6 的 RGB 小图,手工给红色通道赋值 arr = np.zeros((4, 6, 3), dtype=np.uint8) arr[..., 0] = 255 img = Image.fromarray(arr, mode="RGB") print("PIL mode:", img.mode, "size:", img.size) # 走一遍训练时常用的预处理链路 transforms = torchvision.transforms.Compose([ torchvision.transforms.Resize((8, 8)), torchvision.transforms.ToTensor(), torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) tensor = transforms(img) print("tensor shape:", tuple(tensor.shape), "dtype:", tensor.dtype) print("tensor min/max:", tensor.min().item(), tensor.max().item()) # 关键断言:shape 应为 (C=3, H=8, W=8),dtype 必须是 float32 assert tuple(tensor.shape) == (3, 8, 8), "shape mismatch" assert tensor.dtype == torch.float32, "dtype mismatch" assert tensor.max().item() <= 1.0, "normalize range error" print("smoke test passed")

这段脚本里有两个细节容易忽略。Image.fromarray(arr, mode="RGB")显式指定 mode 是好事,避免 Pillow 在少部分机器上把 3D numpy 数组识别成 mode "RGBA" 的边界情况。Normalize 这步的作用是模拟真实训练流程,如果前面 Resize 或 ToTensor 出了问题,这里会因为数值范围不对直接报警。三个断言分别锁通道数、数据类型和数值范围,任何一个不过都能帮助定位是哪一层出了问题。

4.3 断言失败怎么定位:先查 Pillow 再查 torchvision

如果跑完脚本报断言错误,不要急着重装全套环境,按顺序排查三件事。先确认 Pillow 版本是不是 6.2.2,这是反馈最快的一步,很多情况下就是之前某个步骤把 Pillow 又升回去了。再看Resize的输出尺寸,如果 size 变成(8, 6)这种宽高不等的结果,说明 transforms 里的尺寸参数写错了,和 Pillow 无关。最后查tensor.dtype,如果出来的是 float64,说明读图环节把 CUDA 内容转换成了 double 精度,问题在 torch 后端而不是 Pillow。

这三个判断顺序对应的是依赖链的上下游:Pillow 在最底层,torchvision 在中间,torch 在最上面。从下往上查,基本能在十分钟内锁定问题,而不是把整个环境推倒重来。这也是为什么我坚持用一个固定脚本做回归验证,每次环境有任何变动,跑一遍就知道有没有被破坏。

5. 避坑手册:五个真实翻车现场与修复方案

这套环境安装虽然步骤不多,但每一步都有对应的坑。我把这几年在 Python 3.6 环境里装 torch 和 Pillow 时遇到的高频问题记录下来,每条按现象、原因、解决的顺序写,方便你直接对照着排查。

5.1 翻车现场一:pip 把 Pillow 悄悄升到 9.1.0

现象:按正确顺序装完 torch 和 torchvision 后,执行python -c "import PIL; print(PIL.__version__)"发现 Pillow 变成了 9.1.0,而不是想要的 6.2.2。

原因:torchvision 0.7.0 的安装依赖声明是Pillow>=4.1.1,pip 在解析依赖时会自动在 Python 3.6 可用的范围里挑最高版本,而 PyPI 上 Python 3.6 能装的最高 Pillow 是 9.1.0。

解决:安装命令必须加--no-deps参数,python -m pip install Pillow==6.2.2 --no-deps。安装完成后立刻验证版本号,不要拖到跑模型时才发现。如果发现已经被升上去了,先卸载再装,pip uninstall Pillow -y后重新执行上面的命令。

5.2 翻车现场二:python3.6 的 pip 报找不到 torch==1.6.0

现象:执行pip install torch==1.6.0 torchvision==0.7.0时报错No matching distribution found for torch==1.6.0,但明明 PyPI 上存在这个版本。

原因:虚拟环境自带的 pip 版本太老,老到无法解析 torch 1.6.0 的 wheel 元数据,或者把很多兼容平台标记过滤掉了。另一种常见原因是当前机器没有走索引源,pip 默认用的是配置里某个不完整的内部源。

解决:先把 pip 升级到 20.2.4 再装。如果升级后还是报同样错误,检查pip config list看 index-url 是否指向了可用源,必要时在命令里显式指定镜像源地址。这一步能在绝大多数场景下解决问题。

5.3 翻车现场三:pip 和 python 不是同一个解释器

现象:进入虚拟环境后,pip show torch能看到已安装记录,但在 Python 里import torch却报ModuleNotFoundError。

原因:系统里存在多个 Python 版本,而当前 shell 的 PATH 里 pip 指向的是另一个解释器的入口,比如裸pip属于 Python 3.8,装进去的包只进了 3.8 的 site-packages,当前的 Python 3.6 完全看不到。

解决:强制用当前解释器对应的 pip,即python -m pip,而不是裸pip。养成习惯:在虚拟环境里所有安装、卸载、查看操作一律写成python -m pip,这样 pip 永远和当前 python 绑定,不会串环境。

5.4 翻车现场四:Pillow 6.2.2 源码编译失败

现象:安装 Pillow==6.2.2 时不是下载 wheel,而是自动下载源码包开始编译,随后报错zlib not available或者error: command 'gcc' failed。

原因:pip 没有找到匹配当前 Python 和系统的预编译 wheel,退回源码编译。Python 3.6 在 Linux x86_64 上其实有 manylinux wheel,问题通常出在 pip 版本太老无法识别,或者用户在命令里加了--no-binary :all:。

解决:升级 pip 到 20.2.4 以上,然后去掉任何--no-binary参数。如果仍然走源码编译,检查系统是否有 zlib 开发头文件,Debian/Ubuntu 系执行apt-get install zlib1g-dev libjpeg-dev后重装。装完后再确认 Pillow 里有_imaging这个 C 扩展能加载。

5.5 翻车现场五:requirements.txt 里不锁 Pillow 的后果

现象:环境重新搭建后,代码能跑,但同一张图片推理结果和以前不一样,比如检测框偏移几个像素,分割 mask 边缘出现变化。查看 Pillow 版本,发现从 6.2.2 漂到了 8.4.0。

原因:requirements.txt 里写的是Pillow>=6.2.2而不是Pillow==6.2.2,pip 重新解析依赖时会取当前 Python 环境允许的最新版本。Pillow 8.x 在 resize 和图像模式处理逻辑上和 6.x 有差异,推理结果随之漂移。

解决:把 requirements.txt 里所有图像相关依赖都改成精确版本号,Pillow==6.2.2、numpy==1.19.5、torch==1.6.0、torchvision==0.7.0。精确锁版本是这套环境能持续复现的前提,不能偷懒。

6. 离线部署技巧:把这套环境原样搬进生产机

生产机经常是内网环境,不能直接访问 PyPI。这时候要做的不是在一台机器上现装,而是把整套依赖包下载好,原样搬进去。步骤如下:在能联网的机器上,用 pip download 拉全部 wheel 包,然后拷贝到内网机器用本地索引安装。这样能保证生产环境和验证环境用的是同一个版本组合。

6.1 用 pip download 拉全 wheel 包

先准备一份精确锁版本的 requirements.txt,我会把 numpy 也锁到 1.19.5,因为这是 Python 3.6 能装到二进制 wheel 的最后一批 numpy 版本。然后执行下载命令:

python3.6 -m pip download -r requirements.txt -d /opt/wheelhouse/ --no-deps

-d指定输出目录,--no-deps表示只下载 requirements.txt 里显式列出的包,不递归拉其他依赖,避免把不相关版本夹带进来。如果出现网络超时,改用国内镜像源重试。下载完成后检查一下目录里有几个 wheel 文件,确认 torch 的 wheel 文件大小在百兆级别才算完整。

6.2 用固定入口脚本做一致性校验

把 wheelhouse 目录传到生产机后,创建同样的虚拟环境,然后离线安装:

python3.6 -m venv /opt/venvs/py36_old_project source /opt/venvs/py36_old_project/bin/activate python -m pip install --no-index --find-links=/opt/wheelhouse/ -r requirements.txt

--no-index告诉 pip 完全不要访问 PyPI,--find-links指定到本地目录查找 wheel。装完不要急着跑业务代码,先执行第 4 章那个 check_env.py,确认版本矩阵和 smoke test 全部通过。我在一次生产部署里就因为跳过这步,把 Pillow 装到了 9.1.0 还毫不知情,直到线上推理结果异常才回头排查。从那以后,每次搬老项目环境,第一件事就是锁 Pillow,第二件事就是跑一遍 check_env.py,再开始碰模型代码。希望这套组合清单和排查流程能帮到你,省下半天踩坑时间。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询