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.DatasetDataLoader 来高效加载数据。

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 加速:确保数据和模型都在同一设备(cpucuda)。

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)。

如果你有具体的线性回归问题(例如处理特定数据集、优化性能等),请提供更多细节,我可以进一步定制代码或解决方案!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注