使用PyTorch实现线性回归的全面指南

 更新时间:2026年05月19日 08:53:09   作者:独隅  
本文是一份全面的PyTorch线性回归实战指南,从理论基础到代码实现,从简单示例到真实场景应用,系统性地讲解如何使用PyTorch实现线性回归模型,需要的朋友可以参考下

摘要

核心内容包括:

  • ✅ 深入剖析线性回归的数学原理和梯度下降算法
  • ✅ 两种实现方式:从零实现 vs PyTorch高级API
  • ✅ 完整的数据准备、模型训练、评估流程
  • ✅ 4个实战案例:房价预测、股票分析、医疗费用、工业优化
  • ✅ 模型优化技巧和超参数调优指南

适合人群:

  • PyTorch初学者
  • 机器学习入门者
  • 需要快速上手线性回归的数据分析师
  • 准备面试的算法工程师

通过本文的学习,你将掌握使用PyTorch实现线性回归的完整技能,并能够应用到实际项目中。

第1章 线性回归理论基础

1.1 为什么用 PyTorch 学线性回归?

线性回归是机器学习入门的必修课,本质是通过寻找特征与目标值之间的线性关系来进行预测。而在 PyTorch 中,这个过程被动态图机制简化——每个环节都变得可视化且易于调试

虽然线性回归可以用 scikit-learn 几行代码实现,但用 PyTorch 手动构建能深入理解神经网络的基本工作原理,这对后续学习更复杂模型至关重要。伊利诺伊大学的 ECE 364 课程甚至用整整三周(Week 6-8)专门讲授线性回归在 PyTorch 中的实现及其与数据集、数据加载器等组件的结合。

1.2 PyTorch 两大核心特性

与 NumPy 相比,PyTorch 张量额外具备两大关键特性:

  • 自动微分:当你在 PyTorch 中定义模型时,实际上在构建一个计算图——这个图会记录所有操作步骤,并在反向传播时自动计算梯度
  • GPU 加速:张量可以无缝迁移到 GPU 上进行并行计算,显著加速训练过程

线性回归可以使用单层神经网络来实现,所需要用到的概念和技巧也适用于更复杂的深度学习模型。

1.3 线性回归的核心概念

线性回归是机器学习中最基础、最重要的算法之一,它假设目标变量 y 与输入特征 x 之间存在线性关系。

基本公式:

对于单变量线性回归:

y = w * x + b + ε

对于多变量线性回归:

y = w₁x₁ + w₂x₂ + ... + wₙxₙ + b + ε

参数说明:

  • y:预测的目标值(连续型变量)
  • x₁, x₂, ..., xₙ:输入特征
  • w₁, w₂, ..., wₙ:权重参数,表示各特征对目标的影响程度
  • b:偏置项(截距)
  • ε:噪声项,表示模型无法解释的随机误差

1.4 数学原理与公式推导

1.4.1 损失函数(均方误差)

线性回归使用均方误差(MSE)作为损失函数,衡量预测值与真实值之间的差距:

L(w, b) = (1/2n) * Σ(yᵢ - ŷᵢ)²

为什么要除以2?

  • 为了在求导时抵消平方项的系数2,使梯度计算更简洁
  • 不影响优化结果,因为这只是对损失函数的缩放

1.4.2 梯度计算

对损失函数求偏导,得到梯度:

∂L/∂wⱼ = (1/n) * Σ(ŷᵢ - yᵢ) * xⱼᵢ
∂L/∂b = (1/n) * Σ(ŷᵢ - yᵢ)

1.4.3 梯度下降更新规则

wⱼ ← wⱼ - α * ∂L/∂wⱼ
b ← b - α * ∂L/∂b

其中 α 是学习率,控制每次更新的步长。

1.5 损失函数与优化算法

1.5.1 常见损失函数对比

损失函数公式适用场景
MSE(1/2n)Σ(y-ŷ)²回归问题,对异常值敏感
MAE(1/n)Σy-ŷ
Huber分段函数回归问题,平衡MSE和MAE

1.5.2 优化算法对比

优化器特点适用场景
SGD简单直接,需要手动调学习率小数据集,简单模型
SGD with Momentum加入动量,加速收敛一般场景
Adam自适应学习率,收敛快大多数场景
RMSprop适合非平稳目标RNN等

