卷积神经网络训练出现无意义NaN损失,求排查优化方案
问题描述
我正在搭建一个用于图像分类(矩形/圆形)及边界框检测的神经网络,基于tensorflow.keras使用人工生成的图像数据集开展训练。目前遇到的核心问题是训练损失值趋于NaN这类无意义数值,尝试添加/移除网络层、调整神经元数量、更换优化器及损失函数均无改善,恳请提供解决方案。
核心代码片段
1. 初始化基础参数
blank=255*np.ones(shape=(200,200,1),dtype='uint8') shapes=['rect','circle'] inputShape=blank.shape
2. 生成训练数据集
x_train,y_train=[],[] for i in range(0,1000): img=blank.copy() shapeChoice=choice(shapes) if shapeChoice=='rect': x1,y1=randrange(50,100),randrange(50,100) x3,y3=x1+randrange(10,50),y1+randrange(10,50) xc,yc,h,w=x1/2+x3/2,y1/2+y3/2,x3-x1,y3-y1 img=cv2.rectangle(img,(x1,y1),(x3,y3),0,-1) y_train.append([1,0,xc,yc,w,h]) if shapeChoice=='circle': xc,yc,R=randrange(50,100),randrange(50,100),randrange(10,50) img=cv2.circle(img,(xc,yc),R,0,-1) y_train.append([0,1,xc,yc,R,R]) x_train.append(img) x_train=np.array(x_train,dtype='uint8') y_train=np.array(y_train,dtype='uint8') x_train=x_train/255 outputUnits=sum(y_train[0].shape)
3. 构建模型与训练
cnn = models.Sequential([ layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu', input_shape=inputShape), layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu'), layers.Conv2D(filters=16, kernel_size=(3, 3), activation='relu'), layers.Conv2D(filters=8, kernel_size=(3, 3), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Conv2D(filters=4, kernel_size=(2, 2), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(16*outputUnits, activation='relu'), layers.Dense(8*outputUnits, activation='relu'), layers.Dense(4*outputUnits, activation='relu'), layers.Dense(2*outputUnits, activation='relu'), layers.Dense(outputUnits, activation='softmax')]) cnn.compile(optimizer=optimizers.Adam(learning_rate=0.1,beta_1=0.9,beta_2=0.99), loss='categorical_crossentropy', metrics=['accuracy']) history=cnn.fit(x_train, y_train, epochs=5,batch_size=5)
训练输出
Epoch 1/5 200/200 [==============================] - 22s 15ms/step - loss: nan - accuracy: 0.0510 Epoch 2/5 200/200 [==============================] - 3s 15ms/step - loss: nan - accuracy: 0.0000e+00 Epoch 3/5 200/200 [==============================] - 3s 16ms/step - loss: nan - accuracy: 0.0000e+00 Epoch 4/5 200/200 [==============================] - 3s 15ms/step - loss: nan - accuracy: 0.0000e+00 Epoch 5/5 200/200 [==============================] - 3s 15ms/step - loss: nan - accuracy: 0.0000e+00
解决方案
1. 修正任务与损失/激活函数的匹配问题
你的任务是分类+回归混合任务(前2位是分类标签,后4位是边界框回归数值),但当前用的categorical_crossentropy仅适用于分类,softmax激活会把所有输出压缩到0-1范围,完全不符合回归需求,直接导致损失计算异常。
- 拆分模型输出:用多分支结构,一个分支输出分类结果(2个神经元,softmax激活+交叉熵损失),另一个分支输出边界框回归结果(4个神经元,线性激活+MSE损失),最终损失为两类损失的加权和。
- 若坚持单输出层,需将激活函数改为
linear,损失函数使用分类损失(如binary_crossentropy)+回归损失(如MSE)的组合。
2. 降低学习率
Adam优化器的默认学习率是0.001,你设置的0.1过大,会导致权重更新幅度过大,直接引发数值溢出变成NaN。
- 将学习率改为
0.001或更小,比如:optimizers.Adam(learning_rate=0.001)
3. 修正标签数据类型
你将y_train强制转为uint8,但标签中包含浮点数(如xc = x1/2 + x3/2的计算结果),转成整数会截断小数部分丢失信息,同时浮点数训练与整数标签不匹配容易引发数值问题。
- 删除
y_train=np.array(y_train,dtype='uint8')这行代码,让标签保持浮点类型。
4. 归一化回归标签
边界框的坐标、宽高数值范围是50-150,和分类标签(0/1)尺度差异极大,会导致梯度更新失衡,引发NaN。
- 将回归标签(后4位)归一化到0-1范围,比如除以图像尺寸200:
# 矩形情况 y_train.append([1,0,xc/200,yc/200,w/200,h/200]) # 圆形情况 y_train.append([0,1,xc/200,yc/200,R/200,R/200])
5. 简化冗余网络结构
你用了4层全连接层且神经元数量倍数过高,容易引发梯度爆炸/消失,尤其是在学习率过高的情况下。
- 简化全连接部分,比如只保留1-2层:
layers.Flatten(), layers.Dense(64, activation='relu'), layers.Dense(outputUnits, activation='linear') # 回归任务用线性激活
6. 检查数据有效性
训练前确认数据集无NaN或无穷大值,避免输入数据本身导致异常:
print(np.isnan(x_train).any()) print(np.isnan(y_train).any()) print(np.isinf(x_train).any()) print(np.isinf(y_train).any())
内容的提问来源于stack exchange,提问作者Vishnu Balaji
相关产品推荐
相关产品推荐

