为何keras.metrics.TruePositives会出现小数?CNN训练异常排查
Keras分类指标出现小数且总和不符问题解决
问题描述
在图像数据集上训练二分类CNN模型时,使用tf.keras.metrics.TruePositives、TrueNegatives、FalsePositives、FalseNegatives这四个指标,出现两个异常:
- 指标数值为小数(如true_positives显示437.6487);
- 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])
问题原因
- 指标状态被提前污染:你手动调用了
tp.update_state()给指标初始化了测试数据的状态,训练时指标会在这个基础上继续累加计算,导致最终数值偏离真实样本的统计结果。 - 训练时显示的是加权平均值: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
相关产品推荐
相关产品推荐