第2章 PyTorch框架入门

2.1 PyTorch核心特性

  • 动态计算图:运行时构建计算图,调试方便
  • Pythonic:API设计符合Python习惯
  • GPU加速:无缝支持CUDA,加速计算
  • 自动求导:自动计算梯度,简化实现

2.2 环境配置与安装

# 创建虚拟环境
python -m venv pytorch_env
source pytorch_env/bin/activate  # Linux/Mac
# pytorch_env\Scripts\activate  # Windows
# 安装PyTorch(CPU版本)
pip install torch torchvision torchaudio
# 安装PyTorch(GPU版本,CUDA 11.8)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# 安装其他依赖
pip install numpy pandas matplotlib seaborn jupyter

2.3 张量操作基础

import torch

# 创建张量
x = torch.tensor([1.0, 2.0, 3.0])  # 从列表创建
y = torch.zeros(3)                 # 零张量
z = torch.ones(2, 3)               # 全1张量
a = torch.randn(2, 2)              # 标准正态分布

# 张量属性
print(f"形状: {x.shape}")
print(f"数据类型: {x.dtype}")
print(f"设备: {x.device}")

# 基本运算
x = torch.tensor([1.0, 2.0, 3.0])
y = torch.tensor([4.0, 5.0, 6.0])
print(f"加法: {x + y}")
print(f"乘法: {x * y}")
print(f"点积: {torch.dot(x, y)}")

# 矩阵运算
A = torch.randn(3, 2)
B = torch.randn(2, 4)
C = torch.matmul(A, B)  # 矩阵乘法
print(f"矩阵乘法结果形状: {C.shape}")

第3章 从零实现线性回归

3.1 数据生成与准备

import torch
import numpy as np

# 设置随机种子,确保可复现
torch.manual_seed(42)
np.random.seed(42)

# 定义真实的模型参数
true_w = torch.tensor([[2.0], [-3.4]])  # 真实权重
true_b = 4.2                            # 真实偏置

# 生成数据
num_examples = 1000  # 样本数量
num_inputs = 2       # 特征数量

# 从标准正态分布中随机生成输入特征
X = torch.normal(0, 1, (num_examples, num_inputs))

# 根据真实公式计算标签,并加入噪声
noise = torch.normal(0, 0.01, (num_examples, 1))
y = torch.matmul(X, true_w) + true_b + noise

print(f"数据集形状: X={X.shape}, y={y.shape}")
print(f"前3个样本:\n{X[:3]}")
print(f"对应标签:\n{y[:3]}")

3.2 模型参数初始化

# 初始化权重 w,从均值为0,标准差为0.01的正态分布中采样
w = torch.normal(0, 0.01, size=(num_inputs, 1), requires_grad=True)

# 初始化偏置 b 为 0
b = torch.zeros(1, requires_grad=True)

print(f"初始权重 w:\n{w}")
print(f"初始偏置 b: {b}")
print(f"w 需要梯度: {w.requires_grad}")
print(f"b 需要梯度: {b.requires_grad}")

关键点:

  • requires_grad=True 告诉 PyTorch 这些参数需要计算梯度
  • 权重通常用小的随机数初始化,避免对称性问题
  • 偏置可以初始化为0

3.3 前向传播与损失计算

def linreg(X, w, b):
    """线性回归模型的前向传播"""
    return torch.matmul(X, w) + b

def squared_loss(y_hat, y):
    """均方损失函数"""
    # 将 y 的形状调整为和 y_hat 一致
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

# 测试前向传播
y_hat = linreg(X[:5], w, b)
print(f"预测值:\n{y_hat}")

# 测试损失计算
loss = squared_loss(y_hat, y[:5])
print(f"损失值:\n{loss}")
print(f"平均损失: {loss.mean()}")

3.4 反向传播与参数更新

def sgd(params, lr, batch_size):
    """
    小批量随机梯度下降优化器
    
    参数:
        params: 需要更新的参数列表,如 [w, b]
        lr: 学习率
        batch_size: 批量大小
    """
    with torch.no_grad():  # 更新参数时,不需要记录梯度
        for param in params:
            # 梯度下降更新公式
            param -= lr * param.grad / batch_size
            # 更新后,手动将梯度清零
            param.grad.zero_()

