
PyTorch 和 TensorFlow选一个还是两个都学我的看法是前期别急着做排除法两个都装上、都跑一遍反而能更快建立对深度学习框架的整体认知。这篇文章面向刚入门深度学习、想在本地环境把 PyTorch 和 TensorFlow 都跑通的读者。内容覆盖两套框架的安装、环境搭建、GPU 验证、首个分类任务实战以及两个框架并存时的切换技巧和常见排查思路。最值得关注的点不是某个安装命令本身而是两套框架的设计逻辑差异——动态图与静态图分别适合什么阶段学术研究和工业部署各自偏爱哪一套。搞懂这些之后你再看新项目、读论文源码、接部署任务都会比死记 API 舒服得多。先说结论如果目标是快速验证想法、跑论文代码、做研究实验PyTorch 更顺手如果团队已经沉淀了 TensorFlow 的 Serving 和部署链路或者要面对移动端、嵌入式设备那 TensorFlow 的成熟工具链会更有优势。但这两个结论不是劝你只选一个而是告诉你两条路都值得走一遍而且完全可以同时走。1. 两个框架不是二选一而是两条技术路线1.1 动态图与静态图核心设计差异PyTorch 默认采用动态计算图模型在每次前向传播时都会实时构建计算图。这意味着你可以直接用普通 Python 的条件判断、for 循环去控制网络结构调试时也能打断点查看中间张量。对研究和实验阶段来说这种灵活性非常关键。我最初从 TensorFlow 1.x 转到 PyTorch 时最明显的感觉就是写模型像写普通 Python 代码不再需要先定义占位符和 Session出错的位置一眼就能看到。TensorFlow 从 2.x 开始也默认开启 Eager Execution动态执行模式但它的底层设计仍然保留了静态图、SavedModel、GraphDef 这一整套序列化体系。换句话说TensorFlow 给你的是“动态调试 静态部署”的组合方案研究阶段用 Keras 高层 API 快速建模部署阶段再通过tf.saved_model.save导出成固化模型交给 Serving、Lite、JS 等工具链去跑。这个差异会影响你写代码的方式也会影响你排查问题的思路。PyTorch 的报错往往直接指向 Python 栈TensorFlow 的报错则可能出现在底层图执行阶段信息量更大但定位起来也更绕。1.2 学术研究与工业部署各自的主场看论文复现代码时你会发现大量项目默认提供 PyTorch 版本。Transformer、Diffusion、LLM 微调这些热门方向PyTorch 生态的更新速度通常更快。原因也不复杂研究者需要随时改动模型结构动态图 Python 原生控制流最省事社区里互相传代码的门槛也低。TensorFlow 的强项在工业落地。从 TF Serving 到 TensorFlow Lite再到 TensorFlow.js它的部署链路是完整的。如果你的产品需要长时间稳定运行、需要标准化的模型版本管理、需要跑到手机或嵌入式设备上TensorFlow 这套工具链依然很有竞争力。另外很多老项目、企业内部项目还是 TensorFlow 写的你会读、能改、能迁移都是实打实的能力。所以我的建议是入门阶段不要把两个框架放在对立面。PyTorch 适合帮你“想明白”TensorFlow 适合帮你“送上线”。两条腿走路比单押一边稳得多。2. 动手之前先确认环境显卡、CUDA 和 Conda2.1 先看显卡再定安装方案装框架之前第一件事不是复制安装命令而是确认机器的硬件和驱动情况。Windows 和 Linux 上最简单的方式是打开终端执行nvidia-smi重点看两行信息显卡型号以及右上角的 CUDA Version。这个版本号表示当前驱动支持的最高 CUDA 版本不是你系统里已经装好的 CUDA 工具包版本。PyTorch 和 TensorFlow 安装时会自带运行时所需的 CUDA 库多数情况下不需要你单独去装完整版 CUDA Toolkit但驱动版本必须够新否则底层库加载时会报错。如果你没有 NVIDIA 显卡或者用的是 Mac、纯 CPU 服务器也不用放弃。PyTorch 和 TensorFlow 都有 CPU 版本跑 MNIST、文本分类这类入门任务完全够用只是训练速度会慢很多。学习阶段先把流程跑通后面再考虑 GPU。2.2 用 Conda 建独立环境避免依赖互相打架PyTorch 和 TensorFlow 对 Python 版本、CUDA 运行时、第三方库的要求并不完全一致直接装在同一个环境里很容易出现依赖冲突。最省心的做法是装 Anaconda 或 Miniconda然后给每个框架建独立虚拟环境。conda create -n pytorch_env python3.9 -y conda create -n tf_env python3.9 -y这里选择 Python 3.9 是比较稳的折中方案主流版本的 PyTorch 和 TensorFlow 基本都支持。如果你的机器已经装了更高版本的 Python也可以先查一下目标框架官方文档里的支持列表再决定具体版本。为什么强调用虚拟环境因为我在实际开发中见过太多“昨天还能跑今天 import 就报错”的情况最后排查下来都是某个包被升级了或者两个项目共用了同一个 site-packages。虚拟环境隔离的不只是 Python 版本还有一堆传递依赖。前期多花一分钟建环境后面能省一晚上的排查时间。2.3 CPU 版和 GPU 版怎么选CPU 版安装简单、体积小、兼容性好适合学习语法、跑小数据集。GPU 版训练速度快但安装时要额外确认显卡驱动、CUDA 版本和框架版本的匹配关系。判断标准很简单如果你只是想体验框架的写法CPU 版够了如果你的模型稍大、数据稍多或者想真实感受训练流程那就优先 GPU 版。GPU 版安装失败的概率确实更高但这不代表你的操作有问题多数情况下是版本匹配问题。后面我会专门讲排查顺序。3. PyTorch 安装与首个实战3.1 安装步骤从 pip 到验证PyTorch 官方提供了一套按 CUDA 版本区分的安装命令。安装前先激活环境conda activate pytorch_env然后去 PyTorch 官网的 Get Started 页面选择系统、包管理器和 CUDA 版本复制对应的命令即可。常见形式是pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118这段是示例命令实际安装时以你选择的 CUDA 版本为准。如果你不打算用 GPU直接执行下面这条更简单pip install torch torchvision torchaudio这里有一个容易被忽略的点PyTorch 的 CPU 版和 GPU 版都叫 torch区别在于安装源不同。如果你之前装过 CPU 版后来想换 GPU 版最好先卸载干净再装否则可能出现torch.cuda.is_available()一直返回 False 的情况。3.2 验证 CUDA 是否真的可用安装完成后打开 Python 交互环境或写一个临时脚本执行import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU only)如果torch.cuda.is_available()返回 True说明 PyTorch 能正常调用 GPU可以进入下一步。如果返回 False先不要急着重装按下面顺序检查确认安装的是 GPU 版本而不是 CPU 版本。确认 nvidia-smi 能正常显示显卡信息。确认显卡驱动版本够新必要时去显卡官网更新驱动。确认你选的安装源 CUDA 版本和驱动支持的 CUDA 版本不矛盾。大多数情况下第 1 条和第 3 条就能解决 80% 的问题。3.3 用 MNIST 跑通第一个训练流程环境没问题之后我建议用 MNIST 手写数字分类作为第一个实战项目。这个数据集小、任务清晰、训练速度快非常适合验证整个流程。下面是一个最小可运行的 PyTorch 训练脚本import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_loader DataLoader( datasets.MNIST(./data, trainTrue, downloadTrue, transformtransform), batch_size64, shuffleTrue ) class Net(nn.Module): def __init__(self): super().__init__() self.fc nn.Sequential( nn.Flatten(), nn.Linear(28 * 28, 128), nn.ReLU(), nn.Linear(128, 10) ) def forward(self, x): return self.fc(x) model Net() loss_fn nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lr0.001) for epoch in range(3): for x, y in train_loader: optimizer.zero_grad() out model(x) loss loss_fn(out, y) loss.backward() optimizer.step() print(fepoch {epoch 1}, loss: {loss.item():.4f})这个脚本有几个值得注意的点。nn.Sequential只是把层堆起来方便示例展示真实项目里你经常会自定义forward逻辑这就体现出 PyTorch 动态图的优势。optimizer.zero_grad()必须放在每次反向传播之前否则梯度会在多次迭代中累积导致训练结果异常。loss.item()的作用是把张量转成 Python 数字方便打印同时避免梯度图上的无关引用。跑通这个脚本后你可以试着改两个参数一是把batch_size从 64 改成 128观察训练速度和 loss 变化二是把nn.Linear的隐藏层维度从 128 改成 256感受模型容量对收敛过程的影响。这种“改一个参数看一个结果”的实验方式比一口气读完整个框架文档高效得多。4. TensorFlow 安装与首个实战4.1 安装步骤TensorFlow 2.x 的简化逻辑TensorFlow 从 2.x 开始把 API 大幅简化Keras 被整合为官方推荐的高层接口。安装也简单了很多GPU 和 CPU 版本不再分成两个包名直接安装 tensorflow 即可conda activate tf_env pip install tensorflow这套命令在绝大多数普通环境里都能直接安装成功如果机器有可用的 NVIDIA GPU 且驱动满足要求TensorFlow 会自动启用 GPU 加速。如果你看到 TensorFlow 2.18 这类比较新的版本号不用着急安装后先确认 Python 版本在支持列表里就行。新版 TensorFlow 对 Python 版本的要求比较严格Python 版本太新可能装不上太老又可能缺少依赖所以环境创建时选 Python 3.9 或 3.10 是比较稳妥的。4.2 验证 GPU 是否被识别安装完成后执行import tensorflow as tf print(tf.__version__) print(tf.config.list_physical_devices(GPU))如果输出里包含 GPU 设备信息说明 TensorFlow 已经识别到显卡。如果只显示空列表说明 TensorFlow 运行在 CPU 模式。这里有一个容易误解的地方TensorFlow 安装包本身的体积很大因为它在底层集成了大量 CUDA 相关库。装完之后磁盘占用好几个 GB 是正常现象不要以为出了问题。另外TensorFlow 的 GPU 支持对驱动版本有要求如果list_physical_devices(GPU)返回空先检查驱动版本再检查安装日志里是否有 CUDA 库加载失败的提示。4.3 用 Keras 快速完成同一个分类任务同一个 MNIST 任务用 TensorFlow 的 Keras 接口写起来会非常紧凑import tensorflow as tf (x_train, y_train), (x_test, y_test) tf.keras.datasets.mnist.load_data() x_train x_train.astype(float32) / 255.0 x_test x_test.astype(float32) / 255.0 model tf.keras.Sequential([ tf.keras.layers.Flatten(input_shape(28, 28)), tf.keras.layers.Dense(128, activationrelu), tf.keras.layers.Dense(10, activationsoftmax) ]) model.compile( optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy] ) model.fit(x_train, y_train, epochs3, batch_size64, validation_data(x_test, y_test))如果你手写过 PyTorch 版本再看这段代码会明显感觉到差异。Keras 把训练循环封装进了model.fit你不需要手动处理zero_grad、backward、step这些步骤适合快速验证想法。但封装也意味着可控性下降当你想在训练过程中加入自定义逻辑比如梯度裁剪、分层学习率、自定义回调时就需要去理解 Keras 的回调机制和自定义训练循环。对比两个实现你会发现PyTorch 把控制权交给你TensorFlow/Keras 把训练流程标准化。没有好坏之分只看你当前的场景需要什么。5. 两个框架并存环境切换与项目选型5.1 环境切换的两个实用技巧既然两个环境都建好了平时使用时的核心就是切换干净。我一般会这样做# 切到 PyTorch 环境 conda activate pytorch_env python train_pytorch.py # 切到 TensorFlow 环境 conda activate tf_env python train_tf.py只要命令在对应环境里执行依赖就不会混。需要注意两个容易踩的坑第一Jupyter Notebook 或 VS Code 这类编辑器在启动时一定要确认当前解释器是哪个环境的 Python否则会出现“明明装了 torch但 import 报错”的情况。第二不要在同一个 Python 进程里同时 import torch 和 tensorflow。虽然大部分时候不会立刻崩但两个框架底层可能使用不同的 CUDA 运行时版本混用容易触发奇怪的段错误或显存分配异常。如果确实需要同时用建议拆成两个独立进程通过文件、数据库或消息队列做数据中转。5.2 项目选型什么时候用谁我给出的判断标准很简单复现论文、做实验、快速验证 idea优先 PyTorch。已有项目是 TensorFlow 维护的优先沿用 TensorFlow不要为了“用新的”而重写。需要服务化部署、移动端/嵌入式部署TensorFlow 的 Serving、Lite 工具链更成熟。团队里大多数人都熟悉哪个就用哪个。团队协作的成本往往比框架本身的技术差异大得多。如果你在 Jetson 这类嵌入式设备上开发比如 JetPack 6.x 系统不能直接照搬 PC 的安装命令。ARM 架构和 JetPack 版本对 PyTorch 有严格的版本对应关系需要先查清设备支持哪个版本的 PyTorch再按官方指引安装否则很容易遇到编译失败或无法加载。5.3 从 PyTorch 切到 TensorFlow 的常见坑两个框架的 API 命名和数据处理方式差异不小切换时最常遇到三类问题。第一Dataset 接口不通用。PyTorch 的DataLoader、Dataset和 TensorFlow 的tf.data.Dataset完全两套体系写数据处理代码时不能只复制前一半。第二模型保存方式不同。PyTorch 常用torch.save保存状态字典而 TensorFlow 2.x 推荐使用SavedModel格式或 Keras 的.h5。如果模型要在两个框架之间迁移不能直接读文件只能重新训练或者用中间格式转换。第三版本更新带来的行为变化需要注意。比如较新版本的 PyTorch 里torch.load对weights_only参数的默认值做了调整如果你加载的是别人很久之前保存的模型文件可能会遇到警告甚至加载失败。解决办法是加载时明确指定weights_only的值同时确认模型文件的来源是可信的不要随意加载不明来源的权重文件。这类问题在社区里很常见遇到时先查一下当前版本的 release notes很多时候不是你的代码写错而是默认行为变了。6. 安装失败和训练异常的排查清单6.1 安装失败先看这三层不管是 PyTorch 还是 TensorFlow安装失败时我建议从下往上排查。第一层是网络和下载源。pip 下载超时、安装到一半中断多半是网络波动。国内用户可以把 pip 源换成镜像源或者直接看安装命令里的下载地址是否能访问。这个问题和框架本身无关但最容易让人误判。第二层是 Python 版本和 pip 版本。pip 版本太旧可能导致无法解析某些 wheel 包Python 版本不在框架支持列表里则可能找不到匹配的安装包。建议先执行python --version和pip --version确认基础环境。第三层是系统依赖。Linux 上常见的是缺少某些系统库Windows 上常见的是缺少 Visual C 运行库。这类错误信息通常比较明确照着提示装即可。一个好消息是绝大多数安装问题在你换一个干净的虚拟环境后都会消失。所以我一直强调先建环境、再安装这是一条成本极低的容错路径。6.2 训练时报错的定位顺序训练脚本报错时我的排查顺序是这样的先看完整报错栈不要只看最后一行。PyTorch 报错栈会指向具体代码行TensorFlow 有时会把底层 C 的信息混进来但最初的 Error 类型往往已经说明了问题。再确认输入形状。Linear层的输入维度和数据形状不匹配是新手最常见的错误之一。再看损失函数和标签的类型。分类任务里标签是整数还是独热编码决定了你该用哪种损失函数。然后看显存和内存。训练中途突然崩溃、进程被杀通常不是代码逻辑问题而是显存或内存耗尽。把batch_size调小或者改用梯度累积往往比优化代码更快见效。最后考虑环境问题。确认当前进程用的是哪个 Python、哪套 CUDA 库不要在排查到一半时发现环境切错了。6.3 新手学习路线先跑通再深入如果你刚接触这两个框架我不建议一上来就啃官方文档的每一个 API。更实际的做法是第一步把上面两个 MNIST 脚本分别跑通确保两个环境都正常工作。第二步改参数、改网络结构观察训练结果的变化。第三步用同一个数据集比如猫狗分类、文本情感分类分别用两个框架实现一遍体会 API 组织方式的不同。第四步找一份开源项目的代码先读懂数据加载和模型定义再跑起来最后尝试替换里面的一两个模块。等你走到第四步就会发现框架之间的差别逐渐变小因为真正核心的东西——数据处理、模型结构、损失函数、优化器、评估指标——是相通的。框架只是表达这些思想的工具。我个人还是更建议把单任务先跑稳再考虑批量和接口化。前面有人问“我全都要”是不是太贪心我的回答是框架不是信仰是工具。两个都装上、都跑一遍、都踩过坑你自然知道在什么场景下该拿哪个出来用。环境搭好之后剩下的就是多写、多跑、多排查这条路没有任何捷径。最后留几个我自己排查时会优先看的点安装命令是不是从官方最新页面复制的虚拟环境有没有激活对显存是不是被其他进程占着模型文件路径和权限是否正常。这四件事能覆盖大多数“看起来像框架问题”的实际情况。