TensorFlow 作为当今最流行、功能最强大的机器学习框架之一,在深度学习领域扮演着举足轻重的角色。自 TensorFlow 2.x 发布以来,其 API 设计更加简洁、易用,并且引入了 Eager Execution(动态图)作为默认执行模式,极大地提升了开发者的效率和模型调试的便利性。
本文将带您深入了解 TensorFlow 2.x 的核心 API,并演示如何使用这些 API 构建一个简单的深度学习模型,帮助您快速上手 TensorFlow 的开发。
一、 TensorFlow 2.x 的核心概念与新特性
在深入 API 之前,理解 TensorFlow 2.x 的几个核心概念和新特性至关重要:
Eager Execution (动态图):
默认启用: TF 2.x 默认开启 Eager Execution,这意味着操作会立即执行,便于调试和交互式开发。这与 TensorFlow 1.x 的静态图(需要先定义计算图,再执行 session)形成鲜明对比。
调试友好: 可以像 Python 代码一样,直接打印张量的值、使用标准 Python 调试器(如 pdb)进行断点调试。
tf.function:
性能优化: 虽然 Eager Execution 易于使用,但对于大型模型,其性能不如静态图。tf.function 装饰器可以将 Python 函数编译成高效的 TensorFlow 计算图,实现性能的飞跃。
自动图形构建: 由 TensorFlow 根据函数体的计算逻辑自动构建计算图,无需手动定义。
tf.keras - 高级 API:
官方集成: Keras 已成为 TensorFlow 的官方高级 API,提供了构建神经网络的模块化、用户友好的接口。
易用性: 模型构建、层定义、损失函数、优化器、指标等都非常直观,降低了深度学习的入门门槛。
tf.data - 数据管道:
高效数据加载: 提供了一个强大的 API,用于构建高效、可扩展的数据输入管道,实现数据的预处理、批处理、shuffle、预取等操作,避免 I/O 成为模型训练的瓶颈。
自动微分 tf.GradientTape:
梯度计算: TensorFlow 2.x 使用 tf.GradientTape API 来自动计算梯度,这是模型训练(反向传播)的关键。
二、 TensorFlow 2.x 核心 API 概览
TensorFlow 2.x 的 API 非常丰富,但以下几个模块是构建模型最常用的:
1. Tensor (张量) - tf.Tensor
张量是 TensorFlow 中最基本的数据结构,类似于 NumPy 的 ndarray。
创建张量:
<PYTHON>
import tensorflow as tf
import numpy as np
# 从 NumPy 数组创建
numpy_array = np.array([1, 2, 3])
tensor_from_numpy = tf.constant(numpy_array)
print(tensor_from_numpy) # tf.Tensor([1 2 3], shape=(3,), dtype=int64)
# 直接创建:标量、向量、矩阵、高维张量
scalar = tf.constant(5)
vector = tf.constant([1., 2., 3.])
matrix = tf.constant([[1, 2], [3, 4]])
tensor_3d = tf.constant([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
张量属性:
shape: 张量的维度。
dtype: 张量的数据类型 (如 tf.float32, tf.int64)。
name: 张量的名称(可选)。
常用张量操作:
形状操作: tf.reshape(), tf.squeeze(), tf.expand_dims()
数学运算: tf.add(), tf.subtract(), tf.multiply(), tf.divide(), tf.square(), tf.sqrt(), tf.reduce_sum(), tf.reduce_mean()
逻辑运算: tf.equal(), tf.greater(), tf.logical_and(), tf.where()
切片与索引: 与 NumPy 类似,tensor[0], tensor[1:3]
类型转换: tf.cast(tensor, dtype)
2. tf.keras - 构建模型的利器
tf.keras 提供了高层次的 API,极大简化了模型构建过程。
模型 (Models):
tf.keras.Sequential: 用于构建线性堆叠的层。
<PYTHON>
model = tf.keras.Sequential([
tf.keras.layers.Dense(64, activation='relu', input_shape=(784,)), # 输入层,784个特征
tf.keras.layers.Dense(64, activation='relu'), # 隐藏层
tf.keras.layers.Dense(10, activation='softmax') # 输出层,10个类别
])
函数式 API (Functional API): 用于构建复杂的、非线性的模型(如多输入/输出模型、共享层模型)。
<PYTHON>
inputs = tf.keras.Input(shape=(784,))
x = tf.keras.layers.Dense(64, activation='relu')(inputs)
outputs = tf.keras.layers.Dense(10, activation='softmax')(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
继承 tf.keras.Model: 可以自定义模型层,完全掌控模型的构建和训练过程。
<PYTHON>
class MyModel(tf.keras.Model):
def __init__(self):
super(MyModel, self).__init__()
self.dense1 = tf.keras.layers.Dense(64, activation='relu')
self.dense2 = tf.keras.layers.Dense(10, activation='softmax')
def call(self, inputs): # 定义前向传播逻辑
x = self.dense1(inputs)
return self.dense2(x)
model = MyModel()
层 (Layers): tf.keras.layers 模块包含各种神经网络层。
核心层:
tf.keras.layers.Dense: 全连接层。
tf.keras.layers.Conv2D: 2D 卷积层(用于图像)。
tf.keras.layers.MaxPooling2D: 2D 最大池化层。
tf.keras.layers.Flatten: 展平层,将多维输入映射为一维。
tf.keras.layers.Dropout: Dropout 层,用于正则化,防止过拟合。
tf.keras.layers.BatchNormalization: 批量归一化层,加速训练并改善稳定性。
tf.keras.layers.Embedding: 词嵌入层,用于处理文本数据。
tf.keras.layers.LSTM, tf.keras.layers.GRU: RNN 层。
激活函数 (Activations): tf.keras.activations 模块,如 relu, sigmoid, softmax, tanh。也可以直接在层中通过 activation='relu' 指定。
损失函数 (Losses): tf.keras.losses 模块,用于衡量模型预测与真实值之间的差距。
tf.keras.losses.CategoricalCrossentropy: 多分类交叉熵。
tf.keras.losses.BinaryCrossentropy: 二分类交叉熵。
tf.keras.losses.MeanSquaredError: 均方误差(用于回归)。
优化器 (Optimizers): tf.keras.optimizers 模块,用于更新模型权重以最小化损失函数。
tf.keras.optimizers.Adam: Adam 优化器(常用)。
tf.keras.optimizers.SGD: 随机梯度下降。
tf.keras.optimizers.RMSprop: RMSprop 优化器。
指标 (Metrics): tf.keras.metrics 模块,用于评估模型性能。
tf.keras.metrics.Accuracy: 准确率。
tf.keras.metrics.Precision, tf.keras.metrics.Recall: 精度和召回率。
tf.keras.metrics.MeanAbsoluteError: 平均绝对误差。
3. 数据管道 - tf.data
目的: 构建高效、可配置的数据加载和预处理流程。
主要组件:
tf.data.Dataset: 表示数据元素的序列。
创建 Dataset:
tf.data.Dataset.from_tensor_slices((features, labels)): 从 NumPy 数组或张量创建。
tf.data.TFRecordDataset(filenames): 从 TFRecord 文件加载。
tf.data.TextLineDataset(filenames): 从文本文件加载。
常用转换操作:
dataset.shuffle(buffer_size): 打乱数据顺序。
dataset.batch(batch_size): 将数据分批。
dataset.map(preprocessing_fn): 对每个元素应用一个预处理函数。
dataset.repeat(num_epochs): 重复数据集多次(用于指定训练轮数)。
dataset.prefetch(buffer_size): 预取数据,在 GPU 计算时加载下一批数据,提高效率。
dataset.cache(): 在第一次迭代后将数据集缓存在内存或文件中,避免重复读取。
示例:
<PYTHON>
# 假设有 num_samples 个样本,每个样本有 features_dim 个特征
x_train = np.random.rand(1000, 784).astype(np.float32)
y_train = np.random.randint(0, 10, 1000)
# 创建 Dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# 数据预处理函数 (例如,可以将数据归一化)
def normalize(features, labels):
features = features * 255.0 # 假设是图像数据,乘255归一化
return features, labels
# 构建数据管道
train_dataset = train_dataset.map(normalize) # 应用预处理
train_dataset = train_dataset.shuffle(1000) # 打乱数据
train_dataset = train_dataset.batch(32) # 分批
train_dataset = train_dataset.prefetch(tf.data.AUTOTUNE) # 预取数据
# 可以在训练循环中迭代这个 dataset
for batch_features, batch_labels in train_dataset:
# ... 模型训练步骤 ...
pass
4. 自动微分 - tf.GradientTape
训练循环中的应用: 在使用自定义训练循环时,tf.GradientTape 是计算模型参数梯度的关键。
<PYTHON>
# 假设 model 是一个 tf.keras.Model 实例
# optimizer 是一个 tf.keras.optimizers 实例
# loss_object 是一个 tf.keras.losses 实例
# dataset 是一个 tf.data.Dataset 实例
# 训练一个 batch
for batch_features, batch_labels in dataset:
with tf.GradientTape() as tape:
predictions = model(batch_features, training=True) # training=True 确保 Dropout/BatchNorm 工作正常
loss = loss_object(batch_labels, predictions)
# 计算梯度
gradients = tape.gradient(loss, model.trainable_variables)
# 应用梯度更新模型权重
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
persistent 参数: 默认情况下,GradientTape 记录的上下文只允许一次梯度计算。如果需要多次计算梯度,需设置 tf.GradientTape(persistent=True)。
watch() 方法: 默认情况下,GradientTape 会自动跟踪它创建过的张量(即 model() 调用过程中产生的中间张量)。如果需要跟踪一个不在计算图中的张量,可以使用 tape.watch(tensor)。
三、 使用 TensorFlow 2.x 构建一个简单的模型
我们将以一个经典的图像分类任务——MNIST 手写数字识别为例,演示如何使用 TensorFlow 2.x 的核心 API 构建一个完整的模型。
1. 数据准备
<PYTHON>
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
# 加载 MNIST 数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 数据预处理:
# 1. 转换为浮点型,并将像素值归一化到 [0, 1]
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
# 2. 展平图像 (MNIST 是 28x28 图像,展平成 784 维向量)
# 不需要显式展平,可以在模型的第一层使用 Flatten
# x_train = x_train.reshape(-1, 28 * 28)
# x_test = x_test.reshape(-1, 28 * 28)
# 3. 独热编码标签 (将数字标签转换为 one-hot 向量)
# 例如,数字 3 变成 [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
num_classes = 10
y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)
# 4. 使用 tf.data 构建数据管道
batch_size = 64
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(10000) # 打乱训练数据
train_dataset = train_dataset.batch(batch_size)
train_dataset = train_dataset.prefetch(tf.data.AUTOTUNE)
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_dataset = test_dataset.batch(batch_size)
test_dataset = test_dataset.prefetch(tf.data.AUTOTUNE)
print(f"x_train shape: {x_train.shape}") # (60000, 28, 28)
print(f"y_train shape: {y_train.shape}") # (60000, 10)
2. 模型构建 (tf.keras.Sequential 方式)
<PYTHON>
# 使用 Sequential API 构建一个简单的全连接神经网络
model_seq = tf.keras.Sequential([
# 输入层 & 第一个隐藏层
tf.keras.layers.Flatten(input_shape=(28, 28)), # 自动处理 28x28 -> 784
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2), # 添加 Dropout 防止过拟合
# 第二个隐藏层
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
# 输出层
tf.keras.layers.Dense(num_classes, activation='softmax') # 10个神经元,softmax 输出概率
])
# 编译模型:配置训练过程
model_seq.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
loss='categorical_crossentropy', # 适用 one-hot 编码的多分类问题
metrics=['accuracy']) # 评估指标
# 查看模型结构
model_seq.summary()
3. 模型构建 (tf.keras.Model 函数式 API 方式)
<PYTHON>
# 使用函数式 API 构建相同的模型
inputs = tf.keras.Input(shape=(28, 28))
x = tf.keras.layers.Flatten()(inputs)
x = tf.keras.layers.Dense(128, activation='relu')(x)
x = tf.keras.layers.Dropout(0.2)(x)
x = tf.keras.layers.Dense(128, activation='relu')(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = tf.keras.layers.Dense(num_classes, activation='softmax')(x)
model_func = tf.keras.Model(inputs=inputs, outputs=outputs)
# 编译模型
model_func.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
model_func.summary()
4. 模型训练
<PYTHON>
# 定义训练参数
epochs = 10
history = model_seq.fit(train_dataset,
epochs=epochs,
validation_data=test_dataset) # 使用测试集进行验证
# 如果不使用 tf.data,可以直接传入 numpy 数组,例如:
# history = model_seq.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(x_test, y_test))
5. 模型评估
<PYTHON>
# 在测试集上评估模型性能
loss, accuracy = model_seq.evaluate(test_dataset)
print(f"Test Loss: {loss}, Test Accuracy: {accuracy}")
6. 模型预测
<PYTHON>
# 进行单样本预测
sample_image = x_test[0:1] # 取第一个测试样本,注意保持 batch 维度
predictions = model_seq.predict(sample_image)
print(f"Prediction probabilities: {predictions}")
# 获取预测类别
predicted_class = tf.argmax(predictions, axis=1).numpy()[0]
print(f"Predicted class: {predicted_class}")
# 真实类别
true_class = tf.argmax(y_test[0]).numpy()
print(f"True class: {true_class}")
7. 使用 tf.function 提升性能 (可选)
对于训练和预测的逻辑,可以封装在 tf.function 中以获得更好的性能。
<PYTHON>
# 定义一个训练步函数
@tf.function
def train_step(images, labels, model, loss_object, optimizer, metric):
with tf.GradientTape() as tape:
predictions = model(images, training=True)
loss = loss_object(labels, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
# 更新指标
metric.update_state(labels, predictions)
return loss
# 定义一个测试步函数
@tf.function
def test_step(images, labels, model, loss_object, metric):
predictions = model(images, training=False) # training=False
t_loss = loss_object(labels, predictions)
metric.update_state(labels, predictions)
return t_loss
# --- 在训练循环中使用 ---
# loss_fn = tf.keras.losses.CategoricalCrossentropy()
# accuracy_metric = tf.keras.metrics.CategoricalAccuracy()
# optimizer = tf.keras.optimizers.Adam()
# for epoch in range(epochs):
# # Reset metrics at the start of each epoch
# accuracy_metric.reset_states()
# train_loss_avg = tf.keras.metrics.Mean()
# print(f"Epoch {epoch+1}/{epochs}")
# for batch_images, batch_labels in train_dataset:
# loss = train_step(batch_images, batch_labels, model_seq, loss_fn, optimizer, accuracy_metric)
# train_loss_avg.update_state(loss) # Accumulate batch losses
# print(f" Train Loss: {train_loss_avg.result():.4f}, Train Accuracy: {accuracy_metric.result():.4f}")
# # ----------------- Validation -----------------
# test_accuracy_metric = tf.keras.metrics.CategoricalAccuracy()
# test_loss_avg = tf.keras.metrics.Mean()
# for test_images, test_labels in test_dataset:
# t_loss = test_step(test_images, test_labels, model_seq, loss_fn, test_accuracy_metric)
# test_loss_avg.update_state(t_loss)
# print(f" Validation Loss: {test_loss_avg.result():.4f}, Validation Accuracy: {test_accuracy_metric.result():.4f}")
注意: 使用 tf.function 时,需要将模型编译(model.compile)相关的配置(优化器、损失函数、指标)解耦,并自己实现训练循环。model.fit() 内部已经做了很多优化,对于初学者,直接使用 model.fit() 是更简单高效的选择。tf.function 更多用于自定义训练循环的场景,以获得极致性能。
四、 模型的保存与加载
训练好的模型可以保存下来,以便后续复用或部署。
保存模型 (SavedModel 格式):
<PYTHON>
# 保存整个模型,包括权重、结构、优化器状态
model_seq.save("my_mnist_model_savedmodel")
# 可以用 tf.keras.models.load_model() 加载
loaded_model = tf.keras.models.load_model("my_mnist_model_savedmodel")
loaded_model.summary()
保存权重 only:
<PYTHON>
# 保存模型权重
model_seq.save_weights("my_mnist_model_weights.h5") # .h5 是 Keras 默认格式
# 需要先创建模型结构,再加载权重
# new_model = ... # 创建一个与原模型结构相同的模型
# new_model.load_weights("my_mnist_model_weights.h5")
五、 总结
TensorFlow 2.x 提供了一套强大而易用的 API,通过 Eager Execution、tf.keras、tf.data 等特性,极大地简化了深度学习模型的构建和训练过程。
本文介绍了:
核心概念: Eager Execution, tf.function, tf.keras, tf.data, tf.GradientTape。
核心 API:
tf.Tensor 的创建与操作。
tf.keras 中的 Model (Sequential, Functional, Subclassing), Layers, Losses, Optimizers, Metrics。
tf.data 的构建高效数据管道。
tf.GradientTape 在自定义训练循环中的应用。
模型构建实战: 基于 MNIST 数据集,演示了如何使用 tf.keras.Sequential 和函数式 API 构建、编译、训练、评估和预测。
模型保存与加载: 介绍了 SavedModel 和权重only的保存方式。
通过学习和实践,您应该能够掌握 TensorFlow 2.x 构建基础深度学习模型的能力。接下来,您可以尝试更复杂的模型结构、更丰富的数据集,或者探索 TensorFlow 提供的更高级功能,如自定义层、自定义训练循环、模型部署等,进一步深化对 TensorFlow 的理解。