# 示例:假设我们有梯度
w.grad = torch.tensor([[0.1], [0.2]])
b.grad = torch.tensor([0.05])
lr = 0.03

print(f"更新前 w: {w.flatten()}")
print(f"更新前 b: {b.item()}")

sgd([w, b], lr, 10)

print(f"更新后 w: {w.flatten()}")
print(f"更新后 b: {b.item()}")

3.5 完整训练循环

import random

def data_iter(batch_size, features, labels):
    """
    生成小批量数据的迭代器
    """
    num_examples = len(features)
    indices = list(range(num_examples))
    random.shuffle(indices)  # 打乱样本顺序
    
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)]
        )
        yield features[batch_indices], labels[batch_indices]

# 超参数设置
lr = 0.03        # 学习率
num_epochs = 5   # 训练轮数
batch_size = 10  # 批量大小

# 重新初始化参数
w = torch.normal(0, 0.01, size=(num_inputs, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

# 开始训练
print("=" * 60)
print("开始训练线性回归模型...")
print("=" * 60)

for epoch in range(num_epochs):
    for X_batch, y_batch in data_iter(batch_size, X, y):
        # 1. 前向传播:计算预测值
        y_hat = linreg(X_batch, w, b)
        
        # 2. 计算损失
        loss = squared_loss(y_hat, y_batch).mean()
        
        # 3. 反向传播:计算梯度
        loss.backward()
        
        # 4. 更新参数
        sgd([w, b], lr, batch_size)
    
    # 每个epoch结束后,计算在整个数据集上的平均损失
    with torch.no_grad():
        train_loss = squared_loss(linreg(X, w, b), y).mean()
        print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {train_loss:.6f}')

# 训练结束,查看学习到的参数
print("\n" + "=" * 60)
print("训练完成!模型参数对比:")
print("=" * 60)
print(f'真实的权重 w: {true_w.flatten().numpy()}')
print(f'学到的权重 w: {w.detach().flatten().numpy()}')
print(f'权重误差: {((w - true_w).abs() / true_w.abs()).mean().item():.4%}')
print()
print(f'真实的偏置 b: {true_b:.4f}')
print(f'学到的偏置 b: {b.item():.4f}')
print(f'偏置误差: {abs(b.item() - true_b) / abs(true_b):.4%}')

输出示例:

============================================================
开始训练线性回归模型...
============================================================
Epoch 1/5, Loss: 0.042567
Epoch 2/5, Loss: 0.000152
Epoch 3/5, Loss: 0.000058
Epoch 4/5, Loss: 0.000051
Epoch 5/5, Loss: 0.000050

============================================================
训练完成!模型参数对比:
============================================================
真实的权重 w: [ 2.  -3.4]
学到的权重 w: [ 1.9998 -3.3995]
权重误差: 0.0123%
真实的偏置 b: 4.2000
学到的偏置 b: 4.1998
偏置误差: 0.0048%

第4章 PyTorch高级API实现

4.1 nn.Module模型定义

import torch.nn as nn

class LinearRegressionModel(nn.Module):
    def __init__(self, input_dim):
        super(LinearRegressionModel, self).__init__()
        # 定义线性层
        self.linear = nn.Linear(input_dim, 1)
    
    def forward(self, x):
        # 前向传播
        return self.linear(x)

# 创建模型
model = LinearRegressionModel(num_inputs)
print(model)
print(f"\n模型参数:")
for name, param in model.named_parameters():
    print(f"  {name}: {param.shape}")

输出:

LinearRegressionModel(
  (linear): Linear(in_features=2, out_features=1, bias=True)
)

模型参数:
  linear.weight: torch.Size([1, 2])
  linear.bias: torch.Size([1])

4.2 内置损失函数与优化器

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器
optimizer = torch.optim.SGD(model.parameters(), lr=0.03)

# 训练循环
num_epochs = 5
for epoch in range(num_epochs):
    for X_batch, y_batch in data_iter(batch_size, X, y):
        # 前向传播
        y_pred = model(X_batch)
        
        # 计算损失
        loss = criterion(y_pred, y_batch)
        
        # 反向传播
        optimizer.zero_grad()  # 梯度清零
        loss.backward()        # 计算梯度
        
        # 更新参数
        optimizer.step()
    
    # 打印训练进度
    if (epoch + 1) % 1 == 0:
        with torch.no_grad():
            y_pred = model(X)
            epoch_loss = criterion(y_pred, y).item()
            print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.6f}')

# 查看学习到的参数
print("\n学到的参数:")
print(f"w: {model.linear.weight.data.numpy()}")
print(f"b: {model.linear.bias.item()}")

4.3 DataLoader数据加载器

from torch.utils.data import TensorDataset, DataLoader

# 创建数据集
dataset = TensorDataset(X, y)

# 创建数据加载器
data_loader = DataLoader(
    dataset=dataset,
    batch_size=batch_size,
    shuffle=True,      # 每个epoch打乱数据
    num_workers=0      # 数据加载的子进程数
)

# 使用 DataLoader 训练
model = LinearRegressionModel(num_inputs)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

for epoch in range(num_epochs):
    for X_batch, y_batch in data_loader:
        y_pred = model(X_batch)
        loss = criterion(y_pred, y_batch)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    
    if (epoch + 1) % 1 == 0:
        with torch.no_grad():
            y_pred = model(X)
            epoch_loss = criterion(y_pred, y).item()
            print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.6f}')

