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

PyTorch训练Loss居高不下无下降趋势,求排查代码问题

问题分析与修复方案

你的代码存在几个基础问题,直接导致Loss居高不下且无下降趋势,以下是具体问题和修复方法:

1. 数据未做标准化/归一化

输入x的范围是0到9999,y仅为0-9,两者量级差距极大;输出goal随x线性增长到近30000。这种极端的数据分布会导致模型权重更新时梯度爆炸或消失,优化器无法有效调整参数。

修复方法:对输入和输出做标准化(减去均值除以标准差),或者归一化到[0,1]区间,这里用sklearn.preprocessing.StandardScaler处理。

2. 训练循环遍历错误

训练函数里遍历的是train_data(自定义Dataset实例),会逐个取出单样本,而非用train_dataloader按批次加载数据。这不仅效率低下,还会导致模型每次处理单个样本,梯度波动极大,难以收敛。

修复方法:将enumerate(train_data)改为enumerate(train_dataloader)。

3. 冗余的Variable封装

PyTorch 0.4版本之后,Tensor已整合Variable的功能,不需要手动将数据转为Variable,直接使用Tensor即可。

修复方法:删除data = Variable(data)和target = Variable(target)两行代码。

4. 损失函数定义位置错误

每次迭代中重复定义criterion = F.mse_loss属于冗余操作,应将其移到循环外定义。

5. 激活函数选择不当

隐藏层使用ReLU激活函数,但目标是拟合线性函数。若初始权重导致layer_1输出为负,ReLU会将其置0,阻断梯度传递到输入层,模型无法学习x的线性关系。

修复方法:要么去掉ReLU激活(线性任务无需非线性激活),要么先做数据标准化保证ReLU能正常传递梯度。


完整修复后的代码

数据集生成代码(无需修改)

import numpy as np
import pandas as pd

list_x = []
list_y = []
list_goal = []

for i in range(0, 10000):
    list_x.append(i)
    list_y.append(int(np.random.rand()*10))
    list_goal.append(3*i + list_y[i] + np.random.rand()*2)

df_new = pd.DataFrame()
df_new['x'] = list_x
df_new['y'] = list_y
df_new['goal'] = list_goal

df_new.to_csv('dataset.csv', sep=',', encoding='utf-8', index=False)

训练代码(已修复)

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import pandas as pd
import numpy as np

# 加载数据
df = pd.read_csv('dataset.csv')
X = df[["x", "y"]].values
y = df[["goal"]].values

# 数据标准化
scaler_X = StandardScaler()
scaler_y = StandardScaler()
X_scaled = scaler_X.fit_transform(X)
y_scaled = scaler_y.fit_transform(y)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_scaled, test_size=.2, random_state=42)

# 自定义Dataset
class Data(Dataset):
    def __init__(self, X, y):
        self.X = torch.from_numpy(X.astype(np.float32))
        self.y = torch.from_numpy(y.astype(np.float32))
        self.len = self.X.shape[0]

    def __getitem__(self, index):
        return self.X[index], self.y[index]

    def __len__(self):
        return self.len

batch_size = 32
train_data = Data(X_train, y_train)
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)

test_data = Data(X_test, y_test)
test_dataloader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True)

# 定义模型(去掉ReLU,适配线性任务)
input_dim = 2
hidden_dim_1 = 2
output_dim = 1

class NeuralNetwork(nn.Module):
    def __init__(self, input_dim, hidden_dim_1, output_dim):
        super(NeuralNetwork, self).__init__()
        self.layer_1 = nn.Linear(input_dim, hidden_dim_1)
        self.layer_out = nn.Linear(hidden_dim_1, output_dim)

    def forward(self, x):
        x = self.layer_1(x)  # 使用线性激活
        x = self.layer_out(x)
        return x

model = NeuralNetwork(input_dim, hidden_dim_1, output_dim)
optimizer = optim.SGD(model.parameters(), lr=0.01)
criterion = F.mse_loss  # 移至循环外定义

def train(epoch):
    model.train()
    total_loss = 0.0
    for batch_id, (data, target) in enumerate(train_dataloader):
        optimizer.zero_grad()
        out = model(data)
        loss = criterion(out, target)
        total_loss += loss.item()
        loss.backward()
        optimizer.step()
    # 每个epoch打印平均损失
    print(f'Epoch {epoch}, Average Training Loss: {total_loss / len(train_dataloader):.6f}')

for epoch in range(1, 30):
    train(epoch)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:37:00