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

基于California Housing数据集的回归神经网络无法学习求助

问题排查与修正方案

你的代码存在几个核心问题导致回归模型无法正常学习,以下是具体问题和修正步骤:

1. 回归任务错误引入分类准确率计算

这是最致命的错误:你在回归任务中错误使用了分类任务的准确率计算逻辑。回归预测的是连续数值,outputs.max(1)和predicted.eq(labels)完全不适用于回归场景,这些代码计算出的“准确率”毫无意义,还会误导你对模型训练状态的判断。

修正方式:删除train和test函数中所有与准确率相关的代码,只保留损失计算逻辑。

2. 特征未做标准化处理

California Housing数据集的特征数值范围差异极大(例如MedInc在0-15之间,AveOccup可达到100以上),神经网络对输入数据的尺度非常敏感,未标准化的特征会导致梯度爆炸/消失,模型无法有效收敛。

修正方式:使用sklearn.preprocessing.StandardScaler对训练数据做标准化,测试数据必须使用训练数据的均值和方差进行转换,避免数据泄露。

3. 模型结构过于复杂(可选优化)

你构建了5层全连接网络+批量归一化+Dropout,对于加州房价预测这种简单回归任务来说,过深的模型会增加训练难度,甚至导致过拟合。可以先简化模型,等模型稳定收敛后再逐步增加复杂度。


修正后的完整代码

import torch.nn.functional as F
import torch.nn as nn
import torch
import pandas as pd
import sklearn.datasets
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 加载数据
data = sklearn.datasets.fetch_california_housing(as_frame=True)

# 划分数据集并标准化特征
X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.25, random_state=13)

# 特征标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

class MyDataset(torch.utils.data.Dataset):
    def __init__(self, x, y):
        self.f_tensor = torch.tensor(x, dtype=torch.float32)
        self.t_tensor = torch.tensor(y.values, dtype=torch.float32).reshape(-1, 1)

    def __len__(self):
        return len(self.f_tensor)

    def __getitem__(self, idx):
        return self.f_tensor[idx], self.t_tensor[idx]

train_dataset = MyDataset(X_train_scaled, y_train)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=128, shuffle=True, drop_last=True)

test_dataset = MyDataset(X_test_scaled, y_test)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=16, shuffle=False, drop_last=True)

# 简化模型结构
class FeedForward(nn.Module):
    def __init__(self, input_dim, hidden_dims, output_dim=1):
        super().__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dims[0])
        self.fc2 = nn.Linear(hidden_dims[0], hidden_dims[1])
        self.fc3 = nn.Linear(hidden_dims[1], output_dim)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

def train(model, optimizer, criterion, train_loader, device):
    model.train()
    running_loss = 0.0

    for inputs, labels in train_loader:
        inputs, labels = inputs.to(device), labels.to(device)
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()

    train_loss = running_loss / len(train_loader)
    return train_loss

def test(model, criterion, test_loader, device):
    model.eval()
    running_loss = 0.0

    with torch.no_grad():
        for inputs, labels in test_loader:
            inputs, labels = inputs.to(device), labels.to(device)
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            running_loss += loss.item()

    test_loss = running_loss / len(test_loader)
    return test_loss

def train_model(model, optimizer, criterion, train_loader, test_loader, device, num_epochs=50):
    train_losses = []
    test_losses = []

    for epoch in range(num_epochs):
        train_loss = train(model, optimizer, criterion, train_loader, device)
        test_loss = test(model, criterion, test_loader, device)

        train_losses.append(train_loss)
        test_losses.append(test_loss)

        print(f"Epoch [{epoch+1}/{num_epochs}]: Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}")

    return train_losses, test_losses

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
hidden_dims = [64, 32]  # 简化隐藏层
model = FeedForward(8, hidden_dims).to(device)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

train_losses, test_losses = train_model(model, optimizer, criterion, train_loader, test_loader, device)

# 绘制损失曲线
plt.figure(figsize=(8, 4))
plt.plot(train_losses, label="Train Loss")
plt.plot(test_losses, label="Test Loss")
plt.xlabel("Epochs")
plt.ylabel("MSE Loss")
plt.legend()
plt.show()

关键修改说明

  1. 移除了所有与“准确率”相关的错误代码,回归任务只需要关注MSE损失的变化。
  2. 添加了特征标准化步骤,确保所有特征处于同一尺度,帮助模型稳定收敛。
  3. 简化了模型结构,减少了隐藏层数量和正则化组件,降低训练难度。
  4. 增加了训练轮数到50,确保模型有足够时间学习数据模式。

运行修正后的代码,你会看到训练损失和测试损失稳步下降,说明模型已经正常学习。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 01:11:06