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

PyTorch多输出回归仅优化单个输出的问题排查求助

3输出回归任务问题排查与解决方案

1. 数据层面排查与处理

  • 标签尺度归一化:检查三个输出标签的数值范围,若各输出尺度差异较大(比如第一个输出范围是0-100,另外两个是0-1),MSE损失会天然偏向优化尺度大的输出。必须对每个输出标签单独做Z-score标准化(每个输出减去自身均值后除以标准差),同时输入特征也要做归一化,确保所有输入输出处于同一量级。
  • 数据有效性验证:统计训练集中三个输出的样本分布,确认是否存在某两个输出的样本噪声过大、缺失值较多,或样本覆盖范围不足的情况。若某输出的样本数据质量差,模型自然无法学到有效映射。
  • 特征-输出相关性分析:计算每个输出与输入特征的皮尔逊相关系数,若某两个输出与所有输入特征的相关性极低,说明现有特征无法支撑这两个输出的预测,需补充特征或重新评估任务合理性。

2. 模型结构优化

  • 简化模型规模:当前模型采用9→16→32→64→128→256→256→128→64→32→16→3的对称结构,对于9维输入的回归任务来说过于庞大,容易过拟合到第一个输出的模式,忽略其他两个。建议简化为轻量结构,例如:
class DNN(nn.Module):
    def __init__(self, n_features):
        super(DNN, self).__init__()
        self.layers = nn.Sequential(
            nn.Linear(n_features, 32),
            nn.ELU(),
            nn.Linear(32, 64),
            nn.ELU(),
            nn.Linear(64, 32),
            nn.ELU(),
            nn.Linear(32, 3)
        )
    
    def forward(self, x):
        return self.layers(x)
  • 多分支输出结构:改为共享特征提取+独立输出分支的结构,让每个输出拥有专属的映射层,避免任务间干扰:
class DNN(nn.Module):
    def __init__(self, n_features):
        super(DNN, self).__init__()
        # 共享特征层
        self.shared = nn.Sequential(
            nn.Linear(n_features, 32),
            nn.ELU(),
            nn.Linear(32, 64),
            nn.ELU()
        )
        # 独立输出分支
        self.out1 = nn.Linear(64, 1)
        self.out2 = nn.Linear(64, 1)
        self.out3 = nn.Linear(64, 1)
    
    def forward(self, x):
        feat = self.shared(x)
        return torch.cat([self.out1(feat), self.out2(feat), self.out3(feat)], dim=1)

3. 损失与训练策略调整

  • 加权损失函数:根据各输出的尺度或重要性,给每个输出的损失分配权重,强制模型均衡学习。示例代码:
def weighted_mse(pred, target, weights):
    # weights为长度3的张量,对应三个输出的权重
    per_out_loss = F.mse_loss(pred, target, reduction='none')
    return (per_out_loss * weights).mean()

使用时可根据各输出的方差设置权重(比如输出2的方差是输出1的1/10,则给输出2的权重设为10)。

  • 训练参数调优:
    • 调整学习率:尝试在1e-4~1e-3区间内测试,配合ReduceLROnPlateau学习率调度器,训练后期自动降低学习率以稳定收敛。
    • 调整批大小:若批大小过小,梯度噪声大导致模型无法稳定学习;过大则显存压力大且梯度更新不频繁,建议在32~128区间测试。
    • 增加正则化:在特征层之间加入nn.Dropout(p=0.2),配合现有weight_decay缓解过拟合。
  • 分输出监控损失:修改训练代码,单独记录每个输出的训练/测试损失,精准定位问题输出:
def train(net, train_features, train_labels, test_features, test_labels,
          num_epochs, learning_rate, weight_decay, batch_size):
    train_total, test_total = [], []
    train_per_out = [[], [], []]
    test_per_out = [[], [], []]
    train_iter = d2l.load_array((train_features, train_labels), batch_size)
    optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate, weight_decay=weight_decay)
    
    for epoch in range(num_epochs):
        for X, y in train_iter:
            optimizer.zero_grad()
            out = net(X)
            loss = F.mse_loss(out, y)
            loss.backward()
            optimizer.step()
        
        # 记录整体与分输出损失
        train_pred = net(train_features)
        train_total.append(F.mse_loss(train_pred, train_labels).item())
        for i in range(3):
            train_per_out[i].append(F.mse_loss(train_pred[:,i], train_labels[:,i]).item())
        
        if test_labels is not None:
            test_pred = net(test_features)
            test_total.append(F.mse_loss(test_pred, test_labels).item())
            for i in range(3):
                test_per_out[i].append(F.mse_loss(test_pred[:,i], test_labels[:,i]).item())
    
    return train_total, test_total, train_per_out, test_per_out

4. 权重初始化优化

PyTorch默认的Linear层初始化可能不匹配ELU激活函数,可手动对所有层采用Kaiming初始化,确保初始梯度稳定:

def init_weights(m):
    if isinstance(m, nn.Linear):
        nn.init.kaiming_uniform_(m.weight, nonlinearity='elu')
        nn.init.zeros_(m.bias)

net = DNN(n_features=9)
net.apply(init_weights)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 01:55:35