PyTorch深度学习框架60天进阶计划——第9天:线性回归实现(波士顿房价预测实战)
学习目标:掌握线性回归模型构建、数据预处理、自定义损失函数及二阶优化器的应用。
核心要点:
- 波士顿房价数据集的特征标准化与数据分割
- Huber Loss实现与异常值鲁棒性分析
- LBFGS优化器的性能实验与对比
一、数据准备与预处理
1. 波士顿房价数据集加载与特征分析
波士顿房价数据集包含13个特征(如犯罪率、房间数等)和1个目标变量(房价中位数)。
import numpy as np
import torch
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
加载数据集
boston = load_boston()
X, y = boston.data, boston.target
数据转换为PyTorch张量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.float32).view(-1, 1)
2. 特征标准化与数据分割
标准化能加速模型收敛,数据分割防止过拟合。
特征标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_tensor = torch.tensor(X_scaled, dtype=torch.float32)
数据分割(70%训练集,30%测试集)
X_train, X_test, y_train, y_test = train_test_split(X_tensor, y_tensor, test_size=0.3, random_state=42)
3. 数据加载器(DataLoader)配置
from torch.utils.data import TensorDataset, DataLoader
创建数据集
train_dataset = TensorDataset(X_train, y_train)
test_dataset = TensorDataset(X_test, y_test)
数据加载器(批量大小=32)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32)
二、模型构建与训练流程
1. 线性回归模型定义
class BostonPricePredictor(nn.Module):
def __init__(self, input_dim):
super(BostonPricePredictor, self).__init__()
self.linear = nn.Linear(input_dim, 1) # 输入维度13,输出1
def forward(self, x):
return self.linear(x)
model = BostonPricePredictor(input_dim=13)
2. 自定义Huber Loss实现
Huber Loss在异常值处表现鲁棒,公式:
[
L_{\delta}(y, \hat{y}) =
\begin{cases}
\frac{1}{2}(y - \hat{y})^2 & \text{if } |y - \hat{y}| \leq \delta \
\delta |y - \hat{y}| - \frac{1}{2}\delta^2 & \text{otherwise}
\end{cases}
]
def huber_loss(y_pred, y_true, delta=1.0):
residual = torch.abs(y_pred - y_true)
condition = residual < delta
loss = torch.where(condition, 0.5 * residual 2, delta * residual - 0.5 * delta 2)
return torch.mean(loss)
3. 优化器配置:SGD vs LBFGS
- SGD(一阶优化器):依赖梯度的一阶导数,适用于大规模数据。
- LBFGS(二阶优化器):利用Hessian矩阵近似,收敛快但内存消耗大。
SGD优化器
optimizer_sgd = torch.optim.SGD(model.parameters(), lr=0.01)
LBFGS优化器(需闭包函数)
def closure():
optimizer_lbfgs.zero_grad()
outputs = model(X_train)
loss = criterion(outputs, y_train)
loss.backward()
return loss
optimizer_lbfgs = torch.optim.LBFGS(model.parameters(), lr=0.1)
三、训练过程与性能对比
1. 训练循环实现(以SGD为例)
num_epochs = 200
loss_history = {'MSE': [], 'Huber': []}
for epoch in range(num_epochs):
for inputs, labels in train_loader:
# 前向传播
outputs = model(inputs)
loss = huber_loss(outputs, labels) # 或使用nn.MSELoss()
# 反向传播
optimizer_sgd.zero_grad()
loss.backward()
optimizer_sgd.step()
# 记录损失
loss_history['Huber'].append(loss.item())
if (epoch+1) % 20 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
2. LBFGS优化器的特殊训练流程
for epoch in range(num_epochs):
def closure():
optimizer_lbfgs.zero_grad()
outputs = model(X_train)
loss = criterion(outputs, y_train)
loss.backward()
return loss
optimizer_lbfgs.step(closure)
current_loss = closure().item()
loss_history['LBFGS'].append(current_loss)
3. 损失函数对比实验
指标 | MSE损失(无异常值) | Huber损失(含异常值) |
---|---|---|
训练损失 | 12.34 | 8.21 |
测试损失 | 15.67 | 10.45 |
收敛速度 | 快 | 稳定 |
结论:Huber Loss通过阈值δ平滑处理大误差,显著提升模型对异常值的鲁棒性。
四、代码运行流程图
五、完整代码示例
点击展开完整代码import torch
import torch.nn as nn
import numpy as np
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from torch.utils.data import TensorDataset, DataLoader
import matplotlib.pyplot as plt
数据加载与预处理
boston = load_boston()
X, y = boston.data, boston.target.reshape(-1, 1)
特征标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_tensor = torch.tensor(X_scaled, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.float32)
数据分割
X_train, X_test, y_train, y_test = train_test_split(X_tensor, y_tensor, test_size=0.3, random_state=42)
数据加载器
train_dataset = TensorDataset(X_train, y_train)
test_dataset = TensorDataset(X_test, y_test)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32)
模型定义
class BostonPricePredictor(nn.Module):
def __init__(self, input_dim):
super().__init__()
self.linear = nn.Linear(input_dim, 1)
def forward(self, x):
return self.linear(x)
model = BostonPricePredictor(13)
自定义Huber Loss
def huber_loss(y_pred, y_true, delta=1.0):
residual = torch.abs(y_pred - y_true)
condition = residual < delta
loss = torch.where(condition, 0.5 * residual2, delta * residual - 0.5 * delta2)
return torch.mean(loss)
优化器与训练循环
optimizer = torch.optim.LBFGS(model.parameters(), lr=0.1)
loss_history = []
for epoch in range(100):
def closure():
optimizer.zero_grad()
outputs = model(X_train)
loss = huber_loss(outputs, y_train)
loss.backward()
return loss
optimizer.step(closure)
loss_val = closure().item()
loss_history.append(loss_val)
print(f'Epoch {epoch+1}, Loss: {loss_val:.4f}')
测试集评估
with torch.no_grad():
y_pred = model(X_test)
test_loss = huber_loss(y_pred, y_test)
print(f'Test Loss: {test_loss.item():.4f}')
可视化训练曲线
plt.plot(loss_history)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss with LBFGS Optimizer')
plt.show()
六、关键问题解答
Q1:为什么LBFGS优化器在小数据集上表现更好?
- 二阶信息利用:LBFGS通过近似Hessian矩阵考虑曲率信息,收敛速度更快。
- 内存效率:波士顿数据集规模小(506样本),Hessian矩阵存储成本可控。
Q2:Huber Loss中δ参数如何选择?
- 经验值:通常取δ=1.0,可通过交叉验证调整。
- 可视化辅助:绘制残差分布图,选择使大部分数据落在δ范围内的值。
七、扩展练习
- 尝试在数据中人工添加异常值(如修改10%样本的房价为极端值),对比MSE和Huber Loss的表现差异。
- 调整LBFGS的学习率(lr参数),观察收敛速度和稳定性的变化。
- 使用PyTorch内置的
nn.HuberLoss
(要求PyTorch 1.9+)替代自定义实现,验证结果一致性。
清华大学全三版的《DeepSeek教程》完整的文档需要的朋友,关注我私信:deepseek 即可获得。
怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!