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

PyTorch二分类模型首轮即达100%准确率问题求助

问题分析与修复方案

核心问题拆解

  1. 准确率计算逻辑完全错误:模型输出是经过sigmoid的单值(形状[batch_size, 1]),但验证时用outputs.argmax(1)——对于单维度输出,argmax(1)会返回全0,而数据集99.99%是负例(target=0),所以准确率必然是100%,这是最直接的假象。
  2. 损失函数与维度不匹配:用MSELoss做二分类不合适,且训练时targets是一维数组([batch_size]),outputs是二维([batch_size,1]),维度不匹配导致损失计算异常,模型只需输出全0就能快速让损失趋近于0。
  3. 极端数据不平衡未处理:35个正例vs30万负例,模型直接输出全0就能获得极高的表面性能,完全不会学习正例特征。

具体修复步骤

1. 修正准确率计算逻辑

替换验证代码中的准确率计算部分,用阈值判断二分类结果(而非argmax):

# 验证循环内替换原val_acc计算代码
loan_model.eval()
val_loss = 0
val_acc = 0
with torch.no_grad():
    for inputs, targets in val_loader:
        outputs = loan_model(inputs)
        targets = targets.view(-1, 1)  # 匹配outputs维度
        val_loss += criterion(outputs, targets)
        # 用0.5阈值判断类别,计算正确数
        preds = (outputs > 0.5).float()
        val_acc += (preds == targets).sum().item()
val_loss /= len(val_loader)
val_acc /= len(val_loader.dataset)

2. 更换损失函数并修复维度匹配

改用二分类专用损失函数,同时确保targets与outputs维度一致:

# 替换原损失函数定义
criterion = torch.nn.BCELoss()  # 配合模型的sigmoid输出
# 或者用BCEWithLogitsLoss(更稳定,此时需删除模型forward中的sigmoid)
# criterion = torch.nn.BCEWithLogitsLoss()

optimizer = torch.optim.Adam(loan_model.parameters(), lr=0.001)  # 降低学习率,0.01过大

# 训练循环内添加维度调整
for epoch in range(num_epochs):
    loan_model.train()
    for i, (inputs, targets) in enumerate(train_loader):
        optimizer.zero_grad()
        targets = targets.view(-1, 1)  # 转为[batch_size,1],匹配outputs
        outputs = loan_model(inputs)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()

3. 处理极端数据不平衡

针对你的数据情况,推荐以下两种方案:

方案A:加权损失

给正例设置更高的损失权重,让模型重视正例:

# 计算正例权重:负例数量/正例数量
pos_weight = torch.tensor([(len(train_df) - train_df['target'].sum()) / train_df['target'].sum()])
criterion = torch.nn.BCELoss(weight=pos_weight)
方案B:加权采样

用WeightedRandomSampler让DataLoader优先采样正例,平衡每个batch的正负样本比例:

from torch.utils.data import WeightedRandomSampler

# 计算每个样本的权重
class_counts = train_df['target'].value_counts().values
weights = 1. / class_counts
sample_weights = weights[train_df['target'].values]

# 创建带采样器的DataLoader
sampler = WeightedRandomSampler(sample_weights, len(sample_weights), replacement=True)
train_loader = data_utils.DataLoader(train_data, batch_size=32, sampler=sampler)
方案C:Focal Loss(进阶)

自定义Focal Loss,降低易分类负例的权重,聚焦难分类的正例:

class FocalLoss(torch.nn.Module):
    def __init__(self, alpha=0.8, gamma=2):
        super().__init__()
        self.alpha = alpha
        self.gamma = gamma

    def forward(self, outputs, targets):
        bce_loss = torch.nn.functional.binary_cross_entropy(outputs, targets, reduction='none')
        pt = torch.exp(-bce_loss)
        focal_loss = self.alpha * (1 - pt) ** self.gamma * bce_loss
        return torch.mean(focal_loss)

criterion = FocalLoss(alpha=0.8, gamma=2)

4. 补充更有效的评估指标

不平衡数据下准确率毫无意义,需监控精确率、召回率、F1分数:

from sklearn.metrics import precision_score, recall_score, f1_score

# 验证时收集所有预测结果和真实标签
all_preds = []
all_targets = []
loan_model.eval()
with torch.no_grad():
    for inputs, targets in val_loader:
        outputs = loan_model(inputs)
        preds = (outputs > 0.5).float()
        all_preds.extend(preds.cpu().numpy().flatten())
        all_targets.extend(targets.cpu().numpy())

# 计算指标
precision = precision_score(all_targets, all_preds)
recall = recall_score(all_targets, all_preds)
f1 = f1_score(all_targets, all_preds)
print(f'Val Precision: {precision:.4f}, Val Recall: {recall:.4f}, Val F1: {f1:.4f}')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:35:05