01
Google 的深度学习框架:Keras 3 时代
TensorFlow 是 Google 开源的深度学习框架,覆盖「定义模型 → 训练 → 保存 → 部署」整条链路。2.x 默认以 eager 执行(写一行、跑一行,跟普通 Python 一样好调试);从 2.16 起,默认内置的高层 API 就是 Keras 3——同一套 Keras 代码,后端可以换成 TensorFlow、JAX 或 PyTorch。
它解决的问题很直接:你不想手写梯度下降和矩阵求导,只想把精力放在模型结构和数据上。用 model.fit() 十行以内就能完成一次完整训练;等模型练好了,.keras 保存、model.export() 导出、TF Serving 上线,路径都是官方铺好的。
适合谁:要在生产环境部署模型(TF Serving / LiteRT 移动端)的团队、想用最省事 API 入门深度学习的初学者。如果你的方向是研究、追新论文,PyTorch 生态更主流——两套都值得摸一遍,心智模型是相通的。
一句话版本史:1.x 的静态图让无数人吃过「先定义再 run」的苦,2.0 起全面拥抱 eager 执行;2.16 把 Keras 3 推上默认位,打通多后端。现在装 2.x,你拿到的就是「默认即时执行 + Keras 3」的组合。
生态位怎么记:训练用 TensorFlow / Keras;部署分两条线——服务器侧 TF Serving 吃 SavedModel,手机与嵌入式端走 LiteRT(原 TF Lite),浏览器里另有 TensorFlow.js。本页聚焦训练主线,部署概念在 s5、s7 里点到为止。
- 最新稳定版
- 2.21.0(2026-11 核对)
- 内置 Keras
- Keras 3(2.16 起默认)
- 开发方
- Google,Apache-2.0 开源
- 语言
- Python(核心为 C++)
- Python 要求
- ≥ 3.10(2.21 移除了 3.9)
- 执行方式
- 默认 eager,可切换图模式
- GPU 支持
- Linux + NVIDIA CUDA(pip 装 [and-cuda])
- macOS GPU 构建
- 无——Apple Silicon 只能 CPU 跑
import tensorflow as tf 换成 import keras,再用 KERAS_BACKEND=jax(或 torch)切后端,同一份模型代码可以在三个框架之间迁移——写法见第 04 节。对初学者的好处是:学 Keras 这一门 API,背后三个引擎都能用。02
安装:一条 pip 走完,GPU 另说
TensorFlow 2.x 只有一个包名 tensorflow。装完验证 tf.__version__ 有输出就说明环境没问题;要不要 GPU,看你的系统和硬件。
# 先升级 pip(TF 对 pip 版本有要求,macOS 要求 pip > 20.3) pip install --upgrade pip # 三个平台通用;macOS 直接装,不需要任何 -macos 后缀包 pip install tensorflow # 验证 python -c "import tensorflow as tf; print(tf.__version__)"
import tensorflow 会打印一屏日志,属正常现象。
# Linux + NVIDIA 显卡:extra 会带上匹配的 CUDA / cuDNN 运行库 pip install tensorflow[and-cuda] # 验证 GPU 是否被认到 python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))" # 输出形如 [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')] 即成功
# 仓库里是 Keras 2 的老代码:装兼容包,让 tf.keras 走回 Keras 2 pip install tf_keras export TF_USE_LEGACY_KERAS=1 # 或者干脆钉住旧版本(不推荐新项目) pip install "tensorflow==2.15.*"
tf.keras 是 Keras 2 API,与 3.x 在导入方式、保存格式上有差异。老代码能兼容跑就行,新项目一律按 Keras 3 写。
03
五分钟上手:8 行代码拟一条直线
不碰图像、不碰 GPU,先用最小例子走完「建模型 → compile → fit → predict」闭环:让一个神经元自己学出 y = 2x + 1 里的系数。跑通它,你就跑通了 TensorFlow 90% 的日常形态。
# python fit_line.py —— CPU 上几秒跑完 import numpy as np import tensorflow as tf x = np.linspace(-1, 1, 200).astype("float32") y = 2 * x + 1 + 0.05 * np.random.randn(200).astype("float32") # 带噪声的观测 model = tf.keras.Sequential([tf.keras.layers.Dense(1)]) # 一行建模型 model.compile(optimizer="sgd", loss="mse") # 三要素配齐 model.fit(x, y, epochs=50, verbose=0) # 静默训练 print(model.predict(tf.constant([0.5]), verbose=0)) # 约 [[2.0]](示意输出)
-
01
准备数据
numpy 数组直接喂给 Keras,它会自己转成 Tensor。注意 dtype 用 float32——TF 的默认计算精度就是它,float64 会报 dtype 不匹配。
-
02
一行建模型
Sequential按顺序堆层。Dense(1)只有一个神经元:权重 w、偏置 b,正是要学的 2 和 1。 -
03
compile 定三要素
优化器怎么走(sgd)、损失怎么算(mse)、要盯什么指标(这次回归任务不需要 metrics)。编译只是配置,不碰数据。
-
04
fit 开训、predict 验收
fit里 epochs 是遍历全数据的次数,verbose=0 静音进度条。训完拿 0.5 去问模型,输出接近 [[2.0]](y = 2×0.5 + 1)就说明学对了。
import tensorflow 打的 CUDA 相关 WARNING 不影响 CPU 训练,可以无视;报 dtype 错误大概率是喂了 float64 的 numpy 数据,转成 float32 即可。想亲眼验证学到了什么:训练完调 model.get_weights(),返回数组里 w ≈ 2、b ≈ 1——一个神经元学一条直线,参数刚好看得清清楚楚。
04
核心概念:Tensor、Tape、tf.data 与建模三式
Tensor 与 Variable:数据和参数
Tensor(张量)是多维数组的统称,是 TF 里一切数据的容器;它是不可变的,算完产生新张量。Variable 是可训练的张量——模型的权重和偏置都是 Variable,训练器的本质就是每步沿着梯度改它。
>>> t = tf.constant([[1.0, 2.0], [3.0, 4.0]]) # 不可变张量 >>> v = tf.Variable([[1.0, 2.0]]) # 可训练变量:模型参数就是它 >>> t.shape, t.dtype (TensorShape([2, 2]), tf.float32) >>> t + 10 # 运算产生新张量,t 本身不变
tf.GradientTape:自动求导
eager 模式下,你在 GradientTape 上下文里做的每一步运算都被录在「磁带」上;出上下文后调 gradient(目标, 变量),它就沿磁带反推导数。手写训练循环全靠它(第 06 节速查表里给了一整段模板)。
>>> x = tf.Variable(3.0) >>> with tf.GradientTape() as tape: ... y = x ** 2 + 2 * x # y = x² + 2x >>> dy_dx = tape.gradient(y, x) # 导数 2x + 2 在 x=3 处 >>> dy_dx.numpy() 8.0
tf.data:把数据变成流水线
数据一多就不能整块塞进内存,tf.data.Dataset 负责把数据变成「边流边喂」的管道:打乱、组批、预处理、预取各一步,链式写完。CPU 准备下一批和 GPU 训练上一批是并行的——prefetch + AUTOTUNE 是官方给的标准姿势,加上后训练速度常有可观提升。
ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)) # 切成一条条样本 ds = ds.shuffle(10000).batch(128).prefetch(tf.data.AUTOTUNE) # 打乱 → 组批 → 预取 model.fit(ds, epochs=5) # Dataset 直接当 fit 输入
训练闭环与自定义训练循环
Keras 把标准闭环封装成四步:compile 配置 → fit 训练 → evaluate 评估 → predict 推理,90% 的任务到这就够了。但当损失函数复杂到 fit 表达不了(GAN 的对抗损失、多任务联合优化)时,就要用 GradientTape 亲手写循环——这也是理解「训练到底在做什么」的最佳练习。
# 自定义训练循环:结构永远不变——前向、求梯度、更新 optimizer = tf.keras.optimizers.Adam(1e-3) ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(64) for epoch in range(10): for xb, yb in ds: with tf.GradientTape() as tape: logits = model(xb, training=True) # 1 前向 loss = tf.keras.losses.sparse_categorical_crossentropy(yb, logits) grads = tape.gradient(loss, model.trainable_variables) # 2 求梯度 optimizer.apply_gradients(zip(grads, model.trainable_variables)) # 3 更新 print(f"epoch {epoch} done") # fit 自带的进度条、回调、验证集都要自己补;先跑通 fit,再按需下探
Keras 建模三式:Sequential / Functional / Subclassing
Sequential 适合「一层接一层」的直筒模型(本页 s3、s6 都在用);Functional 用 Input + 函数式调用拼图,适合多输入多输出、有分支的结构,是工程里最常用的;Subclassing 继承 tf.keras.Model 自己写 call,自由度最高、样板代码也最多。
class MyModel(tf.keras.Model): # 子类化:自由度最高的一式 def __init__(self): super().__init__() self.dense = tf.keras.layers.Dense(10) def call(self, inputs): # 定义数据怎么流过模型 return self.dense(inputs) model = MyModel() model.build(tf.TensorShape([None, 4])) # 子类式要先 build 或跑一次才有形状
选型口诀:直筒用 Sequential,有分叉用 Functional,搞研究要极尽灵活才上 Subclassing。三种方式都接同一套 compile / fit。
05
API 速查:常用的就这几张表
下面这块表格能搜。忘了某个层、某个损失函数叫什么,直接搜 conv、损失、早停、batch 之类的词。
| API | 作用 |
|---|---|
| tf.keras.Sequential([...]) | 按顺序堆层的最简模型容器 |
| tf.keras.Input(shape=...) | 声明输入形状,Functional 建模的入口 |
| tf.keras.Model(inputs, outputs) | 函数式建模,多输入多输出就用它 |
| tf.keras.layers.Dense(64) | 全连接层;activation="relu" 常配 |
| tf.keras.layers.Conv2D(32, 3) | 二维卷积层,图像任务主力 |
| tf.keras.layers.MaxPooling2D() | 最大池化,卷积后降尺寸 |
| tf.keras.layers.Flatten() | 摊平成一维,卷积接全连接的桥 |
| tf.keras.layers.Dropout(0.5) | 训练期随机置零一部分激活,抗过拟合 |
| tf.keras.layers.BatchNormalization() | 批归一化,深网络稳定训练 |
| tf.keras.layers.Embedding(vocab, 16) | ID 序列转稠密向量,文本任务入口层 |
| tf.keras.layers.LSTM(64) | 循环层,序列任务经典选择 |
| model.summary() | 打印每层形状与参数量,建模完先看它 |
| API | 作用 |
|---|---|
| model.compile(optimizer, loss, metrics) | 配置训练三要素,fit 前必调 |
| optimizer="adam" | 字符串简写;细调用 keras.optimizers.Adam(learning_rate=1e-3) |
| optimizer="sgd" | 随机梯度下降;SGD(momentum=0.9) 更稳 |
| metrics=["accuracy"] | fit 过程中顺带计算并汇报的指标列表 |
| loss="sparse_categorical_crossentropy" | 整数标签(0~9)的多分类,最常用 |
| loss="categorical_crossentropy" | one-hot 标签的多分类 |
| loss="binary_crossentropy" | 二分类,输出层配 Dense(1, activation="sigmoid") |
| loss="mse" / "mae" | 回归:均方误差 / 平均绝对误差 |
| model.fit(x, y, epochs, batch_size, validation_split) | 训练主体;validation_split=0.1 划验证集 |
| model.evaluate(x_test, y_test) | 测试集评估,返回 loss 与 metrics 列表 |
| model.predict(x) | 批量推理,返回预测数组 |
| model.save("model.keras") | 全量保存(结构 + 权重 + 优化器状态),load_model 直接恢复 |
| model.export("serving_dir") | 导出纯推理 SavedModel 目录,给 TF Serving 用 |
| keras.models.load_model("model.keras") | 把 .keras 文件原样加载回来 |
| 回调 | 作用 |
|---|---|
| keras.callbacks.EarlyStopping(patience=3) | 验证指标不再变好就提前停训 |
| …restore_best_weights=True | 早停后自动回滚到历史最优权重,常配 |
| keras.callbacks.ModelCheckpoint("best.keras") | 按轮保存;save_best_only=True 只存最优 |
| keras.callbacks.TensorBoard(log_dir="logs") | 写训练曲线日志,可视化 loss / accuracy |
| keras.callbacks.ReduceLROnPlateau(factor=0.5) | 验证损失停滞时自动降学习率 |
| keras.callbacks.CSVLogger("train.log") | 把每轮指标追加写进 CSV |
| keras.callbacks.LearningRateScheduler(fn) | 按 epoch 手工调学习率,fn 返回新 lr |
| keras.callbacks.TerminateOnNaN() | loss 变 NaN 立即停训,排障好帮手 |
| monitor="val_accuracy" | 回调的通用参数:指定盯哪个指标 |
| tensorboard --logdir logs | 命令行起 TensorBoard,浏览器开 localhost:6006 |
| API | 作用 |
|---|---|
| tf.data.Dataset.from_tensor_slices((x, y)) | 从内存数组建数据集,逐条切片 |
| ds.shuffle(buffer_size) | 打乱顺序,buffer 要够大才真乱 |
| ds.batch(32) | 把单条样本组成批 |
| ds.map(fn) | 逐条变换:归一化、resize、数据增强 |
| ds.take(5) | 只取前几条样本,快速试管道用 |
| ds.prefetch(tf.data.AUTOTUNE) | 预取下一批,让 CPU 和 GPU 并行 |
| ds.cache() | 预处理结果缓存到内存,第二轮起省算力 |
| tf.data.AUTOTUNE | 并行度交给运行时自动决定,预取/map 都能用 |
| tf.keras.datasets.fashion_mnist.load_data() | 内置数据集,本页 s6 就用它 |
| tf.config.list_physical_devices("GPU") | 列出 GPU,验证 CUDA 是否生效 |
没有匹配的 API。换个词试试,比如「conv」「损失」「早停」「batch」。
06
实战:Fashion-MNIST 的 CNN 训练全程
Fashion-MNIST 是 MNIST 的「换装版」:同样 6 万训练 + 1 万测试、28×28 灰度图、10 类,但换成 T 恤、裤子、鞋、包等服饰,比手写数字难一点,更适合当教学基准。目标:一个几十 KB 参数的小 CNN,CPU 上几分钟内把测试集准确率练到 0.90 左右。
第 1 步:数据加载与预处理
import tensorflow as tf # 1) 内置数据集:60000 训练 + 10000 测试,28x28 灰度图,10 类 (x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data() # 2) 归一化到 0~1:像素 0~255 直接喂会让 loss 又大又不稳 x_train = x_train / 255.0 x_test = x_test / 255.0 # 3) 加通道维:(60000, 28, 28) -> (60000, 28, 28, 1),Conv2D 要求 4 维输入 x_train = x_train[..., tf.newaxis] x_test = x_test[..., tf.newaxis] print(x_train.shape, y_train.shape) # (60000, 28, 28, 1) (60000,)
第 2 步:用 Functional 方式搭 CNN
# 两轮「卷积 + 池化」提特征,摊平后接全连接出 10 类 inputs = tf.keras.Input(shape=(28, 28, 1)) x = tf.keras.layers.Conv2D(32, 3, activation="relu")(inputs) x = tf.keras.layers.MaxPooling2D()(x) x = tf.keras.layers.Conv2D(64, 3, activation="relu")(x) x = tf.keras.layers.MaxPooling2D()(x) x = tf.keras.layers.Flatten()(x) x = tf.keras.layers.Dropout(0.4)(x) # 小数据集防过拟合 outputs = tf.keras.layers.Dense(10, activation="softmax")(x) model = tf.keras.Model(inputs, outputs) model.summary() # 先看一眼结构与参数量
别被 Conv2D(32, 3) 两个数字迷惑:32 是输出通道数,3 是卷积核边长。卷积核在全图上共享,参数量远小于同规模全连接层——这正是 CNN 适合图像的根本原因。
第 3 步:compile + 回调 + fit
# 标签是 0~9 整数,用 sparse 前缀的交叉熵 model.compile( optimizer=tf.keras.optimizers.Adam(1e-3), loss="sparse_categorical_crossentropy", metrics=["accuracy"], ) callbacks = [ tf.keras.callbacks.EarlyStopping(monitor="val_accuracy", patience=3, restore_best_weights=True), # 不再变好就停 tf.keras.callbacks.ModelCheckpoint("best_model.keras", monitor="val_accuracy", save_best_only=True), # 只存最优 ] history = model.fit( x_train, y_train, epochs=30, # 上限开大,早停会自己收手 batch_size=128, validation_split=0.1, # 留 10% 训练数据当验证集 callbacks=callbacks, )
fit 返回的 history 是个字典,history.history["val_accuracy"] 就是每轮验证准确率——画曲线就用它。训练尾段常见现象:train accuracy 还在涨、val 停滞甚至回落,EarlyStopping 就是在这个拐点上踩刹车。
第 4 步:evaluate、predict 与保存
# 测试集评估(fit 从没见过这 10000 张) test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0) print(f"测试集准确率:{test_acc:.3f}") # 0.90 左右(示意输出) # 单张预测:predict 返回 10 个概率,取最大者当类别 import numpy as np probs = model.predict(x_test[:3], verbose=0) print(probs.argmax(axis=1)) # [9 2 1](示意输出) # 全量保存为 .keras:结构 + 权重 + 优化器状态一起带走 model.save("fashion_mnist_cnn.keras") restored = tf.keras.models.load_model("fashion_mnist_cnn.keras")
第 5 步:用 TensorBoard 看训练曲线
# 在第 3 步的 callbacks 列表里追加一项: callbacks.append(tf.keras.callbacks.TensorBoard(log_dir="logs")) # 训练开跑后,另开一个终端启动看板(浏览器开 http://localhost:6006): # tensorboard --logdir logs —— loss / accuracy 曲线实时刷新
调参时盯着 val 曲线比盯终端数字直观得多——训练损失继续降、验证曲线抬头的那一眼,就是过拟合的现场。
以上准确率与预测数字均为示意输出:CNN 初始化带随机性,同一份代码不同机器的结果会小幅波动。想部署成服务,把 model.save 换成 model.export("serving") 导出 SavedModel,交给 TF Serving 加载即可。
07
避坑:版本、形状、速度与保存
坑一:版本混装,Keras 2 / 3 断代
最常见的环境病:pip install tensorflow 装的是 Keras 3,网上老教程却在用 Keras 2 API,跑起来满屏 AttributeError。2.16 是分水岭:之前 tf.keras 是 Keras 2,之后是 Keras 3。老代码别硬改,用官方兼容层。
pip uninstall tensorflow-macos # 2.16 起不再需要,留着会互相打架 pip install --upgrade --force-reinstall tensorflow pip install tf_keras # Keras 2 兼容包 export TF_USE_LEGACY_KERAS=1 # 让 tf.keras 指回 Keras 2 行为
python -c "import keras; print(keras.__version__)"。版本 3.x 开头就按 Keras 3 语法排查;另外确认同一个虚拟环境里只装了一份 tensorflow——混装 tensorflow、tensorflow-macos、tensorflow-gpu 是历史遗留重灾区。坑二:形状不对、没归一化,loss 不收敛
图像进 Conv2D 必须是 4 维 (批, 高, 宽, 通道),灰度图的通道维要自己补;像素 0~255 直接喂网络,梯度会被大数值搅得来回震荡。这两件事没做,症状都是「几十个 epoch 了 loss 还在 2 以上」。
# 两个修正都齐了再进模型 x = x.astype("float32") / 255.0 # 归一化 x = x[..., tf.newaxis] # (N, 28, 28) -> (N, 28, 28, 1) # 标签是整数就配 sparse_categorical_crossentropy; # 报 sparse/one-hot 相关错误,八成是损失函数跟标签格式配错了对
坑三:训练慢——CPU 全在等数据,或 GPU 没用上
慢有三个惯犯:没建 tf.data 管道(每步都在现场做预处理)、batch 太小(GPU 吃不饱)、GPU 根本没被认到。排查顺序也是这三步。
import tensorflow as tf
print(tf.config.list_physical_devices("GPU"))
# 空列表 = GPU 没生效。Linux:确认装了 tensorflow[and-cuda]、驱动正常;
# WSL2:2.21.0 有 GPU 识别问题(见 GitHub issue #113541),可先用 2.20.0
cache()/prefetch(),别一股脑 np.load 全量进 RAM。坑四:保存了模型,换环境加载报错
两个高频报错都有明确解法:加载 .keras 报 unknown layer——自定义层/子类模型保存时要能被找到(自定义层实现 get_config,加载前先 import 定义它的模块);分不清两种保存——.keras 是给「继续训练 / Python 里复用」的全量格式,model.export() 导出的是纯推理 SavedModel,只喂给 TF Serving 这类部署工具。
# 路线 A:继续训练 / 自己加载推理 model.save("model.keras") m2 = tf.keras.models.load_model("model.keras") # 路线 B:上 TF Serving / 服务器部署(只含推理图) model.export("serving/1") # Serving 端按目录号加载:serving/1, serving/2 … 模型版本管理天然成型
08
进阶:官方文档与部署路线
本页只覆盖训练主线,下面这些是官方入口,按需取用:
- TensorFlow 安装指南 —— 各平台、GPU、虚拟环境的权威说法,版本冲突先查这里。
- 官方教程库 —— 图像分类、NLP、时序、GAN 等成套的 Colab 教程,比任何二手教程都新。
- Keras 3 开发者文档 —— 多后端说明、层与回调的完整 API、迁移指南都在这里。
- GitHub 仓库 —— Release Notes 追版本变化(如 2.21 的 CUDA 变更)。
- TF Serving —— 把 SavedModel 变成高吞吐推理服务的主流方案。
- LiteRT(原 TF Lite) —— 手机、嵌入式端部署;2.20 起 TFLite 已整体迁到 LiteRT 项目,新代码别再从
tf.lite起手。
09
收尾:照着勾一遍
0 / 5