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

BERT序列分类损失计算:训练值与手动计算值不符的疑问

BERT序列分类任务损失计算不符问题排查与正确流程

问题描述

在BERT序列分类任务中,训练时模型报告的损失为0.5368,但手动计算得到的损失为0.6769,两者数值不符。训练代码与手动计算代码如下:

训练代码

tokenized_data1= {'input_ids': array([[  101, 19278, 15091, ...,     0,     0,     0],
        [  101, 19278, 15091, ...,     0,     0,     0],
        [  101,  8084, 11318, ...,     0,     0,     0],
        ...,
        [  101,  7708, 14381, ...,     0,     0,     0],
        [  101,  5379,   787, ...,     0,     0,     0],
        [  101, 22327,  1987, ...,     0,     0,     0]]),
 'token_type_ids': array([[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]]),
 'attention_mask': array([[1, 1, 1, ..., 0, 0, 0],
        [1, 1, 1, ..., 0, 0, 0],
        [1, 1, 1, ..., 0, 0, 0],
        ...,
        [1, 1, 1, ..., 0, 0, 0],
        [1, 1, 1, ..., 0, 0, 0],
        [1, 1, 1, ..., 0, 0, 0]])}


labels1=[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0,
       0, 0, 0, 0, 0, 1, 0, 0, 0, 0]

from transformers import TFAutoModelForSequenceClassification

model = TFAutoModelForSequenceClassification.from_pretrained("bert-base-cased")
model.compile(optimizer=Adam(3e-5))
model.fit(tokenized_data1, labels1)

# 训练输出:1/1 [==============================] - 40s 40s/step - loss: 0.5368

手动计算代码

# Obtaining logits
outputs = model(input_ids=tf.constant(tokenized_data1['input_ids']),
                attention_mask=tf.constant(tokenized_data1['attention_mask']))
logits = torch.Tensor(outputs.logits.numpy())
labels1=torch.tensor(labels1)

# Calculating loss using cross-entropy loss function
loss_fct = CrossEntropyLoss()
loss = loss_fct(logits.view(-1, 2), torch.tensor(labels1).view(-1))
# 得到损失:0.6769

错误排查

手动计算存在三个核心错误:

  • 模型状态不一致:训练时的损失基于初始未更新的模型参数计算,但手动计算调用的是model.fit之后的模型,此时参数已经经过一轮训练更新,输出的logits与训练时完全不同,损失自然不匹配。
  • 跨框架混用导致损失计算差异:使用TensorFlow版本的BERT模型(TFAutoModelForSequenceClassification),却用PyTorch的CrossEntropyLoss计算损失。两者的损失函数实现细节有差异,比如TensorFlow默认的SparseCategoricalCrossentropy针对稀疏整数标签优化,而PyTorch的CrossEntropyLoss在数值计算、归约方式上可能存在细微差别。
  • 未对齐内置损失的配置:TFAutoModelForSequenceClassification默认使用SparseCategoricalCrossentropy(from_logits=True)计算损失(因为输入标签是整数形式),手动计算时没有匹配这一配置,导致计算逻辑不一致。

正确的损失计算流程

1. BERT序列分类内置损失逻辑

当使用TFAutoModelForSequenceClassification训练时,若未指定损失函数,模型会自动采用:

tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.AUTO)

计算流程为:

  • 对每个样本的logits计算softmax,得到类别概率分布
  • 取对应真实标签的负对数概率
  • 对batch内所有样本的损失值取均值,得到最终的batch损失

2. 正确的手动计算步骤

要得到与训练时一致的损失,需做到:

  • 在model.fit之前获取初始模型的logits
  • 使用TensorFlow的损失函数,保持框架一致
  • 匹配内置损失的配置(from_logits=True、归约方式为均值)

修正后的手动计算代码:

import tensorflow as tf
from transformers import TFAutoModelForSequenceClassification

# 初始化模型(未训练的初始状态)
model = TFAutoModelForSequenceClassification.from_pretrained("bert-base-cased")

# 转换数据为TensorFlow张量
input_ids = tf.constant(tokenized_data1['input_ids'])
attention_mask = tf.constant(tokenized_data1['attention_mask'])
labels = tf.constant(labels1)

# 获取初始模型的logits
outputs = model(input_ids=input_ids, attention_mask=attention_mask)
logits = outputs.logits

# 使用与内置一致的损失函数计算
loss_fct = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True, reduction='mean')
loss = loss_fct(labels, logits)

print(loss.numpy())  # 此时结果应与训练时报告的0.5368一致

内容的提问来源于stack exchange,提问作者krishna kaushik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:58:11