4.4 训练过程可视化

import matplotlib.pyplot as plt

# 记录训练过程
train_losses = []
model = LinearRegressionModel(num_inputs)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

for epoch in range(20):
    epoch_loss = 0
    for X_batch, y_batch in data_loader:
        y_pred = model(X_batch)
        loss = criterion(y_pred, y_batch)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        epoch_loss += loss.item()
    
    avg_loss = epoch_loss / len(data_loader)
    train_losses.append(avg_loss)

# 绘制损失曲线
plt.figure(figsize=(10, 6))
plt.plot(range(1, len(train_losses) + 1), train_losses, marker='o')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss Curve')
plt.grid(True)
plt.savefig('training_loss.png', dpi=300, bbox_inches='tight')
plt.show()

# 预测结果可视化
with torch.no_grad():
    y_pred = model(X).numpy()
    
plt.figure(figsize=(10, 6))
plt.scatter(y.numpy(), y_pred, alpha=0.5)
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--')
plt.xlabel('True Values')
plt.ylabel('Predictions')
plt.title('True vs Predicted Values')
plt.grid(True)
plt.savefig('predictions.png', dpi=300, bbox_inches='tight')
plt.show()

第5章 实战应用案例

5.1 房价预测项目

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score

# 生成模拟房价数据
np.random.seed(42)
n_samples = 1000

data = {
    'area': np.random.uniform(50, 200, n_samples),        # 面积
    'rooms': np.random.randint(1, 6, n_samples),          # 房间数
    'age': np.random.uniform(0, 30, n_samples),           # 房龄
    'distance_to_center': np.random.uniform(1, 20, n_samples)  # 距离市中心
}

# 生成价格
data['price'] = (
    1.5 * data['area'] +          # 面积系数
    10 * data['rooms'] +          # 房间数系数
    -0.8 * data['age'] +          # 房龄系数
    -2 * data['distance_to_center'] +  # 距离系数
    50 +                          # 基础价格
    np.random.normal(0, 20, n_samples)  # 噪声
)

df = pd.DataFrame(data)

# 特征和标签
X = df[['area', 'rooms', 'age', 'distance_to_center']].values
y = df['price'].values.reshape(-1, 1)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

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

# 转换为PyTorch张量
X_train_tensor = torch.FloatTensor(X_train_scaled)
y_train_tensor = torch.FloatTensor(y_train)
X_test_tensor = torch.FloatTensor(X_test_scaled)
y_test_tensor = torch.FloatTensor(y_test)

# 创建数据加载器
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
train_loader = DataLoader(dataset=train_dataset, batch_size=32, shuffle=True)

# 定义模型
class HousePriceModel(nn.Module):
    def __init__(self, input_dim):
        super(HousePriceModel, self).__init__()
        self.linear = nn.Linear(input_dim, 1)
    
    def forward(self, x):
        return self.linear(x)

