Keras 常见问题

FreeGuideOnline 最新 2026-07-15

python from tensorflow import keras

from tensorflow.keras import layers


如果需要使用独立版本的多后端 Keras,可通过 `pip install keras` 安装,但该版本现在仅为浅层封装,后端仍然重度依赖 TensorFlow,且更新滞后。**新项目请统一使用 tf.keras。**

### 如何检查是否成功安装并识别 GPU?

使用以下代码快速检测 TensorFlow 和 Keras 版本,以及是否检测到可用 GPU:

```python
import tensorflow as tf
from tensorflow import keras

print("TensorFlow version:", tf.__version__)
print("Keras version:", keras.__version__)
print("GPU Available:", tf.config.list_physical_devices('GPU'))

如果输出中 GPU Available 列表不为空,则 GPU 已被识别。若为空,请检查 CUDA 和 cuDNN 版本是否与 TensorFlow 要求匹配。对于 TensorFlow 2.13 及更高版本,Windows 上原生支持 WSL2 GPU 加速,Linux 上推荐使用官方 Docker 镜像省去环境配置烦恼。

安装后导入出现 DLL 加载失败 / libcudart 缺失?

这类错误通常因 CUDA 运行时库(cudart)未找到或版本不匹配。解决方案:

  1. 使用官方验证的 CUDA/cuDNN 组合,参见 TensorFlow GPU 支持页面
  2. 清理环境变量,确保 PATH 中包含正确 CUDA 库路径。
  3. 重新安装 TensorFlow,使用 pip install tensorflow[and-cuda](Windows 限定的简化安装方式,自动拉取兼容依赖)。
  4. 在 Conda 环境中,使用 conda install -c conda-forge cudatoolkit=<version> cudnn 手动指定版本。

CPU 训练速度很慢,如何开启 GPU 加速?

保证 TensorFlow 安装的是 tensorflow 而不是 tensorflow-cpu。然后确保 NVIDIA 驱动、CUDA Toolkit、cuDNN 版本均满足 TensorFlow 要求。最简单的验证方式是在代码中打开设备日志:

import tensorflow as tf
tf.debugging.set_log_device_placement(True)

a = tf.constant([[1.0, 2.0]])
b = tf.constant([[3.0], [4.0]])
c = tf.matmul(a, b)
print(c)

如果看到类似 Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0 的输出,说明 GPU 已参与计算。

模型构建常见问题

如何选择 Sequential 和 Functional API?

  • Sequential API:适用于简单的线性层堆叠,每层顺序连接,单输入单输出。

    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense
    
    model = Sequential([
        Dense(64, activation='relu', input_shape=(784,)),
        Dense(10, activation='softmax')
    ])
    
  • Functional API:适用于多输入/多输出、共享层、残差连接、有向无环图结构。几乎所有现代模型都可用 Functional API 构建。

    inputs = keras.Input(shape=(784,))
    x = Dense(64, activation='relu')(inputs)
    outputs = Dense(10, activation='softmax')(x)
    model = keras.Model(inputs=inputs, outputs=outputs)
    

若不确定,建议直接使用 Functional API,它完全兼容 Sequential 的写法且功能更强。

Input 层中 shape 和 batch_size 参数的区别?

Input 层的 shape 参数用来指定每个样本的特征维度(不包含批量维度)。例如,对于 28x28 的灰度图像,应写为 shape=(28, 28, 1)

batch_size 参数为可选,如果指定则模型将固定在该批量大小上构建,此后只能以该批量大小进行训练和预测,一般很少使用固定批量构建。绝大多数情况只需指定 shape,让模型接受任意批量大小。

# 推荐:灵活批量
input_tensor = keras.Input(shape=(32,))
# 不常用:固定批量
input_tensor = keras.Input(shape=(32,), batch_size=16)

激活函数应该写在层内部还是单独作为一层?

两种方式等价,但内部参数写法更简洁。Keras 提倡在层构造函数中通过 activation 参数指定激活函数:

# 写法1:内部参数 (推荐)
Dense(64, activation='relu')

# 写法2:单独添加层
Dense(64)
Activation('relu')

特殊情况(如需要对激活前的线性输出做额外处理)才会单独使用激活层。通常选择第一种。

如何构建具有共享层的模型?

使用 Functional API,将同一层对象应用到不同输入张量即可共享其内部权重:

shared_dense = Dense(64, activation='relu')

input_a = keras.Input(shape=(100,))
input_b = keras.Input(shape=(200,))

out_a = shared_dense(input_a)
out_b = shared_dense(input_b)

# 后续合并或分别输出
merged = keras.layers.concatenate([out_a, out_b])

训练时,反向传播会同时更新该共享层的权重。

训练与编译常见问题

loss、metrics 和 loss_weights 是什么关系?

  • loss:训练时用于计算梯度的目标函数,例如 'categorical_crossentropy'
  • metrics:监控指标,不参与训练,仅用于观察模型性能,如 ['accuracy']
  • loss_weights:当模型有多个输出时,可以为每个输出损失分配权重。损失总和为各输出损失乘以其对应权重再相加。
model.compile(
    optimizer='adam',
    loss=['categorical_crossentropy', 'mse'],
    loss_weights=[0.6, 0.4],
    metrics=[['accuracy'], ['mae']]
)

如果只有一个输出,无需指定 loss_weights。

如何处理过拟合?

几种有效策略:

  1. 获取更多数据或使用数据增强(例如图像旋转、平移)。
  2. 使用正则化:在层中添加 kernel_regularizer=keras.regularizers.l2(0.01)
  3. 添加 Dropout 层layers.Dropout(0.5)
  4. 早停法(EarlyStopping)
    callback = keras.callbacks.EarlyStopping(
        monitor='val_loss', patience=5, restore_best_weights=True)
    
  5. 减少模型容量:减少层数或神经元数量。

如何设置动态学习率或学习率衰减?

可以在编译后使用 tf.keras.optimizers.schedules 构建学习率调度:

lr_schedule = keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate=1e-2,
    decay_steps=1000,
    decay_rate=0.96)
optimizer = keras.optimizers.Adam(learning_rate=lr_schedule)
model.compile(optimizer=optimizer, ...)

也可在回调中使用 LearningRateSchedulerReduceLROnPlateau:

keras.callbacks.ReduceLROnPlateau(
    monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6)

训练时出现 NaN loss 或 loss 不下降?

常见原因及排查步骤:

  1. 学习率过大:尝试降低学习率一个数量级。
  2. 输入数据未归一化或含有异常值:确保特征缩放到 [0,1] 或标准化为均值0方差1。
  3. 梯度爆炸:使用梯度裁剪 optimizer = keras.optimizers.Adam(clipnorm=1.0)
  4. 损失函数不适合:分类问题检查标签是否正确,是否使用了正确的损失(如交叉熵对应 one-hot 或整数标签,搭配正确的 from_logits 参数)。
  5. 激活函数导致数值不稳定:例如最后一层用 softmax 配合 from_logits=False;注意 tf.math.log 产生 -inf。

如何在自定义训练循环中使用 Keras 模型?

可以获取模型的可训练变量和梯度计算:

optimizer = keras.optimizers.Adam()
loss_fn = keras.losses.SparseCategoricalCrossentropy()

for x_batch, y_batch in dataset:
    with tf.GradientTape() as tape:
        logits = model(x_batch, training=True)
        loss = loss_fn(y_batch, logits)
    grads = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

注意 training=True 用于保证 Dropout、BatchNormalization 等层处于训练模式。

模型保存与加载相关问题

保存整个模型与仅保存权重的区别?

  • 保存整个模型 (model.save('model.h5')model.save('model.keras')): 同时保存模型架构、权重、训练配置(损失、优化器)以及优化器状态。可直接加载用于恢复训练或推理。
  • 仅保存权重 (model.save_weights('weights.h5')): 仅保存权重数值。加载前必须重新构建与原始模型结构完全相同的模型,然后通过 model.load_weights('weights.h5') 赋值。适用于仅需推理权重或结构代码已保留的场景。

推荐使用 TensorFlow 的 SavedModel 格式tf 格式),可通过 model.save('path_to_savedmodel') 保存,兼容性最好,也便于部署。

保存模型后再加载,预测结果不同或准确率下降?

  1. Dropout/BatchNormalization 的推理模式:保存整个模型时,层的 training 参数状态会保留。加载后调用 predict() 会自动使用推理模式(dropout 关闭,BN 使用移动平均),应该保持一致。
  2. 保存权重再构建模型:确保构建时层的顺序、参数、激活函数完全一致。
  3. 自定义层:必须在加载前通过 custom_objects 提供自定义层的类定义。
    model = keras.models.load_model('model.h5', 
         custom_objects={'MyCustomLayer': MyCustomLayer})
    
  4. 数值精度:在 CPU 与 GPU、不同 TensorFlow 版本间可能有微小浮点差异,通常不影响性能。

如何保存训练检查点并在中断后恢复?

使用 ModelCheckpoint 回调保存最佳模型或定期保存,结合 EarlyStopping

checkpoint = keras.callbacks.ModelCheckpoint(
    'best_model.keras', monitor='val_accuracy', save_best_only=True)
model.fit(..., callbacks=[checkpoint])

从上次中断恢复时,如果保存了完整模型,直接加载继续训练:

model = keras.models.load_model('checkpoint.keras')
model.fit(...)

如果只保存了权重,需重建模型再加载权重,优化器状态会丢失,训练可能从头开始。

数据预处理常见问题

如何将图像、文本、数值数据转化为 Keras 接受的输入?

  • 图像:通常使用 tf.keras.utils.image_dataset_from_directorytf.data.Dataset 从文件读取。
    train_ds = keras.utils.image_dataset_from_directory(
        'data_dir', image_size=(224,224), batch_size=32)
    
  • 文本:使用 TextVectorization 层或 Tokenizer 进行文本向量化。
    vectorizer = layers.TextVectorization(max_tokens=10000, output_sequence_length=200)
    vectorizer.adapt(train_texts)
    
  • 数值数据:直接作为 np.arraytf.constant,注意形状为 (batch, features)

如何使用 tf.data.Dataset 提升训练性能?

tf.data.Dataset 支持并行处理、预取,能有效提高 GPU 利用率:

dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
dataset = dataset.shuffle(buffer_size=1024).batch(32).prefetch(tf.data.AUTOTUNE)