PyTorch实现线性回归

PyTorch 最基础的神经网络模板代码**,**分为四个步骤:

1. 准备数据集(Prepare Dataset)

本实例是最基本的一元线性回归,需要导入的数据较少。

python 复制代码
import torch
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[2.0], [4.0], [6.0]])
  • ***[[1.0], [2.0], [3.0]] :***二维列表(矩阵),外层列表表示样本集,内层每个列表表示单个样本的特征。
  • torch.Tensor() : PyTorch 的张量(Tensor)构造函数,将 Python 列表转换为 PyTorch 核心数据结构Tensor(张量)(默认创建float32类型张量)。

2. 设计模型(Design model)

在PyTorch中使用类来设计模型,模型类必须继承*torch.nn.Module。*定义线性回归模型类:

python 复制代码
class LinearModel(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = torch.nn.Linear(1, 1)

    def forward(self, x):
        y_pred = self.linear(x)
        return y_pred

model = LinearModel()
  • class LinearModel(torch.nn.Module): 定义自定义类LinearModeltorch.nn.Module 表示此类继承PyTorch的基类nn.Module(子类*LinearModel* 会完全继承父类*nn.Module*的所有属性和方法)
  • ***def init(self):***类的构造方法,创建类的实例时自动执行,在构造方法中初始化模型的层 及参数,是定义模型结构的固定位置。
  • super().init():super().init() 作用是执行父类nn.Moduleinit() ,如果不写这行,父类*nn.Module* 的初始化逻辑不会执行,模型无法管理参数、无法构建计算图,直接报错(如果子类中没有*init()* 方法,继承父类时会自动调用父类的*init()* ,如果子类中已经有了*init()* 方法,则父类的*init()* 不会自动调用)。
    除了super().init(), 也可以使用super() 来调用父类的其他方法。
    事实上在这种单继承场景下,直接写Module.init() 效果和super().init ()一样,之所以使用super().init() ,第一个好处是当父类名称修改时我们只需要修改class类定义中的父类而不需要将内部调用父类方法的父类名称都修改;第二个好处是在多继承时,可以避免手动调用父类方法导致的逻辑混乱。
  • self.linear = torch.nn.Linear(1, 1): 定义类LinearModel 的第一个属性linear ,本质是实例化 PyTorch 内置的Linear类,并将这个实例赋值给self.linear(类的属性),同时自动初始化了weightbias两个可训练参数,可通过linear.weightlinear.bias 访问。self.linear 是模型的核心计算层,后续前向传播直接调用它即可。
    Linear 类同样继承自nn.Module其底层已经实现了线性计算和参数初始化逻辑。并且也存在方法forward ,可通过*self.linear(x)*直接调用。(关于Linear类的底层逻辑在文章下方有补充说明)
  • def forward(self, x): forward 是*nn.Module* 的固定方法名,必须叫forward ,用于定义前向传播的计算逻辑。当我们调用*model(x)* 时,PyTorch 底层会自动调用forward 方法,无需手动写*model.forward(x)*。
  • y_pred = self.linear(x): 执行线性层的前向计算,得到模型的预测值*y_pred* ,同时自动构建计算图(为后续反向传播求导做准备)。
    这里的y_pred 仍为Tensor(张量),因为线性层的底层*forward*方法返回的是 Tensor
  • model = LinearModel(): 实例化自定义类*LinearModel* ,创建模型对象model。此时模型完成初始化,线性层的被随机初始化,所有可训练参数被*nn.Module* 注册,可通过*model.parameters()*查看。

关于线性模型的具体解释可以参考文章PyTorch_conda-CSDN博客中《Linear Layers(线性层)》一节。

3. 构造损失函数(Construct Loss)

python 复制代码
criterion = torch.nn.MSELoss(reduction='sum')
  • 直接调用 PyTorch 内置的损失函数。
  • 实例化 PyTorch 的MSELoss类,赋值给criterion(准则 / 损失函数)。
  • MSELoss是均方误差损失,对应线性回归的损失公式:

参数说明: 在旧版本中使用size_average参数来决定是否求平均值,若size_average=False,即criterion = torch.nn.MSELoss(size_average=False),表示不对损失求平均值(即省略公式的)。

新版本中size_average即将被移除,改为reduction。若reduction='sum' ,则计算所有样本损失的总和;若reduction='mean' ,则计算所有样本损失的平均值;若reduction='none',则保留每个样本的损失值(张量),最终得到的 loss 是一个和样本数量对应的张量。

4. 构造优化器(Construct Optimizer)

python 复制代码
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
  • ***SGD:***随机梯度下降优化器,最基础的优化算法。
  • ***model.parameters():***获取模型所有可训练参数(线性层的w和b),告诉优化器要更新哪些参数。
  • ***lr=0.01:***学习率,控制参数更新的步长,步长太大不收敛,太小收敛慢。

5. 训练循环(Training Cycle)

循环迭代 1000 次,每一轮都完成**"前向传播算损失→反向传播算梯度→优化器更新参数"** ,让模型的w和b不断逼近真实值。

python 复制代码
for epoch in range(1000):
    y_pred = model(x_data)  # 前向传播(计算预测值)
    loss = criterion(y_pred, y_data)  # 计算损失值
    print(epoch, loss.item())

    optimizer.zero_grad()  # 梯度清零
    loss.backward()  # 反向传播计算梯度
    optimizer.step()  # 更新参数
  • y_pred = model(x_data): 底层自动调用的forward方法,执行线性计算,得到所有样本的预测值,同时构建动态计算图,记录所有计算过程,为反向传播求导做准备。
  • loss = criterion(y_pred, y_data): 调用损失函数实例criterion,传入预测值、真实值,计算得到当前轮次的损失值loss。
    torch.nn.MSELoss类同样继承自Module,criterion(y_pred, y_data) 本质是调用 MSELoss 类的*forward* 方法,此方法返回的loss为Tensor(张量),只有 Tensor 能携带计算图和梯度函数,让 PyTorch 知道 "loss 由 y_pred 计算而来,y_pred 由 weight/bias 计算而来",从而反向推导参数的梯度,因此后续可以使用loss.backward() 方法。
    (关于MSELoss类的底层逻辑在文章下方有补充说明)
  • ***optimizer.zero_grad():***梯度清零,这行必须写,否则梯度会自动累加,上一轮的梯度如果不清零,会和本轮梯度叠加,导致参数更新错误。
  • loss.backward(): 调用张量lossbackward()方法,自动微分引擎会根据前向传播的计算图,自动计算所有可训练参数的梯度,并将梯度存储在参数的.grad属性中;
  • optimizer.step(): 优化器读取参数的梯度.grad,根据 SGD 算法自动更新权重和偏置。

补充1:Linear类底层逻辑,更深刻理解***self.linear = torch.nn.Linear(1, 1)***这一步的linear都有哪些属性与方法

python 复制代码
# 模拟PyTorch的nn.Linear底层
class Linear(nn.Module):
    def __init__(self, in_features, out_features, bias=True):
        super().__init__()
        self.in_features = in_features  # 输入维度
        self.out_features = out_features # 输出维度
        # 初始化权重(可训练参数)
        self.weight = nn.Parameter(torch.randn(out_features, in_features))
        if bias:
            # 初始化偏置(可训练参数)
            self.bias = nn.Parameter(torch.randn(out_features))
        else:
            self.bias = None

    def forward(self, x):
        # 线性计算核心:y = x * weight^T + bias
        output = x @ self.weight.t()  # @是矩阵乘法,.t()是转置
        if self.bias is not None:
            output += self.bias
        return output

补充2:MSELoss类的底层逻辑,更深刻理解criterion = nn.MSELoss(size_average=False) 这一步的criterion都有哪些属性与方法

python 复制代码
# 模拟MSELoss的底层
class MSELoss(nn.Module):
    def __init__(self, size_average=False):
        super().__init__()
        self.size_average = size_average

    def forward(self, input, target):
        # 计算均方误差:(预测值-真实值)^2 的和/均值
        diff = input - target
        square_diff = diff **2
        if self.size_average:
            loss = square_diff.mean()  # 均值
        else:
            loss = square_diff.sum()   # 求和(对应你的代码)
        return loss

完整实例

python 复制代码
import torch

x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[2.0], [4.0], [6.0]])