model = HousePriceModel(X_train_scaled.shape[1])
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

# 训练
num_epochs = 100
for epoch in range(num_epochs):
    for X_batch, y_batch in train_loader:
        y_pred = model(X_batch)
        loss = criterion(y_pred, y_batch)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

# 评估
model.eval()
with torch.no_grad():
    y_pred_train = model(X_train_tensor).numpy()
    y_pred_test = model(X_test_tensor).numpy()
    
    train_rmse = np.sqrt(mean_squared_error(y_train, y_pred_train))
    test_rmse = np.sqrt(mean_squared_error(y_test, y_pred_test))
    train_r2 = r2_score(y_train, y_pred_train)
    test_r2 = r2_score(y_test, y_pred_test)
    
    print(f"训练集 RMSE: {train_rmse:.2f} (万元)")
    print(f"测试集 RMSE: {test_rmse:.2f} (万元)")
    print(f"训练集 R²: {train_r2:.4f}")
    print(f"测试集 R²: {test_r2:.4f}")

5.2 股票趋势分析

# 模拟股票数据
dates = pd.date_range('2023-01-01', periods=365, freq='D')
np.random.seed(42)

stock_data = {
    'date': dates,
    'open': np.random.uniform(100, 150, 365),
    'high': np.random.uniform(105, 155, 365),
    'low': np.random.uniform(95, 145, 365),
    'volume': np.random.uniform(1000000, 5000000, 365),
    'close': np.random.uniform(100, 150, 365) + np.random.normal(0, 2, 365)
}

stock_df = pd.DataFrame(stock_data)
stock_df['return'] = stock_df['close'].pct_change()  # 日收益率
stock_df = stock_df.dropna()

print("股票数据示例:")
print(stock_df.head())
print(f"\n数据集形状: {stock_df.shape}")

5.3 医疗费用预测

# 模拟医疗数据
n_patients = 1000
medical_data = {
    'age': np.random.randint(18, 80, n_patients),
    'bmi': np.random.uniform(18, 40, n_patients),
    'smoker': np.random.choice([0, 1], n_patients, p=[0.8, 0.2]),
    'children': np.random.randint(0, 5, n_patients),
    'charges': (
        200 * medical_data['age'] +
        300 * medical_data['bmi'] +
        10000 * medical_data['smoker'] +
        500 * medical_data['children'] +
        np.random.normal(0, 2000, n_patients)
    )
}

medical_df = pd.DataFrame(medical_data)

print("医疗数据统计:")
print(f"吸烟者平均费用: {medical_df[medical_df['smoker']==1]['charges'].mean():.2f}")
print(f"非吸烟者平均费用: {medical_df[medical_df['smoker']==0]['charges'].mean():.2f}")
print(f"费用标准差: {medical_df['charges'].std():.2f}")

5.4 工业生产优化

# 模拟生产数据
n_samples = 500
production_data = {
    'temperature': np.random.uniform(150, 250, n_samples),
    'pressure': np.random.uniform(5, 15, n_samples),
    'time': np.random.uniform(10, 60, n_samples),
    'speed': np.random.uniform(50, 150, n_samples),
    'quality': (
        0.3 * production_data['temperature'] +
        0.5 * production_data['pressure'] +
        0.2 * production_data['time'] -
        0.1 * production_data['speed'] +
        50 + np.random.normal(0, 5, n_samples)
    )
}

prod_df = pd.DataFrame(production_data)

# 找出最优参数组合
optimal_params = {
    'temperature': prod_df.loc[prod_df['quality'].idxmax(), 'temperature'],
    'pressure': prod_df.loc[prod_df['quality'].idxmax(), 'pressure'],
    'time': prod_df.loc[prod_df['quality'].idxmax(), 'time'],
    'speed': prod_df.loc[prod_df['quality'].idxmax(), 'speed'],
    'quality': prod_df['quality'].max()
}

print("最优生产参数:")
for k, v in optimal_params.items():
    print(f"  {k}: {v:.2f}")

第6章 模型优化与调参

6.1 学习率调优策略

# 不同学习率对比
learning_rates = [0.001, 0.01, 0.03, 0.1, 0.3]
results = {}

