当学习完机器学习基础和简单的神经网络原理后,你肯定会想:难道每次写模型都要自己从零开始写矩阵乘法和反向传播吗?当然不是。在实际工程中,大家都会使用深度学习框架。
这篇文章主要介绍深度学习框架的作用,以及目前最主流的两个框架:PyTorch 和 TensorFlow 之间的区别。
一、为什么我们需要深度学习框架?
简单来说,深度学习框架就像是 AI 领域的“Spring Boot”或“React”。它们帮你把底层最复杂、最重复的工作打包好了。
- 自动求导(Autograd):训练神经网络最核心的一步是计算梯度(反向传播)。框架能自动帮你把这部分复杂的数学微积分算好。
- GPU 加速:矩阵运算在 CPU 上非常慢,框架可以让你只改一行代码,就把计算搬到显卡(GPU)上去执行,速度提升几十倍。
- 现成的层和优化器:无论是全连接层、卷积层,还是 Adam 优化器,框架里都内置了现成的 API,直接调用即可。
二、目前主流的两大阵营
目前工业界和学术界主要使用两大框架:由 Meta(原 Facebook)主导的 PyTorch,以及由 Google 主导的 TensorFlow。
1. TensorFlow:工业界的“老大哥”
TensorFlow 发布较早,曾经统治了整个深度学习领域。它的特点是工程化能力极强,特别适合将模型部署到手机端(TensorFlow Lite)、网页端(TensorFlow.js)或大规模服务器上(TensorFlow Serving)。
不过,早期版本(TF 1.x)的语法比较难懂,调试起来很痛苦。虽然 TF 2.x 吸收了 Keras 作为高层 API,变得简单了很多,但历史包袱依然存在。
2. PyTorch:学术界和研究者的最爱
PyTorch 是后起之秀,但凭借着极其“Pythonic”(符合 Python 编程直觉)的设计,迅速占领了学术界。它的代码写起来就像普通的 Python 代码一样,调试非常方便,可以直接使用 `print()` 打印出张量的值。
近年来,随着 PyTorch 生态(如 Hugging Face)的爆发,绝大多数新的大模型(包括各种开源 LLM)几乎都是基于 PyTorch 开发的。
三、初学者应该选哪一个?
如果你是刚入门的新手,**强烈建议从 PyTorch 开始学起**。原因如下:
- 语法更直观:代码逻辑更容易理解,调试方便,不会有太多奇怪的报错信息。
- 社区资源丰富:现在 GitHub 上绝大多数最新的开源模型和复现代码,都是用 PyTorch 写的。
- Hugging Face 生态:Hugging Face(相当于 AI 界的 GitHub)对 PyTorch 的支持是最好、最原生的。
四、一个小对比:定义一个简单的层
我们来看看用这两种框架定义一个包含 10 个输入和 5 个输出的线性层(全连接层)有什么区别:
PyTorch:
import torch
import torch.nn as nn
layer = nn.Linear(in_features=10, out_features=5)
TensorFlow (Keras):
import tensorflow as tf
from tensorflow.keras import layers
layer = layers.Dense(units=5, input_shape=(10,))
可以看出,两者在简单结构上都很简洁,但在复杂的自定义模型时,PyTorch 的面向对象写法会让逻辑更清晰。
不建议从 model.fit() 这类高层封装入手
Keras 的 model.fit() 一行就能跑完整个训练,看起来对新手最友好。但正因为它把训练循环整个藏起来了,入门阶段反而不推荐先用它。
前面那段 PyTorch 训练循环之所以值得手写一遍,是因为它把五个动作明确摆出来了:取数据、前向、算损失、反传、更新。这五步是所有深度学习训练的骨架,后面读任何论文代码、调试任何训练问题,都要回到这五步上定位。梯度没清零、损失算错了对象、更新前忘了反传——这些问题在手写循环里一眼可见,在 fit() 里则完全不可见。
合理的顺序是先手写几遍训练循环,理解每一步在做什么,再去用高层封装省事。先会拆,再用装好的——反过来的话,第一次遇到需要自定义损失或者梯度裁剪的场景就会卡住。
训练用的框架,不是部署用的格式
上面讨论的都是「用哪个框架写模型」。但有一件事教程里很少说清楚,而它会在你第一次想把模型真正用起来时立刻撞上:训练框架和部署格式是两回事。
用 PyTorch 训完模型,得到的是一个 .pt 或 .pth 文件。这个文件通常只保存了参数张量,不包含网络结构——加载它需要你手边有当初定义模型的那份 Python 代码,而且类名、层名、参数形状都要对得上。换句话说,.pt 文件不是一个可以独立分发的东西,它是「代码 + 权重」这一对里的一半。
所以真正上线时,几乎总要转成一个自包含的格式:
- ONNX:跨框架的通用中间表示。浏览器、C++ 服务、移动端都能加载,不需要 Python 环境。
- GGUF:llama.cpp 生态使用的格式,专为量化后的大语言模型设计,CPU 推理友好。
- TensorRT / CoreML / TFLite:绑定特定硬件或平台的高性能格式。
这个转换不是保存一下那么简单,它有自己的一整套坑。举两个具体的:模型里的动态控制流(比如根据输入形状走不同分支的 if)在导出成静态图时会被固化成导出时那一次的分支,其它输入进来结果就是错的;量化能把模型缩小到四分之一,但量化后的精度必须在真实分布的数据上重新验证,只在训练集风格的样本上测会严重高估它的可靠性。
这两件事我都实际踩过,写在浏览器跑 ONNX 的四个部署坑和量化验证的取样偏差里。入门阶段不需要马上去读,但知道「训练完还有一整段路」这件事,能帮你在选型时少走弯路。
动态图和静态图的差别,在部署时才真正显现
PyTorch「更好调试」这个说法背后的技术原因是动态图:每次前向传播都实时构建计算图,所以你可以在中间插 print()、可以用 Python 的 if 和 for、报错会指向你写的那一行。
静态图则是先把整个计算流程定义好、编译成一张图,再喂数据进去。写起来别扭,调试困难——这正是 TF 1.x 被诟病的地方。
但这个取舍有另一面:静态图能被优化和分发,动态图不能。编译器拿到完整的图之后可以做算子融合、常量折叠、内存复用,还可以把它序列化成一个不依赖 Python 的文件。这就是为什么部署时几乎总要把动态图「固化」成静态图(PyTorch 里是 torch.jit.trace、torch.export 或导出 ONNX)。
所以准确的说法不是「动态图更好」,而是动态图在开发期更好,静态图在部署期更好,现代框架的做法是让你用动态图开发、在最后一步转成静态图。理解这一点,比记住「PyTorch 是动态图」有用得多。
怎么判断手上这份教程已经过时了
这个领域变化快,新手最大的隐性成本不是学得慢,而是照着过时的教程学,然后花大量时间去调一个早就不该那样写的东西。学会识别过时代码,比多学一个 API 有用。
几个一眼可辨的信号:
- 出现
tf.Session()或sess.run():这是 TensorFlow 1.x 的写法,TF 2.x 已经默认即时执行,这类代码在新版本上直接跑不了。 - PyTorch 代码里出现
Variable(x):Variable在 0.4 版本就已经和Tensor合并,现在写它没有任何作用,只说明这份代码至少是几年前的。 - 用
.data取张量值:现在应该用.detach()。.data会绕过自动求导的追踪,在某些情况下产生静默错误的梯度。 - 调用
nn.functional.sigmoid之类:这些早已迁移到torch.sigmoid,旧写法要么警告要么已被移除。 - 训练循环里没有
optimizer.zero_grad():不是过时,是错。PyTorch 的梯度默认累加,不清零会让梯度一直叠加,训练行为完全不对——而且不会报错。
更靠谱的做法是优先看官方文档的教程,而不是搜索引擎排在前面的博客。官方文档会随版本更新,博客不会;而搜索排名靠的是年头久、链接多,恰恰偏向老内容。
另外一个实用习惯:跑别人的代码之前,先看它有没有写明依赖版本。一份没有 requirements.txt 或者没在文中说明框架版本的教程,出问题时你无从判断是自己写错了还是版本不对——这种不确定性对新手是最消耗信心的。
比框架更容易劝退的是版本地狱
最后一件教程通常不提、但新手一定会遇到的事:装不上。
深度学习框架和 GPU 之间隔着好几层,每层都有版本要求:显卡驱动 → CUDA → cuDNN → 框架编译时绑定的 CUDA 版本。任意一层对不上,症状都是同一句 torch.cuda.is_available() 返回 False,而它不会告诉你是哪一层的问题。
能省掉大部分麻烦的两条:
- 不要用
pip install torch的默认版本。去官网选好操作系统和 CUDA 版本,用它生成的那条完整命令——默认版本经常是 CPU 版,装完能 import 但用不了显卡。 - 每个项目一个独立环境。不同项目对框架版本的要求常常互斥,共用一个环境的结果是装好新的、旧的就坏了。
装好之后先跑这三行确认,再开始写模型:
import torch
print(torch.__version__, torch.version.cuda)
print(torch.cuda.is_available(), torch.cuda.get_device_name(0))
如果第二行是 False,先解决环境再往下走。在一个用不了 GPU 的环境里写完整个训练脚本,然后才发现要重装一切,是入门阶段最常见也最挫败的时间浪费。
五、下一步行动
接下来,你可以尝试:
- 安装 PyTorch(建议配合 Anaconda 和虚拟环境)。
- 了解框架中最基本的数据结构:张量(Tensor)。
- 尝试用 PyTorch 写一个最简单的手写数字识别(MNIST)模型。
记住,框架只是工具。无论用哪一个,理解数据是如何流入模型,以及损失函数是如何指导参数更新的,才是最核心的内功。