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

在PyTorch中测试多种损失函数是否需创建多个神经网络实例?

嗨,这个问题问到点子上了,咱们先把两种方案的问题和正确做法理清楚:

先给结论:

你的第一种思路(创建两个独立网络实例)是可行的,但要补全细节保证对比公平;而第二种思路(同一个网络同时用两个损失反向传播)是完全错误的,根本达不到对比两种损失效果的目的。

为什么第二种方案不行?

你写的第二种代码里,los_1.backward()会把损失1的梯度计算出来并累积到网络参数的.grad属性里,紧接着los_2.backward()又会把损失2的梯度也加进去,最后opt.step()是用两个损失的梯度之和来更新权重——这本质上是把两种损失合并成一个复合损失来训练网络,而不是分别用两种损失训练两个独立的模型,完全偏离了你“对比两种损失效果”的目标。

正确的实现方式

方式一:双网络实例(直观,适合同时训练)

这种方法需要创建两个网络,关键是要让它们从完全相同的初始权重开始训练,不然对比就没有意义了。另外你代码里的optim.SGD('params')是错误的,要传入对应网络的参数:

import torch
import torch.nn as nn
import torch.optim as optim

# 假设你的ANN网络定义如下
class ANN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(20, 64)
        self.fc2 = nn.Linear(64, 10)
    def forward(self, x):
        x = torch.relu(self.fc1(x))
        return self.fc2(x)

# 初始化两个网络,并复制权重保证初始状态一致
network_loss1 = ANN().cuda()
network_loss2 = ANN().cuda()
network_loss2.load_state_dict(network_loss1.state_dict())  # 复制初始权重

# 定义两种损失函数
criterion_loss1 = nn.CrossEntropyLoss()
criterion_loss2 = nn.MSELoss()

# 分别为两个网络创建优化器
optimizer_loss1 = optim.SGD(network_loss1.parameters(), lr=0.01, momentum=0.9)
optimizer_loss2 = optim.SGD(network_loss2.parameters(), lr=0.01, momentum=0.9)

num_epochs = 20
data_loader = torch.utils.data.DataLoader(...)  # 替换成你的数据加载器

for epoch in range(num_epochs):
    # 遍历数据集,分别训练两个网络
    for batch_idx, (inputs, labels) in enumerate(data_loader):
        inputs, labels = inputs.cuda(), labels.cuda()
        
        # 训练使用损失1的网络
        optimizer_loss1.zero_grad()
        outputs1 = network_loss1(inputs)
        loss1 = criterion_loss1(outputs1, labels)
        loss1.backward()
        optimizer_loss1.step()
        
        # 训练使用损失2的网络
        optimizer_loss2.zero_grad()
        outputs2 = network_loss2(inputs)
        loss2 = criterion_loss2(outputs2, labels.float())  # 根据损失类型调整标签格式
        loss2.backward()
        optimizer_loss2.step()
    
    # 每个epoch结束后,可以记录两个网络的损失、精度等指标,方便后续对比
    print(f"Epoch {epoch+1} | Loss1: {loss1.item():.4f} | Loss2: {loss2.item():.4f}")

方式二:单网络实例(节省显存,适合资源有限的情况)

如果你的显存不够同时放两个网络,可以用单网络分两次训练:先训练损失1,保存训练结果;然后把网络重置回初始状态,再训练损失2。这样也能保证对比的公平性:

import torch
import torch.nn as nn
import torch.optim as optim

class ANN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(20, 64)
        self.fc2 = nn.Linear(64, 10)
    def forward(self, x):
        x = torch.relu(self.fc1(x))
        return self.fc2(x)

network = ANN().cuda()
initial_weights = network.state_dict()  # 保存初始权重,用于后续重置

# 先训练损失1的情况
criterion_loss1 = nn.CrossEntropyLoss()
optimizer_loss1 = optim.SGD(network.parameters(), lr=0.01, momentum=0.9)
loss_history_loss1 = []

for epoch in range(num_epochs):
    epoch_loss = 0.0
    for inputs, labels in data_loader:
        inputs, labels = inputs.cuda(), labels.cuda()
        optimizer_loss1.zero_grad()
        outputs = network(inputs)
        loss = criterion_loss1(outputs, labels)
        loss.backward()
        optimizer_loss1.step()
        epoch_loss += loss.item()
    avg_loss = epoch_loss / len(data_loader)
    loss_history_loss1.append(avg_loss)
    print(f"Loss1 Training Epoch {epoch+1}: Avg Loss = {avg_loss:.4f}")
# 保存损失1训练后的权重
trained_weights_loss1 = network.state_dict()

# 重置网络到初始状态,训练损失2的情况
network.load_state_dict(initial_weights)
criterion_loss2 = nn.MSELoss()
optimizer_loss2 = optim.SGD(network.parameters(), lr=0.01, momentum=0.9)
loss_history_loss2 = []

for epoch in range(num_epochs):
    epoch_loss = 0.0
    for inputs, labels in data_loader:
        inputs, labels = inputs.cuda(), labels.cuda()
        optimizer_loss2.zero_grad()
        outputs = network(inputs)
        loss = criterion_loss2(outputs, labels.float())
        loss.backward()
        optimizer_loss2.step()
        epoch_loss += loss.item()
    avg_loss = epoch_loss / len(data_loader)
    loss_history_loss2.append(avg_loss)
    print(f"Loss2 Training Epoch {epoch+1}: Avg Loss = {avg_loss:.4f}")

# 对比两个损失的训练历史,或者加载权重测试模型性能

最后提醒

不管用哪种方式,都要保证两个训练过程的所有其他变量一致:比如学习率、优化器参数、训练轮数、数据加载顺序(如果用随机采样的话,要设置相同的随机种子),这样对比出来的结果才是两种损失函数的真实差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:06:13