class LinearModel(torch.nn.Module):

    def __init__(self):
        super(LinearModel, self).__init__()
        self.linear = torch.nn.Linear(1, 1)

    def forward(self, x):
        y_pred = self.linear(x)
        return y_pred

model = LinearModel()


criterion = torch.nn.MSELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)


for epoch in range(1000):
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    print(epoch, loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

print('w = ', model.linear.weight.item())
print('b = ', model.linear.bias.item())


# 推理预测
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred = ', y_test.data)
  • item(): PyTorch 标量张量(只有一个元素的 Tensor) 特有的方法。将标量 Tensor 转换成Python 原生的数值类型(int/float),同时剥离 Tensor 携带的计算图、梯度、设备(CPU/GPU)等所有额外信息,只保留纯数值
相关推荐
AI资源库1 小时前
OpenClaw:159K Star的开源AI助手正在重新定义“个人AI“的边界
人工智能·语言模型
凯子坚持 c1 小时前
StreamingLLM:无需训练即可支持无限上下文的推理技术
人工智能
Tfly__1 小时前
在PX4 gazebo仿真中加入Mid360(最新)
linux·人工智能·自动驾驶·ros·无人机·px4·mid360
LLWZAI1 小时前
让朱雀AI检测无法判断的AI公众号文章,当创作者开始与算法「躲猫猫」
大数据·人工智能·深度学习
深圳市九鼎创展科技2 小时前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
HELLO程序员2 小时前
Claude Code 2.1 发布:2026 年 AI 智能体开发的范式革命
人工智能
DFCED2 小时前
OpenClaw部署实战:5分钟搭建你的专属AI数字员工(附避坑指南)
人工智能·大模型·agent·openclaw
Java新手村2 小时前
基于 Vue 3 + Spring Boot 3 的 AI 面试辅助系统:实时语音识别 + 大模型智能回答
vue.js·人工智能·spring boot
Junlan272 小时前
Cursor使用入门及连接服务器方法(更新中)
服务器·人工智能·笔记