
看到热搜词里同时挂着“tensorflow安装”和“tensorflow与pytorch的流行趋势 2024年”我确实有点感慨。过去一年里几乎每天都会收到类似“TensorFlow 是不是没人用了”“现在入门是不是该直接学 PyTorch”的问题。作为一个从 TensorFlow 1.x 一路用到 2.x又在生产环境里把它和 PyTorch 都跑过的人我想借这篇博文把 TensorFlow 现在到底是什么状态、怎么正确地从安装开始上手、以及它和 PyTorch 之间的真实差距讲清楚。这不是一篇劝退文也不是无脑拉踩。我会从实际工程经验出发告诉你什么时候应该选 TensorFlow什么时候选 PyTorch并且给出可以直接照做的安装步骤和跑通第一个模型的完整流程。无论你是刚接触深度学习的小白还是想给团队做技术选型的工程师这篇文章应该都能给你一些参考。1. 先说结论2024 年 TensorFlow 没有死只是换了角色1.1 “TensorFlow 过气”的声音为什么这么大过去几年 PyTorch 在学术界几乎成了默认选项顶会论文里的开源代码大部分都是 PyTorch 写的。这导致很多人产生一个错觉TensorFlow 已经不行了。但实际上如果你去看工业界的生产环境、移动端部署、云端 TPU 训练TensorFlow 依然有大量存量系统在稳定运行而且 Google 自己的搜索、推荐、广告等核心业务也一直在用 TensorFlow 或其底层技术。我记得有一次和一个朋友聊他刚入职某互联网公司发现内部推荐系统全是 TensorFlow 的 SavedModel还要用 TensorFlow Serving 做线上推理。他当时很惊讶“我一直以为 TensorFlow 没人用了。”我说这不奇怪PyTorch 让研究和原型开发变得很舒服但真正要把模型稳定地跑在服务器上、做版本管理、做灰度发布TensorFlow 的企业级工具链还是相当成熟的。所以与其说 TensorFlow 过气了不如说它把生态重心从“方便研究者做实验”转向了“方便公司做产品”。这没有谁更好只是定位不同。1.2 TensorFlow 真正不可替代的三个场景我自己的经验里有几个场景选 TensorFlow 比选 PyTorch 更省事线上高性能推理TensorFlow Serving 原生支持 SavedModel模型热加载、多版本管理、批处理这些功能开箱即用。PyTorch 虽然也有 TorchServe但生态成熟度和运维工具的完善程度还是有差距。移动端和嵌入式设备TensorFlow Lite 在 Android、iOS、树莓派、MCU 上的支持非常广部署流程很成熟。PyTorch 的 Mobile 方案也不错但如果你要支持的平台特别杂TFLite 的算子覆盖和工具链更稳。与 TPU 或 Google Cloud 深度绑定如果你要用 TPU 训练大模型TensorFlow / JAX 是天然选择。PyTorch 对 TPU 的支持虽然也在改进但 TensorFlow 在这块仍然是第一方亲儿子。当然这不代表 PyTorch 不优秀。做研究、快速迭代、尤其是 NLP 生成式模型PyTorch 的体验确实好得多。选型从来不是“哪个最好”而是“你所在的场景哪个最合适”。2. 环境准备TensorFlow 安装不是 pip install 那么简单2.1 从 CPU 版本到 GPU 版本先确认你的硬件再动手很多新手上来就执行pip install tensorflow然后发现跑得慢再问为什么没用上 GPU。其实 TensorFlow 2.x 的 PyPI 包默认是同时支持 CPU 和 GPU 的只要你机器上有 NVIDIA 显卡并且驱动、CUDA、cuDNN 版本对得上它就会自动调用 GPU。但麻烦也恰恰出在版本匹配上。我建议的安装流程是这样的以 Linux 环境为例先用nvidia-smi确认显卡驱动版本并查看驱动支持的 CUDA 版本。到 TensorFlow 官方文档的“安装”页确认当前版本要求的 CUDA 和 cuDNN 版本号。安装对应版本的 CUDA Toolkit 和 cuDNN建议用 conda 管理环境避免污染系统环境。pip install tensorflow或者如果需要指定版本比如pip install tensorflow2.15.*。安装完以后不要急着跑模型先跑一个小代码块确认 GPU 是否可见。确认 GPU 是否可用的标准姿势import tensorflow as tf print(tf.__version__) print(tf.config.list_physical_devices(GPU))只要你看到类似[PhysicalDevice(name/physical_device:GPU:0, device_typeGPU)]的输出说明 GPU 已经正常接入。如果只看到 CPU多半是 CUDA/cuDNN 版本没配对。2.2 GPU 环境最容易翻车的三个原因及对应解法我在群里帮人排查过很多次“TensorFlow 装好了但不用 GPU”的问题总结下来基本是这几种装了 CPU-only 的包。如果你不小心装的是tensorflow-cpu那不管 GPU 多好都白搭。卸载重新装tensorflow即可。CUDA 和 cuDNN 版本与 TensorFlow 不匹配。这一点最常见尤其你如果之前装过 PyTorchPyTorch 可能自带 CUDA 运行时但 TensorFlow 用的是系统里动态链接的 CUDA。最省心的方法是直接用 conda 创建新环境然后conda install -c conda-forge cudatoolkit版本号 cudnn版本号再pip install tensorflow。驱动版本太低导致 CUDA 不可用。这个只能用nvidia-smi查看如果显示的 CUDA Version 比你需要的低就得去 NVIDIA 官网升级驱动。老实说TensorFlow 的 GPU 环境配置比 PyTorch 麻烦一点因为 PyTorch 的 pip 包会把 CUDA runtime 一起打包而 TensorFlow 依赖系统级的 CUDA 动态库。我知道有些人就是因此被劝退但如果你用 conda 管理环境踩过一次坑后其实也还好。2.3 在 Windows 和 macOS 上安装的特别说明Windows 上现在 TensorFlow 2.10 之后开始只支持原生 Windows 的 GPU 版本但后续版本可能转向 WSL2 推荐。如果你在 Windows 上遇到装好 GPU 版却调用失败我建议直接用 WSL2 装 Ubuntu再在 Linux 环境里跑 TensorFlow省掉大量兼容性问题。macOS 用户则基本只能用 CPU 版Apple Silicon 上可以尝试用 TensorFlow Metal 插件但我个人体验是性能提升有限真要做深度学习训练还是建议搞一台 NVIDIA GPU 机器或用云 GPU。3. 吃透 TensorFlow 2 的五个核心概念你才算真正入门3.1 张量和自动微分TensorFlow 的“数据流”本质TensorFlow 这个名字拆开就是“张量流动”。你可以把张量理解为多维数组但它比 NumPy 的 ndarray 多了一个“计算图”的视角。TensorFlow 2 默认是动态图模式Eager Execution写起来很直观import tensorflow as tf a tf.constant([[1.0, 2.0], [3.0, 4.0]]) b tf.constant([[5.0, 6.0], [7.0, 8.0]]) c tf.matmul(a, b) print(c.numpy())这种写法跟你写 NumPy 几乎一样但背后 TensorFlow 会记录每个张量是怎么算出来的方便你做自动微分。自动微分是深度学习的命根子有了它你只需要定义前向计算反向传播梯度是自动完成的x tf.Variable(3.0) with tf.GradientTape() as tape: y x ** 2 grad tape.gradient(y, x) print(grad.numpy()) # 6.0我见过很多初学者一开始就钻计算图、占位符、会话的牛角尖那是 TensorFlow 1.x 的老黄历。2.x 时代的入门姿势很简单把 TensorFlow 当作“能做自动微分的 NumPy”跑通前向和反向再慢慢理解性能相关的tf.function。3.2 Keras API 是主入口但别忽略 tf.functionKeras 已经是 TensorFlow 官方推荐的高层 API。tf.keras.Sequential、tf.keras.Model这些类让我们搭网络像搭积木。但真正到了性能调优和上线阶段tf.function才是关键。tf.function的作用是把 Python 函数编译成 TensorFlow 计算图让模型在训练和推理时跑得更快。这里有个经典坑很多人直接在自定义训练循环里用纯 Python 的for循环导致每次迭代都要重新建图速度极慢。正确的做法是把你的一整步训练逻辑包在一个被tf.function装饰的函数里tf.function def train_step(images, labels): with tf.GradientTape() as tape: logits model(images, trainingTrue) loss loss_fn(labels, logits) grads tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables))刚开始不需要深究tf.function的底层原理但要意识到Keras 的model.fit()已经在内部帮你做了这些优化而一旦你写自定义训练循环就必须手动处理性能问题。3.3 tf.data 数据集管道让数据不再是瓶颈很多初学者跑小数据集的时候感觉不到数据读取的影响但到了真实项目里模型训练慢往往不是 GPU 不够而是 CPU 读数据的速度跟不上。tf.data.Dataset是一个强大的数据管道工具。它有两条最重要的规则用map做预处理时尽量用 TensorFlow 原生算子或者用tf.py_function包一层但注意性能损失。训练前一定调用prefetch(buffer_sizetf.data.AUTOTUNE)让数据加载和模型计算重叠。一个典型的数据集构建dataset tf.data.Dataset.from_tensor_slices((x_train, y_train)) dataset dataset.shuffle(10000).batch(64).map(preprocess_fn).prefetch(tf.data.AUTOTUNE)顺序不要搞错。先 shuffle再 batch再 map最后 prefetch。如果你先 batch 再 shuffle每个 batch 内部的样本顺序永远是固定的shuffle 只能打乱 batch 顺序效果会差很多。3.4 模型子类化要灵活可以避开 SequentialSequential只适合线性堆层的简单网络。真实项目里经常有残差连接、多输入、共享层这些结构这时候要继承tf.keras.Model重写__init__和call类似 PyTorch 的nn.Module。我自己的习惯是模型复杂就用子类化但build方法里也别忘了super()初始化。3.5 回调机制训练过程中最容易被忽视的“监控器”Keras 的ModelCheckpoint、EarlyStopping、ReduceLROnPlateau这几个回调我几乎每次训练都用。尤其是ModelCheckpoint能让你在训练中途意外中断时不至于前功尽弃。新手总想着把训练跑完再看结果但有经验的人一定会在训练过程中持续保存最优权重而不是最后一刻才保存。4. 完整跑通一个图像分类任务从数据准备到模型部署4.1 从 CIFAR-10 开始比较真实的训练流程这里我以一个最经典的 CIFAR-10 分类任务为例演示 TensorFlow 2 从数据加载、模型搭建、训练到导出的完整流程。CIFAR-10 有 5 万张 32x32 的小图10 个类别虽然简单但足以跑通整个深度学习项目生命周期。数据加载直接使用tf.keras.datasets.cifar10但这里有个常见的坑返回的数据是 NumPy 数组范围是 0 到 255。直接用的话模型很难收敛必须做归一化(x_train, y_train), (x_test, y_test) tf.keras.datasets.cifar10.load_data() x_train x_train.astype(float32) / 255.0 x_test x_test.astype(float32) / 255.0 y_train tf.keras.utils.to_categorical(y_train, num_classes10) y_test tf.keras.utils.to_categorical(y_test, num_classes10)然后构建一个简单的卷积网络model tf.keras.Sequential([ tf.keras.layers.Conv2D(32, (3, 3), activationrelu, input_shape(32, 32, 3)), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Conv2D(64, (3, 3), activationrelu), tf.keras.layers.MaxPooling2D((2, 2)), tf.keras.layers.Flatten(), tf.keras.layers.Dense(64, activationrelu), tf.keras.layers.Dense(10, activationsoftmax) ])4.2 训练细节为什么数据增强和早停能救命直接训练这个模型花不了几分钟但准确率大概也就 60% 上下想提升需要加数据增强。tf.keras.layers.RandomFlip和RandomRotation可以直接作为网络层加在输入侧非常方便data_augmentation tf.keras.Sequential([ tf.keras.layers.RandomFlip(horizontal), tf.keras.layers.RandomRotation(0.1), ]) inputs tf.keras.Input(shape(32, 32, 3)) x data_augmentation(inputs) x tf.keras.layers.Conv2D(32, (3, 3), activationrelu)(x) ... model tf.keras.Model(inputs, outputs)训练时我习惯加上EarlyStopping和ModelCheckpoint。ReduceLROnPlateau也很有用当验证集指标不再提升时自动降低学习率往往能再往下探一点callbacks [ tf.keras.callbacks.EarlyStopping(patience5, restore_best_weightsTrue), tf.keras.callbacks.ModelCheckpoint(best_model.h5, save_best_onlyTrue), tf.keras.callbacks.ReduceLROnPlateau(factor0.5, patience3), ] model.compile( optimizertf.keras.optimizers.Adam(learning_rate1e-3), losscategorical_crossentropy, metrics[accuracy] ) model.fit(tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(64).prefetch(tf.data.AUTOTUNE), validation_data(x_test, y_test), epochs50, callbackscallbacks)注意我这里没有先手动shuffle因为原本的数据在load_data后已经随机分布但真实场景里如果你的数据是顺序存储的一定要shuffle否则每个 batch 会偏向一个类别。4.3 导出 SavedModel 并用 TensorFlow Serving 部署训练完以后模型文件best_model.h5只是中间产物。真正上线时推荐导出为SavedModel格式因为 TensorFlow Serving 可以直接加载也方便后续做版本管理。model.save(saved_model/my_model, save_formattf)然后启动 TensorFlow Serving一个基础的 Docker 命令docker pull tensorflow/serving docker run -p 8501:8501 \ --mount typebind,source$(pwd)/saved_model/my_model,target/models/my_model \ -e MODEL_NAMEmy_model \ -t tensorflow/serving这样你就可以通过 REST API 请求模型推理了curl -X POST http://localhost:8501/v1/models/my_model:predict \ -H Content-Type: application/json \ -d {instances: [[[...图片像素...]]]}在这个阶段你会发现TensorFlow Serving 的几个优势非常明显模型热加载、多版本路由、批量推理这些生产需求它都提供了标准方案。5. 2024 年 TensorFlow 与 PyTorch 的真实差距不只是流行度5.1 论文 vs 生产两个框架的定位已经完全分化用一张表来概括我观察到的差异对比维度TensorFlowPyTorch学术论文占比略低但还有不少支持目前绝对主流原型开发体验不错但历史包袱重非常舒服模型部署TF Serving / TFLite 生态完善TorchServe ONNX也还行分布式训练TF 分布式策略成熟DDP 也很成熟移动端支持TensorFlow Lite 覆盖广PyTorch Mobile / ExecuTorchTPU/特定硬件第一方支持需要适配社区活跃度偏工程实践偏研究和前沿为什么 PyTorch 在论文里占绝对上风因为它用起来更像写 Python调试方便社区里新的模型几乎都会先出 PyTorch 版本。但你要是去各大公司的生产环境看看TensorFlow 的存量服务绝对不少尤其是 2018 到 2021 年之间上线的系统很多都是 TensorFlow 1.x 或 2.x 写的。5.2 Keras 3 和 JAXTensorFlow 的自我革命2024 年必须提一下 Keras 3。Keras 现在变成了一个多后端框架默认可以用 TensorFlow、JAX 或 PyTorch 作为后端。这个变化意味着你写 Keras 代码在 TensorFlow 和 PyTorch 之间切换的摩擦变小了。另外Google 也在大力推 JAX很多新项目直接用 JAX 做研究而不是 TensorFlow。我觉得这更像是一场内部转型。TensorFlow 没有坐以待毙而是通过 Keras 3 把自己变成一个更开放的生态同时把训练性能的重心慢慢移向 JAX。对普通开发者来说短期影响不大但你得知道TensorFlow 2 依旧维护但长期新增功能可能会集中到 JAX 和 Keras 后端上。5.3 我怎么给团队选型作为一个经常要拍板技术选型的人我给团队的建议很直接如果你做 CV、推荐系统、搜索、广告这类偏工程落地的方向且团队没人对 PyTorch 有强烈偏好选 TensorFlow 是稳妥的。如果你做 NLP、大模型、生成式 AI或者需要快速复现最新论文选 PyTorch因为 Hugging Face Transformers 生态就是围绕 PyTorch 转的。如果你的团队两种都会那优先看部署环境。如果你的服务器上已经有成熟的 TF Serving 基础设施就别轻易换框架。如果你刚入门、想找好工作建议学 PyTorch因为它更容易学会且就业市场对 PyTorch 需求更热。但也不要完全放弃 TensorFlow因为很多偏传统行业的公司还在用它。“TensorFlow 和 PyTorch 哪个更好”这个问题本质上不是技术问题而是场景问题。我见过在 PyTorch 上开发很快、部署却折腾一周的团队也见过 TensorFlow 从训练到上线非常顺的团队。你和你的团队最熟悉什么、维护成本最低那个就是最适合的。6. 我在实际项目里踩过的 TensorFlow 坑汇总6.1 版本不匹配问题真的会让人崩溃我最早在生产环境踩的坑是 TensorFlow 2.4 和 CUDA 11.2 配对问题。当时测试环境明明跑得好好的上生产容器却提示libcudnn.so.8 找不到原因是生产镜像里的 cuDNN 版本不对。后来我们统一用官方提供的 Docker 镜像把 CUDA、cuDNN 这些底层的坑全部交给镜像管理问题才彻底解决。如果你不用 Docker我的建议是建立一个 conda 环境然后严格参照官方文档列出的版本矩阵去装。不要信网上说的“随便装最新版”TensorFlow 对版本真的挑剔。这个坑可以说浪费了无数人半天时间根本不值得重踩。6.2 模型保存格式H5、SavedModel、Checkpoint 到底选哪个tf.keras.callbacks.ModelCheckpoint默认保存.h5格式方便加载继续训练但如果你要部署到 TensorFlow Serving必须导出为SavedModel格式。另一个常见坑是在自定义训练循环里用tf.train.Checkpoint保存的 Checkpoint常常只有变量权重没有完整的图结构加载时需要重新构建模型。我个人的习惯是训练过程中保存.h5或 Checkpoint方便断点续训。训练完成后导出SavedModel作为部署件。如果需要在不同框架间迁移再用onnx兜底。6.3 与 PyTorch 模型互转ONNX 也不是万能的项目里有时候会遇到其他同事用 PyTorch 训练好模型却要部署到我们的 TensorFlow Serving 里。最常规的方案是用 ONNX 中转。PyTorch 模型可以torch.onnx.export到 ONNX再用onnx-tf转换为 TensorFlow 模型。但注意不是所有算子都能转成功。我遇到过一个模型里用了torch.where和F.grid_sample转 ONNX 成功但转 TensorFlow 的时候算子不支持最后只能手动改网络结构。所以结论是互转只适合结构简单的模型复杂模型最好还是用原框架部署或者训练之前就统一框架。6.4 显存溢出怎么排查训练到一半提示Resource exhausted: OOM时不要急着调小 batch size。先用nvidia-smi看显存占用可能是上一个训练进程没被杀掉占着显存。kill掉残留进程后再考虑调小 batch size 或使用混合精度from tensorflow.keras import mixed_precision mixed_precision.set_global_policy(mixed_float16)混合精度能省不少显存。但有些算子对 float16 很敏感用的时候要盯紧训练曲线万一不收敛就改回 float32。6.5 数据读取的隐性瓶颈很多人只在 GPU 上做优化忽略了数据管道的瓶颈。tf.data最常用的优化是prefetch和parallel_map。如果你的预处理函数是纯 Python 写的可以考虑改成tf.image和tf.numpy_function的混合方案或者直接用num_parallel_calls提高并行度dataset dataset.map(preprocess_fn, num_parallel_callstf.data.AUTOTUNE)要注意num_parallel_calls不是越大越好设成和 CPU 核心数相近即可。这个细节对训练速度的影响往往比调几层网络还明显。7. 写在最后的经验分享如果你问我“TensorFlow 现在还值得学吗”我的答案是取决于你要做什么。如果你想快速进入现代深度学习会 PyTorch 确实更容易、也更方便看论文复现。但如果你面向的是企业级应用、生产环境或者你所在的团队就是 TensorFlow 栈那你完全有理由把 TensorFlow 学深一点。我个人在实际操作中的体会是TensorFlow 最大的问题从来不是能力不足而是学习路径对新手不友好。它比 PyTorch 多一点抽象层Keras、tf.function、SavedModel、Serving每样都是单独的概念。但如果你按着“装环境、用 Keras 搭模型、用fit训练、导出 SavedModel、用 Serving 部署”这条链路走一遍你会发现它的生产链路完整度真的很高。最后分享一个小技巧新项目一开始就把环境和部署方式定下来。不要先在裸环境里跑通训练再想怎么部署。我见过太多人训练时用.h5上线时发现要导出SavedModel转换又出了问题。正确的顺序是搭建项目的一开始就用一个 Docker 镜像固定好 TensorFlow 版本、CUDA 版本和 Serving 版本后续所有开发都在这个镜像里做。这样省下来的排障时间绝对比你重新配置一遍环境多得多。希望这篇分享能帮你在 TensorFlow 这条路上少踩几个坑。框架这个东西本就不是什么信仰选一个解决问题的工具而已。工具合适就好。