You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

卷积神经网络训练出现无意义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:07:10