for lr in learning_rates:
    model = LinearRegressionModel(num_inputs)
    optimizer = torch.optim.SGD(model.parameters(), lr=lr)
    criterion = nn.MSELoss()
    
    losses = []
    for epoch in range(20):
        epoch_loss = 0
        for X_batch, y_batch in data_loader:
            y_pred = model(X_batch)
            loss = criterion(y_pred, y_batch)
            
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            
            epoch_loss += loss.item()
        
        losses.append(epoch_loss / len(data_loader))
    
    results[lr] = losses[-1]  # 记录最终损失

print("不同学习率的最终损失:")
for lr, loss in results.items():
    print(f"  lr={lr:.3f}: {loss:.6f}")

6.2 批量大小选择

batch_sizes = [4, 8, 16, 32, 64, 128]
results = {}

for bs in batch_sizes:
    data_loader = DataLoader(dataset=dataset, batch_size=bs, shuffle=True)
    model = LinearRegressionModel(num_inputs)
    optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
    criterion = nn.MSELoss()
    
    for epoch in range(10):
        for X_batch, y_batch in data_loader:
            y_pred = model(X_batch)
            loss = criterion(y_pred, y_batch)
            
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
    
    with torch.no_grad():
        final_loss = criterion(model(X), y).item()
        results[bs] = final_loss

print("不同批量大小的最终损失:")
for bs, loss in results.items():
    print(f"  batch_size={bs}: {loss:.6f}")

6.3 正则化技术

# L2正则化(权重衰减)
model = LinearRegressionModel(num_inputs)
optimizer = torch.optim.SGD(
    model.parameters(), 
    lr=0.01, 
    weight_decay=0.01  # L2正则化系数
)
criterion = nn.MSELoss()

# 训练
for epoch in range(20):
    for X_batch, y_batch in data_loader:
        y_pred = model(X_batch)
        loss = criterion(y_pred, y_batch)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

print("L2正则化后的权重:")
print(f"w: {model.linear.weight.data.numpy()}")
print(f"权重范数: {torch.norm(model.linear.weight).item():.4f}")

6.4 早停与模型保存

# 早停实现
class EarlyStopping:
    def __init__(self, patience=5, min_delta=0.001):
        self.patience = patience
        self.min_delta = min_delta
        self.counter = 0
        self.best_loss = None
        self.early_stop = False
    
    def __call__(self, val_loss):
        if self.best_loss is None:
            self.best_loss = val_loss
        elif val_loss > self.best_loss - self.min_delta:
            self.counter += 1
            if self.counter >= self.patience:
                self.early_stop = True
        else:
            self.best_loss = val_loss
            self.counter = 0
        
        return self.early_stop

# 模型保存与加载
model = LinearRegressionModel(num_inputs)
torch.save(model.state_dict(), 'linear_model.pth')

# 加载模型
model_loaded = LinearRegressionModel(num_inputs)
model_loaded.load_state_dict(torch.load('linear_model.pth'))
model_loaded.eval()

第7章 常见问题与解决方案

问题解决方案
损失不下降增大学习率或检查数据是否标准化
损失震荡剧烈减小学习率
梯度为 NaN学习率过大导致梯度爆炸,降低学习率
训练集和测试集差距大过拟合,增加数据量或添加正则化
忘记 zero_grad()每次迭代前必须调用 optimizer.zero_grad()
GPU 不可用检查 CUDA 版本与 PyTorch 版本是否匹配

7.1 损失不下降

问题: 训练过程中损失值保持不变或震荡

解决方案:

# 1. 检查学习率是否合适
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 尝试更小的学习率

# 2. 检查数据是否标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 3. 检查梯度是否正常
for name, param in model.named_parameters():
    print(f"{name} gradient norm: {param.grad.norm().item()}")

7.2 过拟合问题

问题: 训练集表现好,测试集表现差

解决方案:

# 1. 使用正则化
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=0.01)

# 2. 增加数据
# 3. 减少模型复杂度
# 4. 使用早停
early_stopping = EarlyStopping(patience=5)

7.3 GPU加速

# 检查GPU可用性
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"使用设备: {device}")

# 将模型和数据移动到GPU
model = model.to(device)
X = X.to(device)
y = y.to(device)

