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

DistilBert二分类遇InvalidArgumentError及指标计算问题求助

问题

基于DistilBert的二分类项目(垃圾短信/IMDB数据集均复现问题),计算召回率、精确率和AUC时触发InvalidArgumentError,错误信息如下:

InvalidArgumentError: predictions must be >= 0
Condition x >= y did not hold.
First 3 elements of x:
[-9.  9. -9.]
First 1 elements of y:
[0.]

模型使用BinaryCrossentropy(from_logits=True)损失函数与Adam优化器,预测输出为[-9., 9.]这类负值(本应是类别概率),在计算召回率步骤触发错误。数据集标签已做One-hot编码(0代表正常短信,1代表垃圾短信),完整代码如下:

import pandas as pd
import tensorflow as tf
import transformers
from transformers import DistilBertTokenizer
from transformers import TFAutoModelForSequenceClassification
pd.set_option('display.max_colwidth', None)
MODEL_NAME = 'distilbert-base-uncased'
BATCH_SIZE = 8
N_EPOCHS = 3

train = pd.read_csv("train_set.csv", error_bad_lines=False)
test = pd.read_csv("test_set.csv", error_bad_lines=False)

X_train = train.text
X_test = test.text
y_train = train.label
y_test = test.label

#One-hot encoding of labels
y_train_encoded = tf.one_hot(y_train.values, 2)
y_test_encoded = tf.one_hot(y_test.values, 2)

tokenizer = DistilBertTokenizer.from_pretrained(MODEL_NAME)

train_encodings = tokenizer(list(X_train.values),
                        truncation=True, 
                        padding=True)
test_encodings = tokenizer(list(X_test.values),
                       truncation=True, 
                       padding=True)

train_dataset = tf.data.Dataset.from_tensor_slices((dict(train_encodings),list(y_train_encoded)))

test_dataset = tf.data.Dataset.from_tensor_slices((dict(test_encodings),list(y_test_encoded)))
test_dataset2 = test_dataset.shuffle(buffer_size=1024).take(1000).batch(16)

model = TFAutoModelForSequenceClassification.from_pretrained(MODEL_NAME)

optimizerr = tf.keras.optimizers.Adam(learning_rate=5e-5)

losss = tf.keras.losses.BinaryCrossentropy(from_logits=True)

model.compile(optimizer=optimizerr,
          loss=losss,
          metrics=['accuracy'])

print("Evaluate Base model on test data")
results = model.evaluate(test_dataset2)
print("test loss, test acc:", results)

model.fit(train_dataset.shuffle(len(X_train)).batch(BATCH_SIZE),
      epochs=N_EPOCHS,
      batch_size=BATCH_SIZE)

predictions = model.predict(test_dataset2)
# predictions = TFSequenceClassifierOutput(loss=None, logits=array([[-8.96754 ,  8.966875],....[-8.970767,  8.975923]], dtype=float32), hidden_states=None, attentions=None)

import numpy as np
rounded_predictions = np.rint(predictions.logits)
# rounded_predictions = array([[-9.,  9.],....[-9.,  9.]], dtype=float32)

y_test_encoded
#y_test_encoded = <tf.Tensor: shape=(1930, 2), dtype=float32, numpy=array([[1., 0.],....[0., 1.]], dtype=float32)>

m = tf.keras.metrics.Recall()
m.update_state(y_test_encoded, rounded_predictions)
m.result().numpy()
# This is where I getting the above mentioned error.
解决方案

核心问题分析

模型输出的是logits(原始预测值,未经过激活函数转换),不是0-1区间的概率值。直接对logits取整会得到负值,而TensorFlow的召回率等指标要求输入必须是合法的概率或类别标签,因此触发错误。


1. 将Logits转换为类别概率

由于使用了BinaryCrossentropy(from_logits=True),需要通过Softmax激活函数将logits转换为符合要求的类别概率(二分类+One-hot标签场景下,Softmax适配性更好):

# 替换原预测处理代码
from tensorflow.keras.activations import softmax

# 将logits转换为0-1区间的概率
pred_probs = softmax(predictions.logits, axis=1).numpy()

2. 生成合法输入计算指标

召回率、精确率计算

需要将One-hot编码的真实标签转回一维标签,同时从概率中生成预测标签(取概率最大的类别):

# 真实标签:从One-hot转回一维(0=正常,1=垃圾)
true_labels = np.argmax(y_test_encoded, axis=1)
# 预测标签:取概率最大的类别索引
pred_labels = np.argmax(pred_probs, axis=1)

# 计算召回率
recall_metric = tf.keras.metrics.Recall()
recall_metric.update_state(true_labels, pred_labels)
print(f"召回率: {recall_metric.result().numpy():.4f}")

# 计算精确率
precision_metric = tf.keras.metrics.Precision()
precision_metric.update_state(true_labels, pred_labels)
print(f"精确率: {precision_metric.result().numpy():.4f}")

AUC值计算

AUC需要输入正类(垃圾短信,类别1)的概率值,直接取概率数组的第二列即可:

# 提取类别1的概率值
pos_probs = pred_probs[:, 1]
# 计算AUC
auc_metric = tf.keras.metrics.AUC()
auc_metric.update_state(true_labels, pos_probs)
print(f"AUC值: {auc_metric.result().numpy():.4f}")

3. 可选:编译时直接添加指标

如果不想手动计算,可在模型编译阶段直接指定需要的指标,训练/评估时自动输出结果:

model.compile(
    optimizer=optimizerr,
    loss=losss,
    metrics=['accuracy', tf.keras.metrics.Recall(), tf.keras.metrics.Precision(), tf.keras.metrics.AUC()]
)

# 评估时直接获取所有指标结果
results = model.evaluate(test_dataset2)
print("测试集指标结果:", dict(zip(model.metrics_names, results)))

完整修改后的预测与指标计算代码片段

predictions = model.predict(test_dataset2)

# 转换logits为类别概率
pred_probs = tf.keras.activations.softmax(predictions.logits, axis=1).numpy()

# 转换标签格式
true_labels = np.argmax(y_test_encoded, axis=1)
pred_labels = np.argmax(pred_probs, axis=1)
pos_probs = pred_probs[:, 1]

# 计算召回率
recall = tf.keras.metrics.Recall()
recall.update_state(true_labels, pred_labels)
print(f"召回率: {recall.result().numpy():.4f}")

# 计算精确率
precision = tf.keras.metrics.Precision()
precision.update_state(true_labels, pred_labels)
print(f"精确率: {precision.result().numpy():.4f}")

# 计算AUC
auc = tf.keras.metrics.AUC()
auc.update_state(true_labels, pos_probs)
print(f"AUC值: {auc.result().numpy():.4f}")

内容的提问来源于stack exchange,提问作者Injarapu Sri Sharanya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:35:22