TensorFlow Keras类别精度计算报错:重复指标名称acc1
问题:编译Keras模型时出现重复指标名称错误
在训练数据上计算类别级准确率,已安装最新版TensorFlow和Keras,但编译模型时抛出错误:ValueError: Found two metrics with the same name: acc1
错误信息
raise ValueError('Found two metrics with the same name: {}'.format( ValueError: Found two metrics with the same name: acc1
相关代码
resnet_model.summary() from keras import backend as K #interesting_class_id = 0 # Choose the class of interest def single_class_accuracy(interesting_class_id): def acc1(y_true, y_pred): class_id_true = K.argmax(y_true) class_id_preds = K.argmax(y_pred) accuracy_mask = K.cast(K.equal(class_id_preds, interesting_class_id), 'int32') class_acc_tensor = K.cast(K.equal(class_id_true, class_id_preds), 'int32') * accuracy_mask class_acc = K.cast(K.sum(class_acc_tensor), 'float32') / K.cast(K.maximum(K.sum(accuracy_mask), 1), 'float32') return class_acc return acc1 def single_class_recall(interesting_class_id): def recall(y_true, y_pred): class_id_true = K.argmax(y_true, axis=-1) class_id_pred = K.argmax(y_pred, axis=-1) recall_mask = K.cast(K.equal(class_id_true, interesting_class_id), 'int32') class_recall_tensor = K.cast(K.equal(class_id_true, class_id_pred), 'int32') * recall_mask class_recall = K.cast(K.sum(class_recall_tensor), 'float32') / K.cast(K.maximum(K.sum(recall_mask), 1), 'float32') return recall return recall def single_class_precision(interesting_class_id): def prec(y_true, y_pred): class_id_true = K.argmax(y_true, axis=-1) class_id_pred = K.argmax(y_pred, axis=-1) precision_mask = K.cast(K.equal(class_id_pred, interesting_class_id), 'int32') class_prec_tensor = K.cast(K.equal(class_id_true, class_id_pred), 'int32') * precision_mask class_prec = K.cast(K.sum(class_prec_tensor), 'float32') / K.cast(K.maximum(K.sum(precision_mask), 1), 'float32') return class_prec return prec resnet_model.compile(optimizer=Adam(lr=0.01),loss='binary_crossentropy',metrics=[ 'accuracy', single_class_accuracy(0), single_class_accuracy(1), single_class_recall(0), single_class_recall(1), single_class_precision(0), single_class_precision(1) ]) resnet_model.save('my_model') history = resnet_model.fit(train_ds, validation_data=val_ds, epochs=20)
解决方案
问题根源
调用single_class_accuracy(0)和single_class_accuracy(1)时,返回的内部函数名称都是acc1,Keras默认用函数名作为指标的唯一标识,导致重复命名冲突。同理,single_class_recall和single_class_precision也存在相同隐患。
两种修复方法
方法1:给内部函数设置唯一名称
修改自定义指标函数,为每个返回的内部函数添加包含类别ID的唯一名称:
def single_class_accuracy(interesting_class_id): def acc(y_true, y_pred): class_id_true = K.argmax(y_true) class_id_preds = K.argmax(y_pred) accuracy_mask = K.cast(K.equal(class_id_preds, interesting_class_id), 'int32') class_acc_tensor = K.cast(K.equal(class_id_true, class_id_preds), 'int32') * accuracy_mask class_acc = K.cast(K.sum(class_acc_tensor), 'float32') / K.cast(K.maximum(K.sum(accuracy_mask), 1), 'float32') return class_acc # 设置唯一函数名 acc.__name__ = f'single_class_acc_{interesting_class_id}' return acc def single_class_recall(interesting_class_id): def recall(y_true, y_pred): class_id_true = K.argmax(y_true, axis=-1) class_id_pred = K.argmax(y_pred, axis=-1) recall_mask = K.cast(K.equal(class_id_true, interesting_class_id), 'int32') class_recall_tensor = K.cast(K.equal(class_id_true, class_id_pred), 'int32') * recall_mask class_recall = K.cast(K.sum(class_recall_tensor), 'float32') / K.cast(K.maximum(K.sum(recall_mask), 1), 'float32') return class_recall recall.__name__ = f'single_class_recall_{interesting_class_id}' return recall def single_class_precision(interesting_class_id): def prec(y_true, y_pred): class_id_true = K.argmax(y_true, axis=-1) class_id_pred = K.argmax(y_pred, axis=-1) precision_mask = K.cast(K.equal(class_id_pred, interesting_class_id), 'int32') class_prec_tensor = K.cast(K.equal(class_id_true, class_id_pred), 'int32') * precision_mask class_prec = K.cast(K.sum(class_prec_tensor), 'float32') / K.cast(K.maximum(K.sum(precision_mask), 1), 'float32') return class_prec prec.__name__ = f'single_class_prec_{interesting_class_id}' return prec
方法2:编译时用字典指定指标名称
无需修改指标函数,直接在compile的metrics参数中用字典自定义每个指标的名称,键为唯一名称,值为指标函数:
resnet_model.compile(optimizer=Adam(learning_rate=0.01), loss='binary_crossentropy', metrics={ 'accuracy': 'accuracy', 'class_0_acc': single_class_accuracy(0), 'class_1_acc': single_class_accuracy(1), 'class_0_recall': single_class_recall(0), 'class_1_recall': single_class_recall(1), 'class_0_prec': single_class_precision(0), 'class_1_prec': single_class_precision(1) })
这种方式更直观,能直接控制训练日志中显示的指标名称,推荐使用。
额外提示
- TensorFlow 2.x+版本中,
Adam(lr=0.01)已弃用,需改为Adam(learning_rate=0.01),避免警告。 - 当前使用
binary_crossentropy损失,但指标计算中调用了K.argmax,若为二分类任务,输出应为单节点sigmoid,此时K.argmax会因维度不匹配报错;若为多分类任务,建议改用categorical_crossentropy或sparse_categorical_crossentropy,需确认标签格式与损失函数匹配。
内容的提问来源于stack exchange,提问作者Monika Roopak
相关产品推荐
相关产品推荐