# 训练时同样在GPU上
for X_batch, y_batch in data_loader:
    X_batch = X_batch.to(device)
    y_batch = y_batch.to(device)
    
    y_pred = model(X_batch)
    loss = criterion(y_pred, y_batch)
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

总结

本文从 PyTorch 的基础特性出发,系统讲解了线性回归的完整实现流程——从 nn.Linear 的模型定义、nn.MSELoss 的损失计算、optim.SGD 的参数优化,到 DataLoader 的批量加载、GPU 加速的部署优化、模型的保存与评估。核心要点:

  1. PyTorch 三大核心组件nn.Linear(模型)、nn.MSELoss(损失)、optim.SGD(优化器)是构建任何深度学习模型的基石
  2. 训练循环四步法:前向传播 → 损失计算 → 反向传播 → 参数更新,是 PyTorch 训练的标准范式
  3. 工程化实践:DataLoader 批量加载、训练测试分离、GPU 加速、模型保存加载是实际项目中不可或缺的技能
  4. 从零到框架的对应关系:理解简洁 API 背后的实现逻辑,是掌握深度学习的必经之路

线性回归虽简单,但其中蕴含的前向传播、损失计算、梯度下降、参数更新等概念,是所有复杂深度学习模型的基础。掌握 PyTorch 实现线性回归的完整流水线,你将轻松过渡到更复杂的神经网络模型。

附录

附录A:完整代码实现

"""
PyTorch线性回归完整实现
"""

import torch
import numpy as np
import random
import matplotlib.pyplot as plt
from torch.utils.data import TensorDataset, DataLoader

# ==================== 1. 数据生成 ====================
def generate_data(num_examples=1000, num_inputs=2, seed=42):
    """生成带噪声的线性数据"""
    torch.manual_seed(seed)
    np.random.seed(seed)
    
    true_w = torch.tensor([[2.0], [-3.4]])
    true_b = 4.2
    
    X = torch.normal(0, 1, (num_examples, num_inputs))
    noise = torch.normal(0, 0.01, (num_examples, 1))
    y = torch.matmul(X, true_w) + true_b + noise
    
    return X, y, true_w, true_b

# ==================== 2. 数据迭代器 ====================
def data_iter(batch_size, features, labels):
    """生成小批量数据"""
    num_examples = len(features)
    indices = list(range(num_examples))
    random.shuffle(indices)
    
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)]
        )
        yield features[batch_indices], labels[batch_indices]

# ==================== 3. 模型定义 ====================
def linreg(X, w, b):
    """线性回归模型"""
    return torch.matmul(X, w) + b

# ==================== 4. 损失函数 ====================
def squared_loss(y_hat, y):
    """均方损失函数"""
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

# ==================== 5. 优化器 ====================
def sgd(params, lr, batch_size):
    """小批量随机梯度下降"""
    with torch.no_grad():
        for param in params:
            param -= lr * param.grad / batch_size
            param.grad.zero_()

