
最近后台总有人问一个特别扎心的问题2024年了TensorFlow是不是已经没人用了问的人多半是在校学生或者想转行的朋友看过几篇PyTorch的教程又看到GitHub上TensorFlow的issue讨论没以前热闹就觉得这东西是不是该“入土”了。每到这个时候我都想拦一句别急先把TensorFlow装起来跑个模型再下结论也不迟。这篇就打算从2024年的视角重新把TensorFlow过一遍。先聊它现在到底处于什么生态位然后讲安装环境怎么搭最省心再说清楚它的核心API逻辑最后用一个小项目把整个流程串起来。同时聊透一个绕不开的话题——TensorFlow和PyTorch现在到底怎么选。这篇不是劝你“非要用TensorFlow不可”而是帮你建立一个足够完整的判断坐标系知道这东西在什么场景下是刚需在什么场景下换了更顺手。适合刚开始接触深度学习、想在两个框架之间做选择、或者打算把旧项目从TensorFlow 1.x迁到2.x的读者。1. 2024年的TensorFlow看似“冷”了但实际底盘很稳1.1 为什么会有“TensorFlow凉了”的错觉这个错觉的来源很直接。学术界发论文大家刷Arxiv会发现PyTorch代码出现的频率越来越高尤其是Transformer、扩散模型、大语言模型这些东西几乎默认用PyTorch实现。有的统计里NeurIPS、ICML这些顶会的论文里PyTorch使用占比能到百分之七八十TensorFlow反而成了少数派。学生跟着导师做实验互相传代码全是.pt后缀的权重文件那自然觉得全世界都在用PyTorch。再加上TensorFlow社区确实发生过一些震荡。Google在TensorFlow和JAX之间的资源分配Keras 3.0又搞了一套多后端让人感觉方向一直在变。社区讨论热度没有2018年那么疯狂新手入坑前搜一圈很容易觉得这框架“不香了”。但“论文里用得少”和“生产环境没人用”是两个完全不同的概念。我这些年接触过不少做推荐系统、广告CTR预估、风控和工业视觉的团队他们线上跑的模型很多还是TensorFlow的SavedModel。这些系统往往已经稳定运行了两三年模型导出一份pb文件扔到TF Serving里QPS扛得住服务稳定性有保证没必要为了追时髦把整个链路推翻。1.2 为什么生产端依然相信TensorFlow这里头有几个底层逻辑。第一是部署链路成熟TF Serving、TensorFlow Lite、TensorFlow.js覆盖了从服务器到移动端再到浏览器的全场景这在PyTorch那边虽然现在也补上了TorchServe和ExecuTorch但相比TensorFlow多年沉淀的工具链还是嫩了一些。第二是Keras API的稳定性和易用性在2.x时代大大拉高了开发效率团队协作成本低。第三是Google内部大量业务跑在TPU上而TPU的软件栈和TensorFlow/XLA深度绑定。如果你有一天需要把模型跑到TPU上TensorFlow依然是第一公民。2024年的节点上还有一个值得注意的变化Keras 3.0开始支持多后端同一个模型代码可以在TensorFlow、JAX和PyTorch之间切换。这个动作很微妙等于官方承认了生态多元同时把TensorFlow定位成一个底层执行引擎而非唯一入口。也就是说你完全可以用熟悉的Keras风格写模型后端选TensorFlow来跑数据管线和部署。所以结论是TensorFlow没有凉它只是从一个“被捧上天的明星”变成了“做基础设施的老实人”。对想进工业界搞模型部署的人TensorFlow这碗饭是绕不开的。2. 安装TensorFlow版本、硬件、环境一次说清2.1 安装前必须确认的版本策略很多人安装翻车不是网络问题而是不知道TensorFlow和Python、CUDA、cuDNN之间有严格的版本配对表。就以2024年底的状态来说稳定版已经到2.18官方推荐的Python版本是3.9到3.12再往上比如Python 3.13经常会出现依赖冲突因为trition、numba这些库还没跟上。安装命令看起来简单一行pip install tensorflow但我要多提醒一句如果你在Linux环境里装这一步装的是带CUDA支持的GPU版本如果在Windows上是原生安装默认也带GPU支持前提是卡和驱动没问题如果你在macOS上装装的是CPU版本M系列芯片要额外装tensorflow-metal来启用GPU加速。更稳妥的做法是用虚拟环境隔离。我自己的习惯是python -m venv tf_env source tf_env/bin/activate # Windows下用 tf_env\Scripts\activate pip install --upgrade pip pip install tensorflow python -c import tensorflow as tf; print(tf.__version__)这一套下来如果你只是CPU跑个小模型基本就能用了。但如果你需要GPU加速事情要再细一点。2.2 GPU环境配置最容易踩坑的死角GPU加速的安装流程里最大的坑不是TensorFlow本身而是CUDA和cuDNN的版本对齐。官方在2.18版本里对应的组合大致是NVIDIA驱动建议525以上CUDA 12.3cuDNN 9。这两个东西不是装得越新越好而是要和TensorFlow的预编译二进制对齐装太新反而识别不了。我见过太多人卡在一个现象上tf.config.list_physical_devices(GPU)输出是空的但nvidia-smi明明能看到显卡。原因绝大多数是装的是CPU版TensorFlow注意某些pip镜像源会把tensorflow指到tensorflow-cpuCUDA版本和TF不匹配加载共享库失败在容器里没挂载GPU设备这个要单独看docker run的--gpus参数。排查的时候建议用import tensorflow as tf print(tf.config.list_physical_devices(GPU))如果输出列表是空的再查print(tf.test.is_gpu_available(cuda_onlyTrue))这里还要提一个Windows用户的经典误区在Windows下用WSL2装TensorFlow跑GPUNVIDIA驱动要装Windows侧的然后在WSL2里装CUDA toolkit两边的驱动版本要联动。如果你没搞清楚这个联动很常见的症状就是“WSL2里看得到GPU但TF永远用不了”。2.3 国内镜像源的实际意义安装的时候用国内镜像能省很多时间这个不用我说大家也都懂。我常用的是清华的PyPI镜像pip install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple另外提一句如果你要用Keras 3的多后端能力可以顺手把JAX或者PyTorch也装上然后通过KERAS_BACKEND环境变量切换。这个功能在2.16之后成了默认行为Keras已经不在TensorFlow主包里了是独立安装的keras包很多老朋友不知道这一点以为装了tensorflow就会自动带上Keras其实在2.16版本上装tensorflow会同时拉一个匹配的Keras版本倒也不用太担心但二手环境里经常会出现两个Keras版本叠加的混乱情况。排查这类混乱的办法很简单输出一下这两个路径看看是不是同一个环境下的版本import keras import tensorflow as tf print(keras.__version__) print(tf.__version__)3. 从“会调用API”到“理解TensorFlow的运行逻辑”3.1 Eager Execution让2.x彻底友好TensorFlow 1.x时代劝退新人最狠的一点是计算图模式你得先把整张图描述清楚然后放到Session里跑像写SQL一样写完整个查询最后execute一下。逻辑没错但对快速验证想法很不友好。到了2.x默认开启Eager Execution就是Python里写一步执行一步调试的时候能直接看到中间结果——这体验终于和PyTorch一致了。对于新手来说你只需要记住一个最大的区别在2.x里普通Python代码写出来的张量运算就是动态的不用手动建图和跑session。当你需要性能的时候再通过tf.function把一段python代码编译成静态图。“动态的灵活”和“静态的性能”你都可以要关键要会切换。3.2 张量、轴和形状绕不开的底层概念说句实话TensorFlow里最抽象的并不是张量本身——它就是多维数组。真正的门槛是维度操作和广播机制。很多刚开始写的人搞不清楚shape(3, 4)和shape(4, 3)差在哪里reshape之后数据到底怎么排列。这里我建议一个经验遇到维度问题先手动算一下输入输出形状再用小矩阵打印验证。不要凭感觉写。比如tf.matmul要求两个矩阵最后两维匹配前面维度广播写错了报出来的维度错误信息是英文长句子第一次看确实容易懵但只要你花十分钟把官方那张形状匹配逻辑图过一遍之后就很难再错。3.3 Keras是你的“冰箱”不是玩具很多教程喜欢把Keras说成“高级API”或者“为小白设计”这个说法会让人小看它。Keras 3在2.16之后内置了完整的模型构建、训练、评估、导出、分布式策略接口它更像一台套好保鲜膜的冰箱——你往里面放什么菜都能保鲜但真正的烹饪还是得你自己做。极端情况下你完全不用再写底层的tf.Variable和tf.GradientTape用keras.Sequential或者keras.Model子类化就能解决95%的建模需求。但如果你要自定义一个特殊的损失函数或者要按batch做一些默认API做不到的变换那还是要理解train_step是怎么被子类重写的。我遇到不少人在自定义训练循环这卡住这里给个最小框架import tensorflow as tf from tensorflow import keras class MyModel(keras.Model): def train_step(self, data): x, y data with tf.GradientTape() as tape: y_pred self(x, trainingTrue) loss self.compiled_loss(y, y_pred) grads tape.gradient(loss, self.trainable_variables) self.optimizer.apply_gradients(zip(grads, self.trainable_variables)) self.compiled_metrics.update_state(y, y_pred) return {m.name: m.result() for m in self.metrics}这段代码是自定义训练循环的地基。官方文档讲得比我详细但核心就是梯度带记录前向过程反向算梯度优化器更新变量。4. 一个完整的入门实战图像分类从零到SavedModel导出4.1 数据从哪里来用内置数据集先跑通任何框架教程如果第一步就让你去网上下载几千张图片做清洗标注那多半是在劝退。我建议新手上手就用tf.keras.datasets里的现成数据比如Fashion MNIST——它是MNIST的替代品同样是28×28灰度图但类别是服装对新手更友好训练起来也快。加载只需要一行(x_train, y_train), (x_test, y_test) tf.keras.datasets.fashion_mnist.load_data()拿到数据先做归一化x_train x_train.astype(float32) / 255.0。这个不归一化训练出来的loss很可能一开始就卡住因为像素值0~255和模型初始化的权重范围差距太大梯度更新会很别扭。4.2 模型构建和训练配置模型用最简单的多层感知机或者一个小卷积网络都可以。这里选个小型CNN来演示因为CNN比纯Dense更能体现“网络结构”的威力model keras.Sequential([ keras.layers.Reshape((28, 28, 1), input_shape(28, 28)), keras.layers.Conv2D(32, 3, activationrelu), keras.layers.MaxPooling2D(), keras.layers.Conv2D(64, 3, activationrelu), keras.layers.MaxPooling2D(), keras.layers.Flatten(), keras.layers.Dense(128, activationrelu), keras.layers.Dense(10, activationsoftmax) ]) model.compile( optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy] )为什么用sparse_categorical_crossentropy而不是categorical_crossentropy因为前者的标签是整数索引后者需要one-hot编码。Fashion MNIST的标签是0到9的整数直接用sparse版本省一步。训练的时候建议加上validation_split和回调history model.fit( x_train, y_train, epochs10, batch_size64, validation_split0.2, callbacks[keras.callbacks.EarlyStopping(patience3, restore_best_weightsTrue)] )这里EarlyStopping很实用——它能监测验证集指标连续几个epoch没有提升就自动停止并且restore_best_weights会把模型恢复到历史上验证集表现最好的那一步。很多时候模型过拟合了还不知道就是没加这个回调。4.3 评估、导出和部署前的形态转换训练完model.evaluate(x_test, y_test)看一下测试集准确率正常Fashion MNIST跑到0.9以上是没问题的。然后就是导出model.save(mnist_cnn.keras) model.export(saved_model_dir)在2.16之后的Keras 3里.keras格式是官方推荐的保存格式一个文件搞定架构和权重清清楚楚。而export则导出完整SavedModel可以直接给TF Serving用。到这里你的第一个完整闭环就打通了数据加载、模型定义、训练、回调、评估、导出。后续要上线服务只需要用tensorflow/serving镜像里的tensorflow_model_server把saved_model_dir卷进去跑起来就行了。5. TensorFlow与PyTorch的流行趋势选型不是站队5.1 两边到底差在哪一句话概括如果非要用一句话说清两个框架的本质差异我的理解是TensorFlow是“先生产后研究”的框架PyTorch是“先研究后生产”的框架。TensorFlow的图优化、分布式策略、部署工具链一开始就是奔着工业级来的PyTorch的调试体验、动态图和Python风格从一开始就奔着科研人员的“快速验证”去的。两边这几年疯狂互相学习你加动态图我也加静态导出你有TorchServe我有TF Serving但基因里的侧重点还在。拿2024年的一个典型场景举例训练一个中小规模的视觉模型PyTorch的写法更像我平时写Python代码想打印哪里就打印哪里断点调试稳如老狗TensorFlow在Eager Execution下也做得不错但一旦你加上tf.function去追性能中间报错的信息量就会陡增排查起来确实费力一点。反过来讲部署TensorFlow这边导出一个SavedModel目录里面是pb文件和variable文件夹用TF Serving时直接通过gRPC或REST接口对外服务还能用TensorFlow Model Server自带的批量调度和版本管理。PyTorch那边TorchServe也做得相当可以但你想在移动端跑TensorFlow Lite和TFLite的优化工具链至今依然更成熟。5.2 2024年的趋势对普通开发者的影响从论文总量来看PyTorch的势头确实很猛尤其在生成式模型、大模型微调这块HuggingFace生态从底层就是PyTorch优先的你拿个Qwen或者Llama来微调社区的示例代码绝大多数是.py加.ptTensorFlow虽然也有transformers库的支持但总有一种“二等公民”的味道很多新模型发布当天只有PyTorch权重。这种生态差异带来的一个实际判断是如果你主要在学术圈做研究或者主要玩开源预训练模型那PyTorch的高频场景明显更多但如果你做的项目要进企业生产环境团队里要长期运维一套模型服务或者你的客户对部署有严格的私有化和性能要求那TensorFlow的成熟工具链会让你省很多事。我个人的看法是不要在这个问题上做“信仰绑定”。两边都是开源框架代码都是公开的真正值钱的是你对深度学习本身的理解。我带过不少实习生给他们一个模型结构描述用TensorFlow写成和PyTorch写成工作量差异远没有网上说的那么夸张。换个框架就写不出来代码说明你还是不会建模而不是框架有问题。5.3 迁移旧项目的成本意识如果你手上有个TensorFlow 1.x的老项目准备迁到2.x这里有个非常重要的心理预期别指望搜索替换完成迁移。1.x里的tf.Session()、tf.placeholder、tf.get_variable这些API在2.x里要么被移除要么只在tf.compat.v1里苟延残喘。完整的迁移路径官方有工具tf_upgrade_v2但它只能处理机械性的API替换处理不了需要重构的逻辑——比如把静态图的占位符和feed dict改成函数调用把变量作用域改成Keras层。我的建议是老项目如果还在线上跑得好好的不要为了技术债强行迁移等有需求变更时借机用Keras重写一遍受影响的模块比整体迁移稳得多。6. 那些文档里不写、但实战必知的细节6.1 随机种子为什么你的结果时好时坏深度学习模型训练天然有随机性数据打乱、权重初始化、dropout都会引入随机因子。如果你希望实验可复现必须在训练前固定随机源tf.keras.utils.set_random_seed(42)这个调用会同时设置Python的random、NumPy和TensorFlow的随机种子。注意它并不能保证GPU上100%完全可复现因为某些GPU算子本身是并行的非确定性操作但至少能让结果不再“每次跑都差一大截”。论文实验要出稳定对比数据的同学这一步千万不能省。6.2 OOM之后先别急着骂机器训练大模型时显存溢出Out of Memory几乎人人都会遇到。我第一次在单卡上训练一个比较大的BERT模型时报错信息刷了一屏英文只能看到ResourceExhaustedError几个字第一反应就是“这卡是不是假的”。后来才学到一套排查顺序先看batch size是不是太大再看序列长度是不是没必要那么长然后看混合精度开了没有最后才考虑模型并行。混合精度是这两年最值得开的免费午餐from tensorflow import keras keras.mixed_precision.set_global_policy(mixed_float16)打开这行之后很多模型在训练速度上能提升百分之三四十显存占用也能降下来。代价是数值稳定性需要观察一下loss曲线如果出现NaN再回退到fp32就好。6.3 模型保存别用“一套流程吃天下”保存模型时经常有人随手用model.save(final_model.h5)然后过两天要部署时傻眼了。这里给个清晰的区分如果只是想在训练过程中保存checkpoint以便恢复训练用ModelCheckpoint回调保存.keras或者weights.h5都行如果模型要拿去上线提供推理服务导出SavedModel也就是model.export()的产物如果只是想分享给别人接着做研究给.keras文件是最省心的。另外自定义层里如果写了自定义逻辑加载时要么把类定义放在模块里能被import到要么传custom_objects否则会报反序列化错误。这种坑一般会卡住你一小时以上提前知道能省很多时间。7. 我的最终建议先跑通再站队这篇文章从头到尾聊了TensorFlow的生态位置、安装环境、核心API、实战案例、和PyTorch的趋势对比最后又给了几个实战中省命的细节。如果要我用一句话收束那就是框架是工具不是信仰。我个人在实际操作中的体会是如果一个新人只学一个框架我会建议他先装好TensorFlow跑通本文第四节那个图像分类的小闭环感受一下“数据进模型出结果再导出服务”的完整链路。这一步一旦跑通你对深度学习工程化的理解会扎实很多。之后再去做研究向的探索用PyTorch自然也不会有太大障碍——因为你真正学会的是建模和排查思路而不是背某个框架的API。最后分享一个小技巧装好TensorFlow之后直接在测试集上跑一次model.predict把输出的shape打印出来再和y_test的shape做对比亲手看一次预测张量的样子。这个动作看起来不起眼但它能让你以后遇到任何输入输出维度对不上的报错时第一时间想到“去打印shape”而不是上搜索引擎瞎猜。深度学习这座山看起来高但只要有条好走的路爬上去只是时间问题。