PyTorch 线性回归
下面是关于使用 PyTorch 实现线性回归的详细说明,包括核心概念、代码示例和最佳实践。线性回归是一种基础的机器学习模型,目标是通过最小化均方误差来拟合一个线性函数 ( y = w \cdot x + b )。PyTorch 提供了灵活的工具来构建、训练和评估线性回归模型。
1. 核心概念
- 模型:线性回归模型的数学形式为 ( y = w \cdot x + b ),其中 ( w ) 是权重,( b ) 是偏置。
- 损失函数:通常使用均方误差(Mean Squared Error, MSE)作为损失函数:
( \text{Loss} = \frac{1}{n} \sum_{i=1}^n (y_{\text{pred},i} – y_{\text{true},i})^2 )。 - 优化器:梯度下降(或其变种,如 SGD、Adam)用于优化模型参数 ( w ) 和 ( b )。
- 数据加载:使用
torch.utils.data.Dataset
和DataLoader
来高效加载数据。
2. 实现线性回归的步骤
以下是使用 PyTorch 实现线性回归的完整流程:
2.1 准备数据
假设我们有一个简单的合成数据集,输入 ( x ) 和输出 ( y ) 满足线性关系 ( y = 2x + 1 + \text{noise} )。我们首先生成数据并将其包装为 PyTorch 的 Dataset
。
import torch
from torch.utils.data import Dataset, DataLoader
# 自定义数据集
class LinearDataset(Dataset):
def __init__(self, size=1000):
self.x = torch.linspace(0, 10, size).reshape(-1, 1) # 输入
self.y = 2 * self.x + 1 + torch.randn(size, 1) * 0.5 # 输出(加噪声)
def __len__(self):
return len(self.x)
def __getitem__(self, idx):
return self.x[idx], self.y[idx]
# 创建数据集和 DataLoader
dataset = LinearDataset()
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
2.2 定义模型
PyTorch 提供了 nn.Module
来定义模型。我们可以自定义一个简单的线性回归模型,也可以使用内置的 nn.Linear
。
import torch.nn as nn
class LinearRegression(nn.Module):
def __init__(self, input_dim=1, output_dim=1):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(input_dim, output_dim) # 单层线性层
def forward(self, x):
return self.linear(x)
# 实例化模型
model = LinearRegression()
2.3 定义损失函数和优化器
- 损失函数:使用均方误差(MSE)。
- 优化器:使用随机梯度下降(SGD)或 Adam。
import torch.optim as optim
criterion = nn.MSELoss() # 均方误差损失
optimizer = optim.SGD(model.parameters(), lr=0.01) # 随机梯度下降
2.4 训练模型
通过迭代数据,计算损失并更新模型参数。
num_epochs = 100
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
for epoch in range(num_epochs):
model.train()
total_loss = 0
for x, y in dataloader:
x, y = x.to(device), y.to(device)
# 前向传播
outputs = model(x)
loss = criterion(outputs, y)
# 反向传播和优化
optimizer.zero_grad() # 清空梯度
loss.backward() # 计算梯度
optimizer.step() # 更新参数
total_loss += loss.item()
# 打印每 10 个 epoch 的平均损失
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss/len(dataloader):.4f}')
2.5 评估和预测
训练完成后,可以使用模型进行预测,并查看学习到的参数。
# 切换到评估模式
model.eval()
with torch.no_grad():
test_x = torch.tensor([[5.0]]).to(device)
predicted_y = model(test_x)
print(f'Input x = 5.0, Predicted y = {predicted_y.item():.4f}')
# 查看模型参数
for name, param in model.named_parameters():
print(f'{name}: {param.data}')
3. 完整示例代码
以下是将上述步骤整合的完整代码:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
# 自定义数据集
class LinearDataset(Dataset):
def __init__(self, size=1000):
self.x = torch.linspace(0, 10, size).reshape(-1, 1)
self.y = 2 * self.x + 1 + torch.randn(size, 1) * 0.5
def __len__(self):
return len(self.x)
def __getitem__(self, idx):
return self.x[idx], self.y[idx]
# 定义模型
class LinearRegression(nn.Module):
def __init__(self, input_dim=1, output_dim=1):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(input_dim, output_dim)
def forward(self, x):
return self.linear(x)
# 初始化
dataset = LinearDataset()
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
model = LinearRegression()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
# 训练
num_epochs = 100
for epoch in range(num_epochs):
model.train()
total_loss = 0
for x, y in dataloader:
x, y = x.to(device), y.to(device)
outputs = model(x)
loss = criterion(outputs, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss/len(dataloader):.4f}')
# 预测
model.eval()
with torch.no_grad():
test_x = torch.tensor([[5.0]]).to(device)
predicted_y = model(test_x)
print(f'Input x = 5.0, Predicted y = {predicted_y.item():.4f}')
# 查看参数
for name, param in model.named_parameters():
print(f'{name}: {param.data}')
4. 可视化结果
为了直观展示线性回归的结果,可以使用 matplotlib 绘制数据点和拟合直线:
import matplotlib.pyplot as plt
# 获取数据
x_data = dataset.x.numpy()
y_data = dataset.y.numpy()
# 预测
model.eval()
with torch.no_grad():
y_pred = model(dataset.x.to(device)).cpu().numpy()
# 绘制
plt.scatter(x_data, y_data, label='Data', alpha=0.5)
plt.plot(x_data, y_pred, color='red', label='Fitted Line')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
5. 最佳实践与优化
- 学习率调整:如果损失下降不稳定,尝试减小学习率(如 0.001)或使用
optim.Adam
。 - 数据归一化:在训练前对输入数据进行标准化(如零均值、单位方差),可以加速收敛。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
dataset.x = torch.tensor(scaler.fit_transform(dataset.x))
- 批量大小:选择合适的
batch_size
(如 32 或 64),平衡训练速度和稳定性。 - 早停(Early Stopping):监控验证集损失,若长时间不下降则停止训练。
- GPU 加速:确保数据和模型都在同一设备(
cpu
或cuda
)。
6. 常见问题与解决方案
- 损失不下降:
- 检查学习率是否过高或过低。
- 确保数据预处理正确(如数据是否归一化)。
- 检查模型是否过于简单或复杂。
- 过拟合:如果数据量少,添加正则化(如 L2 正则化,通过
weight_decay
参数):
optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=0.01)
- 内存问题:减小
batch_size
或使用更高效的数据加载方式。
7. 扩展
- 多变量线性回归:将输入维度从 1 扩展到多维,只需修改
nn.Linear(input_dim, output_dim)
的input_dim
。 - 非线性回归:通过添加非线性层(如
nn.ReLU
)将模型扩展为神经网络。 - 真实数据集:使用
torchvision.datasets
或自定义Dataset
加载实际数据(如 CSV、Excel)。
如果你有具体的线性回归问题(例如处理特定数据集、优化性能等),请提供更多细节,我可以进一步定制代码或解决方案!