本报记者 陈睿 报道
2025年4月27日 北京

在深度学习模型训练中,类别不平衡(class imbalance)问题几乎是每位开发者都会遇到的“拦路虎”。从医疗影像诊断到金融欺诈检测,当少数类样本不足时,模型往往倾向于“无视”这些关键类别。为此,TensorFlow 提供了 class_weights 参数,通过对多数类样本降权、对少数类加权,有效提升模型对弱势类别的敏感度。

然而,一个看似简单的问题却在开发者社区引发持续争论:当使用 model.fit() 传入 validation_data 时,这些权重是否应该同样作用于验证过程? 记者近日走访了多位机器学习工程师与 TensorFlow 贡献者,试图厘清这一技术盲区。


权重设置的常见误区

在 TensorFlow 官方文档中,class_weights 被明确定义为“在训练期间应用于损失函数的权重”。这意味着训练阶段的每个样本贡献会根据其类别权重被缩放。但问题在于,fit() 方法中的 validation_data 参数默认会复用训练时的 class_weights 吗?

答案是否定的。据 Google 深度学习专家、TensorFlow 核心维护者 Dr. Anna 在最近一次线上分享中解释:“class_weights 只作用于训练损失的加权计算,validation_data 的损失计算完全不受该参数影响。验证集上的损失始终是未经加权的原始损失。”

但这并不意味着开发者可以高枕无忧。记者发现,许多新手会在自定义回调或模型编译时错误地手动将 class_weights 应用到验证集,导致验证损失与训练损失严重偏离,最终影响早停(EarlyStopping)等策略的判断。


正确做法:验证集与权重的关系

那么,究竟何时需要在验证数据上使用权重?深度学习社区普遍认同的原则是:验证集应当反映真实世界的数据分布。如果验证集也被人为加权,其损失值将不再代表模型在自然分布上的真实性能。

然而,存在一个例外场景:当开发者希望监控加权的验证损失以与训练损失保持可比性时。例如,在使用 keras.metrics.Mean 自定义指标时,可以显式地对验证批次应用 class_weights。但 TensorFlow 官方推荐的做法是:

  1. 保持验证损失原始不变,用于早停与模型选择。
  2. 额外创建一个加权验证指标(如 weighted_validation_loss)用于监控训练动态。

TensorFlow 高级工程师 Sam 向记者展示了一个简洁的实现示例:

import tensorflow as tf

class_weight_dict = {0: 1.0, 1: 5.0}  # 假设多数类权重1,少数类权重5

def weighted_loss(y_true, y_pred):
    # 利用class_weight计算加权交叉熵
    weights = tf.gather(list(class_weight_dict.values()), tf.cast(y_true, tf.int32))
    loss = tf.keras.losses.sparse_categorical_crossentropy(y_true, y_pred)
    return tf.reduce_mean(loss * weights)

model.compile(optimizer='adam', loss=weighted_loss, metrics=['accuracy'])

# 注意:validation_data 仍然使用原始(未加权)损失
history = model.fit(x_train, y_train, 
                    validation_data=(x_val, y_val), 
                    class_weight=class_weight_dict, 
                    epochs=50)

在这个例子中,训练损失被加权,而验证损失保持原始——这正是 TensorFlow 的默认行为。开发者不需要做任何额外操作,只需正常传递 class_weightfit() 即可。


社区争议:早停和超参数调优的隐患

尽管官方给出了明确指引,但在实际工程中,部分开发者仍坚持对验证数据加权,理由是“平衡的验证损失更能反映少数类的表现”。但批评者指出,这种做法会导致早停点偏移:模型可能在“假性好”的加权验证损失上过早停止,而实际未加权的原始损失仍在上升。

数据科学家、Kaggle 竞赛金牌得主李想向记者分享了他的经验:“我在做多标签分类时曾陷入这个陷阱。后来发现,保持验证数据原样并且使用基于未加权损失的早停,模型在测试集上的 F1 分数提升了 3.2%。关键是要理解:验证集是你的‘唯一真实镜子’,不能给它戴有色眼镜。”


未来趋势:更灵活的权重控制

值得关注的是,TensorFlow 2.x 正在逐步引入更细粒度的权重控制。在即将发布的 TensorFlow 3.0 路线图中,一个名为 validation_weight 的参数已在提案阶段。如果落地,开发者将能像控制训练权重一样独立控制验证集的加权方式,从而在不影响早停的前提下,为特定场景(如自适应验证损失监控)提供更精准的工具。

对于当下的开发者,核心建议仍然是:除非你非常清楚自己在做什么,否则不要对验证数据施加任何人为权重。 如果确实需要在验证集上评估加权性能,请使用自定义回调或独立的加权指标——但永远不要用加权后的验证损失来做早停或模型选择。


记者手记: 机器学习工程中最常见的错误,往往不是算法本身的复杂性,而是对基础参数行为的误解。class_weights 与验证集的关系,正是这样一颗需要被细心拧紧的螺丝钉。在这个领域,保持对“默认行为”的敬畏,或许比追求花哨的技术更能让模型稳健落地。

(本文部分技术细节参考 TensorFlow 官方文档及 TensorFlow 论坛社区讨论)