DistilBert二分类预测出现负值及指标计算报错求助
问题原因及修复方案
核心原因解析
- 输入格式不匹配:Recall、Precision等指标要求输入是离散的类别标签(0/1),而你直接传入了模型输出的未归一化logits(包含负值、连续值),指标函数无法正确解析这些值,触发
InvalidArgumentError。 - 模型输出与损失函数不兼容:你的模型输出是双logits(每个样本对应两个类的得分,如
[[8.45632,-8.409305],...]),但使用了针对单输出二分类的BinaryCrossentropy(from_logits=True),这种不匹配会导致输出体系和标签体系的混淆,进一步加剧指标计算的错误。 - AUC指标的输入要求未满足:AUC需要正类的连续得分(概率或logits),但直接传入双logits时,指标函数无法自动识别正类对应的维度,导致解析失败。
修复方案
根据你的模型输出结构,分两种场景处理:
场景1:保留模型双logits输出(最后一层为Dense(2, activation=None))
步骤1:修正损失函数
将BinaryCrossentropy替换为适用于整数标签的多分类损失函数:
import tensorflow as tf model.compile( optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=[tf.keras.metrics.SparseCategoricalAccuracy()] )
步骤2:正确转换输出以计算指标
import numpy as np from sklearn.metrics import recall_score, precision_score, roc_auc_score # 获取模型输出的logits y_pred_logits = model.predict(X_test) y_true = test_labels # 你的0/1整数标签 # 计算Recall、Precision:转换为类别预测(取logits最大值对应的索引) y_pred_labels = np.argmax(y_pred_logits, axis=1) recall = recall_score(y_true, y_pred_labels) precision = precision_score(y_true, y_pred_labels) # 计算AUC:直接使用正类(类别1)的logits作为得分(无需softmax,AUC只关心排序) auc = roc_auc_score(y_true, y_pred_logits[:, 1]) print(f"Recall: {recall:.4f}, Precision: {precision:.4f}, AUC: {auc:.4f}")
场景2:改为单logits输出(更适配BinaryCrossentropy)
步骤1:修改模型最后一层
将最后一层从Dense(2)改为Dense(1, activation=None),输出单个logits值:
from transformers import TFDistilBertModel import tensorflow as tf def build_model(max_len): input_ids = tf.keras.layers.Input(shape=(max_len,), dtype=tf.int32) attention_mask = tf.keras.layers.Input(shape=(max_len,), dtype=tf.int32) distilbert = TFDistilBertModel.from_pretrained('distilbert-base-uncased') outputs = distilbert(input_ids=input_ids, attention_mask=attention_mask) cls_token = outputs.last_hidden_state[:, 0, :] # 改为单输出适配BinaryCrossentropy logits = tf.keras.layers.Dense(1, activation=None)(cls_token) model = tf.keras.Model(inputs=[input_ids, attention_mask], outputs=logits) return model
步骤2:保留BinaryCrossentropy并计算指标
import numpy as np from sklearn.metrics import recall_score, precision_score, roc_auc_score import tensorflow as tf model.compile( optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True) ) # 获取模型输出的单logits y_pred_logits = model.predict(X_test).flatten() y_true = test_labels # 计算Recall、Precision:转换为0/1标签(logits>0对应类别1) y_pred_labels = (y_pred_logits > 0).astype(int) recall = recall_score(y_true, y_pred_labels) precision = precision_score(y_true, y_pred_labels) # 计算AUC:使用sigmoid转换为正类概率,或直接用logits y_pred_prob = tf.sigmoid(y_pred_logits).numpy() auc = roc_auc_score(y_true, y_pred_prob) # 或直接用logits:auc = roc_auc_score(y_true, y_pred_logits) print(f"Recall: {recall:.4f}, Precision: {precision:.4f}, AUC: {auc:.4f}")
额外注意事项
- 如果使用TensorFlow内置的评估指标(如
Recall、Precision),需要在指标内部完成logits到标签/概率的转换,避免直接传入原始logits。 - 无论哪种输出结构,都要确保训练时的损失函数与输出形状、标签格式完全匹配,否则不仅会影响指标计算,还可能导致模型训练效果不佳。
内容的提问来源于stack exchange,提问作者Injarapu Sri Sharanya
相关产品推荐
相关产品推荐

