PyTorch损失函数异常问题:如何正确使用损失函数?
问题分析与解决方案
你的代码存在多个关键问题,导致损失异常、模型无法拟合,逐一修正如下:
核心错误点
- 损失函数误用:
CrossEntropyLoss是分类任务专用损失,回归任务需用均方误差损失(MSELoss),这是损失始终为0的直接原因。 - 梯度更新顺序错误:必须先清零梯度(
optimizer.zero_grad()),再反向传播(loss.backward()),最后更新参数(optimizer.step()),你当前的顺序会导致梯度被提前清零,参数完全不更新。 - 输出层激活函数冗余:回归任务不需要用
leaky_relu限制输出范围,最后一层应直接输出线性结果,否则无法拟合余弦函数的负值区间。 - 输入数据未归一化:输入
i的范围是0-29(弧度),数值跨度太大,神经网络难以学习,需先归一化到较小范围。
修正后的完整代码
import torch import torch.nn as nn import torch.nn.functional as f import math import matplotlib.pyplot as plt class DNN(nn.Module): def __init__(self): super(DNN, self).__init__() self.l1 = nn.Linear(in_features=1, out_features=16) # 适当增加神经元数量提升拟合能力 self.l2 = nn.Linear(in_features=16, out_features=16) self.l3 = nn.Linear(in_features=16, out_features=1) def forward(self, x): x = f.leaky_relu(self.l1(x)) x = f.leaky_relu(self.l2(x)) x = self.l3(x) # 最后一层去掉激活函数,允许输出任意值 return x # 初始化模型、损失、优化器 model = DNN() criterion = nn.MSELoss() # 替换为回归任务损失 optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 降低学习率,避免震荡 # 训练循环 epochs = 1000 # 增加训练轮次提升拟合效果 for epoch in range(epochs): total_loss = 0.0 for i in range(30): # 输入归一化:将0-29映射到[-1, 1]区间 x = torch.tensor([[i / 15 - 1]], dtype=torch.float32) # 真实标签:cos(i)的数值 y_true = torch.tensor([[math.cos(i)]], dtype=torch.float32) # 前向传播 y_pred = model(x) # 计算损失 loss = criterion(y_pred, y_true) # 梯度更新正确顺序 optimizer.zero_grad() loss.backward() optimizer.step() total_loss += loss.item() # 每100轮打印一次平均损失 if (epoch + 1) % 100 == 0: print(f"Epoch {epoch+1}/{epochs}, Average Loss: {total_loss/30:.6f}") # 测试与绘图 x_test = [] y_true = [] y_pred = [] for i in range(30): x_test.append(i) y_true.append(math.cos(i)) # 用同样的归一化处理输入 input_tensor = torch.tensor([[i / 15 - 1]], dtype=torch.float32) pred = model(input_tensor).item() y_pred.append(pred) plt.plot(x_test, y_pred, 'g-', label='模型预测') plt.plot(x_test, y_true, 'b--', label='真实cos值') plt.legend() plt.xlabel('x (弧度)') plt.ylabel('cos(x)') plt.show()
额外优化说明
- 增加神经元数量:原模型只有3个神经元的隐藏层,拟合能力不足,适当提升到16个增强表达能力。
- 降低学习率:原学习率0.1过大,容易导致训练震荡,调整为0.001更适合Adam优化器。
- 规范tensor形状:用
[[i]]创建二维tensor(批量维度+特征维度),符合PyTorch常规输入格式。 - 增加训练轮次:回归任务需要更多轮次让模型收敛,从100轮提升到1000轮。
内容的提问来源于stack exchange,提问作者sanyul
相关产品推荐
相关产品推荐

