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

如何用Python3.9/PyTorch构建多输出神经网络及适配损失优化器?

解决方案:多选场景的PyTorch神经网络实现

一、输出层调整:替换Softmax为Sigmoid

你的场景是多选勾选,每个输出节点独立判断是否为1,Softmax会强制所有输出和为1,完全不适用。应该用nn.Sigmoid(),它能把每个输出映射到0-1区间,且各节点输出独立。

修改后的网络代码如下:

import torch.nn as nn

class NeuralNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(NeuralNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size) 
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, num_classes)  
        self.sigmoid = nn.Sigmoid()  # 添加Sigmoid层
    
    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        out = self.sigmoid(out)  # 对最后一层输出做Sigmoid映射
        return out

如果想避免数值不稳定,也可以用BCEWithLogitsLoss,此时不需要单独加Sigmoid层,直接输出fc2的结果即可,损失函数会自动整合Sigmoid计算:

class NeuralNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(NeuralNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size) 
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, num_classes)  
    
    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)  # 直接输出logits,交给损失函数处理
        return out

二、适配多选场景的损失函数

  • BCELoss:二元交叉熵损失,适用于每个输出节点都是独立的二元判断场景,需要输入是经过Sigmoid后的0-1值。
  • BCEWithLogitsLoss:更推荐的选择,它将Sigmoid激活和BCELoss合并计算,能有效避免数值下溢/上溢问题,输入直接是网络最后一层的logits(未经过Sigmoid的原始输出)。

使用示例:

# 若用单独Sigmoid层,用BCELoss
criterion = nn.BCELoss()
# 若直接输出logits,用BCEWithLogitsLoss
criterion = nn.BCEWithLogitsLoss()

三、优化器的适配问题

你提到的SGD和Adam完全支持多目标输出场景。优化器的作用是更新网络参数,只关心参数的梯度,和输出是单目标还是多目标无关。只要损失函数能计算出合理的梯度,SGD、Adam等常用优化器都可以正常工作。

使用示例:

import torch.optim as optim

optimizer = optim.SGD(model.parameters(), lr=0.01)
# 或者用Adam
optimizer = optim.Adam(model.parameters(), lr=0.001)

训练循环示例

# 假设model是你的NeuralNet实例,criterion是BCEWithLogitsLoss,optimizer是Adam
for epoch in range(num_epochs):
    outputs = model(inputs)
    loss = criterion(outputs, labels)  # labels是形状和outputs一致的0-1张量
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

注意:标签labels必须是和输出张量形状相同的二进制张量(每个元素为0或1),对应每个输出节点是否被勾选。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 07:15:00