使用Keras训练CIFAR10数据集的20层DNN时出现NaN Loss问题的求助
Keras训练CIFAR10数据集的20层DNN时出现NaN Loss问题的求助
我在做Aurelien Geron的《Hands-On ML》里的练习,尝试用20层隐藏层的DNN训练CIFAR10数据集,但不管用自己的代码还是抄答案,训练时的loss和val_loss全是NaN,准确率也完全没提升,而且没有任何Python或TensorFlow的报错。以下是我的代码和训练输出:
我的代码
import tensorflow as tf import datetime (X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data() X_val, y_val = X_train[:5000], y_train[:5000] X_train, y_train = X_train[5000:], y_train[5000:] tf.random.set_seed(42) model = tf.keras.Sequential() model.add(tf.keras.layers.Input(shape=[32,32,3])) model.add(tf.keras.layers.Flatten()) ## 20 Hidden layers for _ in range(20): model.add(tf.keras.layers.Dense(100, activation='swish', kernel_initializer='he_normal')) # Output layer model.add(tf.keras.layers.Dense(10, activation='softmax')) optimizer = tf.keras.optimizers.Nadam(learning_rate=5e-6) model.compile(optimizer=opimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy']) early_stopping = tf.keras.callbacks.EarlyStopping(patience=20, restore_best_weights=True) log_dir = "logs/my_cifar10_model/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir) model.fit(X_train, y_train, epochs=100, callbacks=[early_stopping, tensorboard_callback], validation_data=(X_val, y_val))
训练输出
Epoch 1/100 1407/1407 ━━━━━━━━━━━━━━━━━━━━ 8s 3ms/step - accuracy: 0.1005 - loss: nan - val_accuracy: 0.0996 - val_loss: nan Epoch 2/100 1407/1407 ━━━━━━━━━━━━━━━━━━━━ 3s 2ms/step - accuracy: 0.1007 - loss: nan - val_accuracy: 0.0996 - val_loss: nan ... Epoch 21/100 1407/1407 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.1007 - loss: nan - val_accuracy: 0.0996 - val_loss: nan <keras.src.callbacks.history.History at 0x7801cde19fa0>
问题分析与解决方法
我帮你定位到了两个核心问题,修正后模型就能正常训练了:
- 拼写错误导致优化器未正确配置:在
model.compile()里,你把定义好的optimizer拼成了opimizer——这个笔误会让TensorFlow无法识别优化器,直接导致训练逻辑异常,最终出现NaN Loss。 - 缺少数据归一化处理:CIFAR10的图像像素值范围是0-255,直接输入到20层的全连接网络中,会让模型的输入数值过大,极易引发梯度爆炸或数值不稳定,这也是Loss变成NaN的重要原因。我们需要把像素值缩放到0-1的范围。
修正后的完整代码
import tensorflow as tf import datetime (X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data() X_val, y_val = X_train[:5000], y_train[:5000] X_train, y_train = X_train[5000:], y_train[5000:] # 数据归一化:将0-255的像素值缩放到0-1区间 X_train = X_train / 255.0 X_val = X_val / 255.0 X_test = X_test / 255.0 tf.random.set_seed(42) model = tf.keras.Sequential() model.add(tf.keras.layers.Input(shape=[32,32,3])) model.add(tf.keras.layers.Flatten()) ## 20 Hidden layers for _ in range(20): model.add(tf.keras.layers.Dense(100, activation='swish', kernel_initializer='he_normal')) # Output layer model.add(tf.keras.layers.Dense(10, activation='softmax')) optimizer = tf.keras.optimizers.Nadam(learning_rate=5e-6) # 修正拼写错误:opimizer → optimizer model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy']) early_stopping = tf.keras.callbacks.EarlyStopping(patience=20, restore_best_weights=True) log_dir = "logs/my_cifar10_model/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir) history = model.fit(X_train, y_train, epochs=100, callbacks=[early_stopping, tensorboard_callback], validation_data=(X_val, y_val))
额外训练建议
- 调整学习率:你当前用的
5e-6学习率过小,模型收敛会非常慢,可以尝试调到1e-4左右,后续再根据训练的Loss曲线微调。 - 加入Batch Normalization:对于20层的深度全连接网络,建议在每个Dense层后添加
tf.keras.layers.BatchNormalization(),能有效缓解深度网络的数值不稳定问题,让训练更顺畅。 - 可选:添加Dropout层:如果后续出现过拟合,可以在部分Dense层后加入
tf.keras.layers.Dropout(0.2)来提升模型的泛化能力。
备注:内容来源于stack exchange,提问作者vmmgame
相关产品推荐
相关产品推荐