# ==================== 6. 训练函数 ====================
def train_linear_regression(
    X, y, true_w, true_b,
    lr=0.03, num_epochs=5, batch_size=10
):
    """训练线性回归模型"""
    num_inputs = X.shape[1]
    
    # 初始化参数
    w = torch.normal(0, 0.01, size=(num_inputs, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)
    
    losses = []
    
    print("开始训练...")
    print("=" * 60)
    
    for epoch in range(num_epochs):
        for X_batch, y_batch in data_iter(batch_size, X, y):
            # 前向传播
            y_hat = linreg(X_batch, w, b)
            
            # 计算损失
            loss = squared_loss(y_hat, y_batch).mean()
            
            # 反向传播
            loss.backward()
            
            # 更新参数
            sgd([w, b], lr, batch_size)
        
        # 计算epoch损失
        with torch.no_grad():
            epoch_loss = squared_loss(linreg(X, w, b), y).mean().item()
            losses.append(epoch_loss)
            print(f'Epoch {epoch + 1}/{num_epochs}, Loss: {epoch_loss:.6f}')
    
    # 评估结果
    print("\n" + "=" * 60)
    print("训练完成!")
    print("=" * 60)
    print(f'真实权重: {true_w.flatten().numpy()}')
    print(f'学到权重: {w.detach().flatten().numpy()}')
    print(f'权重相对误差: {((w - true_w).abs() / true_w.abs()).mean().item():.4%}')
    print()
    print(f'真实偏置: {true_b:.4f}')
    print(f'学到偏置: {b.item():.4f}')
    print(f'偏置相对误差: {abs(b.item() - true_b) / abs(true_b):.4%}')
    
    return w, b, losses

# ==================== 7. 主函数 ====================
def main():
    # 生成数据
    X, y, true_w, true_b = generate_data()
    
    # 训练模型
    w, b, losses = train_linear_regression(X, y, true_w, true_b)
    
    # 可视化损失曲线
    plt.figure(figsize=(10, 6))
    plt.plot(range(1, len(losses) + 1), losses, marker='o')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.title('Training Loss Curve')
    plt.grid(True)
    plt.savefig('training_loss.png', dpi=300, bbox_inches='tight')
    plt.show()

if __name__ == "__main__":
    main()

附录B:API速查表

功能PyTorch API说明
创建张量torch.tensor()从数据创建张量
随机张量torch.randn()标准正态分布
线性层nn.Linear()全连接层
MSE损失nn.MSELoss()均方误差
SGD优化器optim.SGD()随机梯度下降
Adam优化器optim.Adam()自适应矩估计
数据加载DataLoader()批量数据加载

通过本文,你不仅掌握了线性回归的理论和实现,更建立了使用PyTorch进行深度学习开发的完整技能体系。

以上就是使用PyTorch实现线性回归的全面指南的详细内容,更多关于PyTorch实现线性回归的资料请关注脚本之家其它相关文章!

相关文章

  • pytorch 6 batch_train 批训练操作

    pytorch 6 batch_train 批训练操作

    这篇文章主要介绍了pytorch 6 batch_train 批训练操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-05-05
  • 解决python写入带有中文的字符到文件错误的问题

    解决python写入带有中文的字符到文件错误的问题

    今天小编就为大家分享一篇解决python写入带有中文的字符到文件错误的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-01-01
  • Python Flask入门

    Python Flask入门

    今天小编就为大家分享一篇Python Flask的入门教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-11-11
  • 详解Python中DOM方法的动态性

    详解Python中DOM方法的动态性

    这篇文章主要介绍了详解Python中DOM方法的动态性,xml.dom模块在Python的网络编程中相当有用,本文来自于IBM官网的开发者技术文档,需要的朋友可以参考下
    2015-04-04
  • Python中Namespace()函数详解

    Python中Namespace()函数详解

    Namespace是argparse模块提供的一个类,用于创建命名空间对象,它允许通过点操作符访问数据,比字典更易读,在深度学习项目中常用于加载配置、命令行参数和超参数,本文介绍Python中Namespace()函数,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • turtle的基础使用之python turtle递归绘图

    turtle的基础使用之python turtle递归绘图

    这篇文章主要介绍了turtle的基础使用之python turtle递归绘图,turtle是一种比较简单的第三方库,下面借助递归绘图详细描述该内容,具有一的的知识性参考价值,需要的朋友可以参考一下
    2022-02-02
  • 使用Python的pygame库绘制图形示例详解

    使用Python的pygame库绘制图形示例详解

    这篇文章主要介绍了使用Python的Pygame库绘制图形的方法,Pygame是被设计用来写游戏的python模块集合,Pygame是在优秀的SDL库之上开发的功能性包,通常使用Pygame来开发具有全部特性的游戏和多媒体软件,感兴趣的朋友可以参考下
    2024-02-02
  • Tensorflow2.10使用BERT从文本中抽取答案实现详解

    Tensorflow2.10使用BERT从文本中抽取答案实现详解

    这篇文章主要为大家介绍了Tensorflow2.10使用BERT从文本中抽取答案实现详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • Python绘图示例程序中的几个语法糖果你知道吗

    Python绘图示例程序中的几个语法糖果你知道吗

    这篇文章主要为大家详细介绍了Python绘图示例程序中的几个语法糖果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • python自定义函数def的应用详解

    python自定义函数def的应用详解

    这篇文章主要介绍了python自定义函数def的应用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06

最新评论