TensorFlow训练Loss为NaN且Accuracy为0的问题排查求助
模型训练Loss为NaN、Accuracy维持0.0的问题排查与解决建议
问题背景
训练模型时出现Loss快速变为NaN、Accuracy降至0并维持的异常,相关代码与训练日志如下:
数据加载代码
def load_images_and_labels(folder_path, json_path): with open(json_path, 'r') as json_file: label_data = json.load(json_file) image_data = [] labels = [] boxes = [] for image_info in label_data["images"]: image_id = image_info["id"] # Construct the full path to the file filename = image_info["file_name"] image_path = os.path.join(folder_path, filename) img = cv2.imread(image_path) img_grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Extract all labels and bounding boxes based on the image_id from the JSON data image_annotations = [item for item in label_data["annotations"] if item["image_id"] == image_id] # Check if there are annotations for the image if image_annotations: for annotation in image_annotations: # Extract label and bounding box information image_label = annotation["category_id"] bbox = annotation["bbox"] # Add the image, label, and bounding box to the arrays image_data.append(img_grey) labels.append(image_label) boxes.append(bbox) # Convert the lists to NumPy arrays image_array = np.array(image_data).astype('float32') label_array = np.array(labels) box_array = np.array(boxes).astype('float32') return image_array, label_array, box_array
模型结构与训练代码
input_image = Input(shape=(400, 400), name='image_input') input_bbox = Input(shape=(4,), name='bounding_box_input') # Flachklopfen des Bildes flatten_image = Flatten()(input_image) merged_input = Concatenate()([flatten_image, input_bbox]) x = Dense(64, activation='relu')(merged_input) output_layer = Dense(28, activation='softmax')(x) model = tf.keras.Model(inputs=[input_image, input_bbox], outputs=output_layer) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) # training model.fit({'image_input': train_images, 'bounding_box_input': train_boxes}, train_labels, epochs=10)
训练日志
Epoch 1/10 112/112 [==============================] - 4s 15ms/step - loss: nan - accuracy: 2.8035e-04 Epoch 2/10 112/112 [==============================] - 2s 15ms/step - loss: nan - accuracy: 0.0000e+00 Epoch 3/10 112/112 [==============================] - 2s 15ms/step - loss: nan - accuracy: 0.0000e+00 Epoch 4/10 112/112 [==============================] - 2s 15ms/step - loss: nan - accuracy: 0.0000e+00
已完成排查
- 验证数据与标签的正确性
- 对图像像素值做了归一化处理(
train_images = train_images / 255.0)
潜在原因分析
- 边界框数据未归一化:图像特征已缩放到0-1范围,但边界框是原始像素坐标(0-400),两者数值范围差异极大,拼接后会导致模型权重更新时梯度爆炸,最终Loss变为NaN。
- 类别标签不匹配:
sparse_categorical_crossentropy要求标签是0到num_classes-1的整数(此处应为0-27),若标签从1开始或存在大于等于28的数值,会导致损失计算时出现无效值。 - 数据存在异常值:部分图像读取失败(
cv2.imread返回None)、边界框坐标超出图像范围(如负坐标、宽高为0),会引入NaN或无效值进入训练流程。 - 学习率过高:Adam默认学习率0.001,在输入特征数值差异大的情况下,易引发梯度爆炸,导致权重出现NaN。
可行解决方法
- 归一化边界框数据:将边界框的x、y、w、h均除以图像尺寸(400),缩放到0-1范围,与图像特征数值范围对齐:
box_array = np.array(boxes).astype('float32') / 400.0 - 修正类别标签:检查标签范围,若标签从1开始,统一减1:
同时确认所有标签值在0-27之间,过滤或修正超出范围的标签。label_array = np.array(labels) - 1 - 添加数据校验逻辑:在
load_images_and_labels函数中加入异常检查:# 检查图像是否读取成功 if img is None: print(f"Failed to read image: {image_path}") continue # 检查边界框有效性 x, y, w, h = bbox if x < 0 or y < 0 or w <=0 or h <=0 or x+w > 400 or y+h >400: print(f"Invalid bbox {bbox} for image {image_path}") continue - 降低学习率并添加梯度裁剪:调整Adam优化器参数,限制梯度大小:
optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001, clipnorm=1.0) model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy']) - 检查输入维度匹配:确认
train_images形状为(样本数,400,400),train_boxes为(样本数,4),train_labels为(样本数,),避免维度不匹配导致的计算错误。
内容的提问来源于stack exchange,提问作者metal-lode
相关产品推荐
相关产品推荐

