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

为何keras.metrics.TruePositives会出现小数?CNN训练异常排查

Keras分类指标出现小数且总和不符问题解决

问题描述

在图像数据集上训练二分类CNN模型时,使用tf.keras.metrics.TruePositives、TrueNegatives、FalsePositives、FalseNegatives这四个指标,出现两个异常:

  1. 指标数值为小数(如true_positives显示437.6487);
  2. tp+tn+fp+fn的总和与样本总数(1146)不匹配。

错误示例

Epoch 1/3
36/36 ━━━━━━━━━━━━━━━━━━━━ 69s 2s/step - false_negatives: 30.1351 - false_positives: 35.3784 - loss: 2.1995 - true_negatives: 389.0540 - true_positives: 437.6487

完整代码

import pandas as pd
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator

from tensorflow.keras.layers import Dense,Flatten,InputLayer,Conv2D,MaxPooling2D,Concatenate,Input,BatchNormalization
from tensorflow.keras.models import Sequential,Model
from tensorflow.keras.losses import BinaryCrossentropy,CategoricalCrossentropy
from tensorflow.keras.optimizers import Adam
import matplotlib.pyplot as plt
from tensorflow.keras.models import Model
from sklearn.metrics import classification_report
from tensorflow.keras.callbacks import EarlyStopping

datagen=ImageDataGenerator(rescale=1.0/255.0)
train_gen=datagen.flow_from_directory('train',class_mode='binary',
                                      target_size=(224,224),batch_size=32,shuffle=True)

# 输出:Found 1146 images belonging to 2 classes.

tp = tf.keras.metrics.TruePositives()
tn = tf.keras.metrics.TrueNegatives()
fp = tf.keras.metrics.FalsePositives()
fn = tf.keras.metrics.FalseNegatives()
tp.update_state([0.4, .9, .7, .8], [1.0, 0.0, 1.0, 1.0])
tp.result()

# 输出:<tf.Tensor: shape=(), dtype=float32, numpy=3.0>

model_input=Input(shape=(224,224,3))

x=Conv2D(filters=32, kernel_size=(3,3),activation='relu',padding='valid')(model_input)
x=MaxPooling2D(pool_size=(2,2),strides=2)(x)
x=Conv2D(filters=64, kernel_size=(3,3),activation='relu',padding='valid')(x)
x=MaxPooling2D(pool_size=(2,2),strides=2)(x)
x=BatchNormalization()(x)
x=Conv2D(filters=64, kernel_size=(3,3),activation='relu',padding='valid')(x)
x=MaxPooling2D(pool_size=(2,2),strides=2)(x)
x=BatchNormalization()(x)
x=Flatten()(x)
x=Dense(units=1000,activation='relu')(x)
output=Dense(units=1,activation='sigmoid')(x)
model=Model(inputs=model_input,outputs=output)

model.compile(optimizer=Adam(),loss=BinaryCrossentropy(),metrics=[tp,fp,fn,tn])
early_stopping = EarlyStopping(monitor='val_loss', patience=2,restore_best_weights=True)

history=model.fit(x=train_gen,epochs=3,callbacks=[early_stopping])

问题原因

  1. 指标状态被提前污染:你手动调用了tp.update_state()给指标初始化了测试数据的状态,训练时指标会在这个基础上继续累加计算,导致最终数值偏离真实样本的统计结果。
  2. 训练时显示的是加权平均值:Keras在训练过程中显示的指标值是每个batch的加权平均值(因为最后一个batch的样本数可能不等于设置的batch_size,比如1146=32*35+26,最后一个batch只有26个样本),而非累计的整数总数,所以会出现小数。

解决方案

方案1:移除测试用的指标更新代码

直接删掉以下测试代码,确保指标从初始干净的状态开始训练:

tp.update_state([0.4, .9, .7, .8], [1.0, 0.0, 1.0, 1.0])
tp.result()

方案2:重置指标状态

如果需要保留测试代码,在编译模型前手动重置所有指标的状态:

tp.reset_states()
tn.reset_states()
fp.reset_states()
fn.reset_states()

方案3:获取累计整数指标

如果想查看训练全程的累计整数指标,可以在训练结束后手动调用每个指标的result()方法:

print("True Positives:", tp.result().numpy())
print("True Negatives:", tn.result().numpy())
print("False Positives:", fp.result().numpy())
print("False Negatives:", fn.result().numpy())

此时得到的会是整数,且总和等于样本总数。

内容的提问来源于stack exchange,提问作者Vinayak Bansal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:39:49