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

分类器网络输出偏向全零的训练问题求解

问题解决方案

核心问题分析

你遇到的本质问题是损失函数误用+单样本训练的梯度偏差:

  • 互斥多分类任务(one-hot标签表示类别互斥)用BCELoss不合适,BCELoss是针对多标签任务(每个样本可属于多个类别)设计的,而你的场景是每个样本仅属于一个类别,属于互斥多分类。
  • 单样本训练时,每个step里模型只看到1个正样本和111个负样本,极度不平衡的样本分布会让模型倾向输出全零来降低损失。

具体修正步骤

1. 替换损失函数与模型激活函数

用CrossEntropyLoss替代BCELoss,这是互斥多分类的标准损失函数,它会自动对模型输出做softmax计算,因此模型不需要sigmoid激活(反而会干扰计算逻辑):

# 修正模型:移除多余的空Sequential,无需sigmoid激活
model = nn.Sequential(nn.Linear(64, 112))
# 替换为互斥多分类专用损失函数
loss_fn = nn.CrossEntropyLoss()

2. 简化标签输入,废弃one-hot

CrossEntropyLoss直接接受类别索引整数作为标签,不需要转成one-hot向量,既节省计算资源,也从根源避免了不平衡的标签分布问题:

# 调整训练循环:改为批次训练,一次性输入所有样本
for epoch in range(500):
    # 提前整理所有样本为批次张量
    input_states = torch.stack([item[0] for item in samples])
    labels = torch.tensor([item[1] for item in samples])
    
    optimizer.zero_grad()
    prediction = model(input_states)
    loss = loss_fn(prediction, labels)
    loss.backward()
    optimizer.step()
    
    # 可选:每轮打印损失,监控训练状态
    if epoch % 50 == 0:
        print(f"Epoch {epoch}, Loss: {loss.item():.4f}")

3. 强制批次训练,消除单样本梯度偏差

原代码的单样本训练会让模型每次仅学习一个类别的信号,批次训练(一次性输入全部112个样本)能让模型同时感知所有类别的分布,梯度更新更稳定,不会偏向全零输出。

4. 可选:优化训练细节

  • 如果收敛速度慢,可适当提高学习率(比如调整为1e-3),或调整AdamW的权重衰减参数;
  • 可给Linear层增加nn.Dropout(0.1)做轻量正则化,避免因样本数与类别数相等导致的过拟合;
  • 可增加训练轮数(比如从500调到1000),观察损失变化趋势。

为什么之前的平均损失无效?

你尝试的“所有样本计算平均损失”如果仍沿用BCELoss+one-hot标签,本质上还是每个样本损失里111个0和1个1的不平衡问题,平均后依然是引导模型输出全零的损失信号,只有更换损失函数和标签形式才能解决根本矛盾。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 05:55:19