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

基于PyTorch的自编码器多标签分类模型性能不佳的问题排查与优化咨询

基于PyTorch的自编码器多标签分类模型性能不佳的问题排查与优化咨询

我正在用PyTorch构建一个基于自编码器的神经网络,解决多标签分类问题。我的整体思路如下:

  • 从CSV文件加载数据集,进行数据清洗(删除缺失值和不必要的列),并选择特征子集
  • 将数据拆分为特征(X)和多标签目标(y)——每个目标都是二元值(0或1)
  • 使用GroupShuffleSplit进行基于分组的训练/测试拆分,确保相关样本保持在一起,这是我的问题特性所必需的
  • 最后用StandardScaler对特征进行标准化

我找不到太多这类方法的示例,目前我的实现如下:

class MutationDataset(Dataset):
    def __init__(self, features, labels):
        self.features = features
        self.labels = labels
        
    def __len__(self):
        return len(self.features)
    
    def __getitem__(self, idx):
        return self.features[idx], self.labels[idx]

# 模型架构
class AutoencoderClassifier(nn.Module):
    def __init__(self, input_dim, latent_dim=32, dropout_rate=0.2):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, 128),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(128, latent_dim),
            nn.ReLU()
        )
        self.decoder = nn.Sequential(
            nn.Linear(latent_dim, 128),
            nn.ReLU(),
            nn.Linear(128, input_dim)
        )
        # 分类头输出原始logits
        self.classifier = nn.Sequential(
            nn.Linear(latent_dim, 64),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(64, 4)
        )
    def forward(self, x):
        encoded = self.encoder(x)
        decoded = self.decoder(encoded)
        logits = self.classifier(encoded)
        return decoded, logits

我的数据集类别高度不平衡(负类占主导)。为了解决这个问题,我尝试使用带正类权重的Focal Loss:

class FocalLoss(nn.Module):
    def __init__(self, alpha=1, gamma=3, reduction='mean'):
        """
        Args:
            alpha (float or Tensor): 稀有类别的权重因子。也可以传入张量实现每类加权。
            gamma (float): 聚焦参数。值越高,越关注难分类的样本。
            reduction (str): 'mean', 'sum', 或 'none'
        """
        super(FocalLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.reduction = reduction

    def forward(self, logits, targets):
        # 逐元素计算标准BCE损失
        BCE_loss = F.binary_cross_entropy_with_logits(logits, targets, reduction='none')
        # 获取概率
        pt = torch.exp(-BCE_loss)
        # 计算Focal Loss的缩放因子
        focal_term = (1 - pt) ** self.gamma
        loss = self.alpha * focal_term * BCE_loss
        
        if self.reduction == 'mean':
            return loss.mean()
        elif self.reduction == 'sum':
            return loss.sum()
        else:
            return loss

最后是我的模型训练代码:

def train_model(X_train, y_train, X_test, y_test, input_dim, 
                device='cuda', learning_rate=0.001, batch_size=32, epochs=50, dropout_rate=0.2):
    train_dataset = MutationDataset(X_train, y_train)
    test_dataset = MutationDataset(X_test, y_test)
    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
    
    model = AutoencoderClassifier(input_dim=input_dim, dropout_rate=dropout_rate)
    model.to(device)
    
    # 计算每个标签的正类权重
    pos_weights = []
    for i in range(y_train.shape[1]):
        pos_count = np.sum(y_train[:, i])
        neg_count = len(y_train) - pos_count
        weight = neg_count / pos_count if pos_count != 0 else 1.0
        pos_weights.append(weight)
    pos_weights = torch.tensor(pos_weights, dtype=torch.float32, device=device)
    print("Pos weights:", pos_weights)
    
    recon_criterion = nn.MSELoss()
    class_criterion = FocalLoss(alpha=1, gamma=2, reduction='mean')
    optimizer = optim.Adam(model.parameters(), lr=learning_rate, weight_decay=1e-4)
    
    for epoch in range(epochs):
        model.train()
        total_loss = 0
        for batch_x, batch_y in train_loader:
            batch_x = batch_x.to(device)
            batch_y = batch_y.to(device)
            optimizer.zero_grad()
            recon, logits = model(batch_x)
            loss = 0.7 * recon_criterion(recon, batch_x) + 0.3 * class_criterion(logits, batch_y)
            loss.backward()
            optimizer.step()
            total_loss += loss.item()
        print(f'Epoch {epoch+1}: Loss {total_loss/len(train_loader):.4f}')
    
    return model, test_loader

不用说,模型的表现非常糟糕:

  • 训练过程中损失稳步下降——从第1轮的约0.20降到第50轮的约0.03
  • 训练集上的准确率相对较高(大多数标签在80%–91%之间),但F1分数差异很大:有些标签能达到中等水平(比如约0.60),其他的则低得多(甚至为0)
  • 测试集上部分标签的准确率还算合理(约77%–87%),但F1分数相比训练集骤降
  • 其中一个标签,模型完全无法预测任何正例(训练集和测试集上的F1分数都是0)

我可以尝试调整一些参数,但感觉可能在整体方法上存在错误。我到底漏掉了什么?

备注:内容来源于stack exchange,提问作者Marta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 03:42:59