TensorFlow Keras回归网络拟合训练数据时loss为nan问题排查
回归网络损失为nan的未排查原因及修复方案
你当前代码的核心隐含问题
你写的空值检测断言assert not np.nan in X_train完全无效:因为np.nan不等于任何值,包括自身,所以np.nan in X_train永远返回False,无法检测到数据中的空值,正确的检测逻辑是assert not np.isnan(X_train).any(),同时你没有对标签y做空值检测。
其他未排查的可能原因
- 正则化参数设置异常:直接传入字符串
l1调用正则化时,Keras会使用默认的0.01作为正则化系数,在你使用小学习率SGD的场景下,很容易导致权重更新异常,配合死ReLU神经元会进一步引发数值溢出为nan。 - 版本兼容性bug:Keras 2.4.0对应的TensorFlow 2.3/2.4版本中,SGD优化器搭配
clipvalue参数存在已知的数值计算bug,会导致梯度计算异常。 - 死ReLU累积:当输入存在极端值、初始化不合适时,ReLU神经元会永久失活(输出永远为0,梯度永远为0),失活占比过高时会导致梯度传递异常,最终损失变为nan。
- GPU环境兼容性问题:如果使用GPU训练,CUDA、CUDNN版本和TensorFlow版本不匹配时,会出现浮点计算错误,生成nan。
- 标签维度不匹配:你打印的初始y_train形状是(11610,),reshape为二维后极少数旧版本Keras可能出现广播异常,导致计算错误。
修复方案
按以下优先级逐步验证:
- 替换空值检测逻辑,同时对标签y做空值校验,确认数据无空值
- 先去掉L1正则化参数,验证是否是正则化导致的问题,若需保留正则化可手动指定小系数:
kernel_regularizer=keras.regularizers.L1(1e-6) - 去掉SGD的
clipvalue参数,或者换成Adam优化器 - 将ReLU替换为LeakyReLU/PReLU,避免死神经元问题
- 强制使用CPU运行,排查GPU环境兼容性问题
可正常运行的修改后代码
from sklearn.datasets import fetch_california_housing from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from tensorflow import keras import numpy as np import os # 强制CPU运行,排查GPU兼容性问题 os.environ["CUDA_VISIBLE_DEVICES"] = "-1" housing = fetch_california_housing() X_train_full, X_test, y_train_full, y_test = train_test_split(housing.data, housing.target, random_state=42) X_train, X_valid, y_train, y_valid = train_test_split(X_train_full, y_train_full, random_state=42) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_valid = scaler.transform(X_valid) X_test = scaler.transform(X_test) # 正确的空值检测逻辑 assert not np.isnan(X_train).any() assert not np.isnan(X_valid).any() assert not np.isnan(y_train).any() assert not np.isnan(y_valid).any() scalery = StandardScaler() y_train = scalery.fit_transform(y_train.reshape(-1, 1)) y_valid = scalery.transform(y_valid.reshape(-1, 1)) y_test = scalery.transform(y_test.reshape(-1, 1)) # 替换为LeakyReLU避免死神经元,先去掉正则化验证 model = keras.models.Sequential([ keras.layers.Dense(30, activation=keras.layers.LeakyReLU(alpha=0.1), input_shape=X_train.shape[1:], kernel_initializer="he_uniform"), keras.layers.Dense(1) ]) # 改用Adam优化器,移除clipvalue optimizer = keras.optimizers.Adam(learning_rate=1e-4) model.compile(loss=keras.losses.MeanSquaredError(), optimizer=optimizer) history = model.fit(X_train[:200], y_train[:200], epochs=5, validation_data=(X_valid[:20], y_valid[:20]))
内容的提问来源于stack exchange,提问作者Simanamis
相关产品推荐
相关产品推荐

