CNN训练首轮出现NaN损失及MAE问题求助(附优化疑问)
解决方案:CNN训练NaN问题及MAE优化
一、解决带BatchNormalization时的NaN问题
出现NaN的核心是训练过程中数值不稳定,结合你的代码和日志,可从以下几点调整:
1. 降低初始学习率
你用的Adam初始学习率0.01远高于默认的0.001,ReLU激活本身易产生大梯度,配合BN的批量统计,极易导致权重更新过大引发数值溢出。修改代码:
modelCNN.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001), loss='mean_absolute_error', metrics=['mae'])
2. 对输入数据做标准化处理
BN依赖批量内数据的均值和方差统计,若输入数据范围过大(比如未归一化的0-255像素值),会导致BN计算的方差过小甚至趋近于0,引发除以0的NaN问题。训练前添加数据归一化:
# 先缩放到0-1,再标准化到均值0、方差1 X_train = X_train / 255.0 X_test = X_test / 255.0 mean = X_train.mean() std = X_train.std() X_train = (X_train - mean) / std X_test = (X_test - mean) / std
3. 调整BatchNormalization超参数
默认epsilon=1e-5太小,批量方差极小时易出问题;momentum=0.99对于TPU大批次可适当调小,让BN更快适应数据分布:
modelCNN.add(tf.keras.layers.BatchNormalization(epsilon=1e-3, momentum=0.9))
4. 优化学习率衰减函数
当前公式在首轮无衰减且速度偏慢,可改成更温和的指数衰减,或从第2轮开始衰减:
def scheduler(epoch, lr): if epoch == 0: return lr # 首轮不衰减 return lr * 0.95 # 每轮衰减5%
5. 检查标签数据是否异常
确认Y_train和Y_test中没有NaN、无穷大或极端值,这些会直接导致Loss计算出现NaN。
二、解决MAE下降慢且不稳定的问题
移除BN后模型稳定性下降,可通过以下方式优化:
1. 对输出标签做归一化
若Y数值范围大(比如几十上百),MAE的Loss值过高会导致优化器难以稳定更新。将Y缩放到0-1或均值0的范围,训练后再反归一化:
# 标签归一化 y_mean = Y_train.mean() y_std = Y_train.std() Y_train = (Y_train - y_mean) / y_std Y_test = (Y_test - y_mean) / y_std # 预测时反归一化 predictions = modelCNN.predict(X_test) * y_std + y_mean
2. 添加正则化与Dropout
防止过拟合导致的MAE震荡,在卷积层和全连接层加入L2正则化或Dropout:
from tensorflow.keras import regularizers # 卷积层加L2正则化 modelCNN.add(tf.keras.layers.Conv2D(100, (8, 8), strides=(2, 2), activation='relu', kernel_regularizer=regularizers.l2(1e-4), input_shape=(256, 256, 1))) # 全连接层前加Dropout modelCNN.add(tf.keras.layers.GlobalMaxPooling2D()) modelCNN.add(tf.keras.layers.Dropout(0.3)) modelCNN.add(tf.keras.layers.Dense(100, activation='relu', kernel_regularizer=regularizers.l2(1e-4)))
3. 调整模型结构
- 减少卷积滤波器数量:第一个Conv2D用64代替100,降低参数规模避免训练震荡;
- 调整池化策略:将第一个MaxPooling的strides从(3,3)改为(2,2),保留更多特征;
- 重新加入BatchNormalization:在解决NaN问题后恢复BN,它本身能稳定训练、降低梯度震荡。
4. 使用自适应学习率回调
替换固定衰减策略,用ReduceLROnPlateau在验证MAE连续不下降时自动降学习率:
lr_schedule = tf.keras.callbacks.ReduceLROnPlateau( monitor='val_mae', factor=0.5, # 每次衰减为原学习率的50% patience=5, # 连续5轮无下降则触发衰减 min_lr=1e-6 # 最小学习率阈值 ) modelCNN.fit(X_train, Y_train, epochs=96, validation_data=(X_test, Y_test), callbacks=[lr_schedule])
5. 增大批量大小
TPU适合大批次训练,增大batch_size(比如256或512,根据TPU内存调整)可让BN统计更准确,梯度更新更稳定:
modelCNN.fit(X_train, Y_train, epochs=96, validation_data=(X_test, Y_test), batch_size=256, callbacks=[lr_schedule])
内容的提问来源于stack exchange,提问作者NikoMolecule
相关产品推荐
相关产品推荐

