当前位置: 首页 > news >正文

pytorch线性回归(二)

前言

在上文《pytorch线性回归》一文中,我们有如下线性回归训练代码:

def train(inputs, target, w, times=50, step=0.01):global loss, outputfor i in range(times):output = inputs.mv(w)loss = (output - target).pow(2).sum()loss.backward()w.data -= step * w.gradw.grad.zero_()#...

其中:

  • output = inputs.mv(w):输入矩阵与权重向量相乘,也就是前向传播过程。
  • loss = (output - target).pow(2).sum():计算损失值,即∑∣Y−X∣2\sum|Y-X|^2YX2。也可以用均方差1n∑∣Y−X∣2\frac{1}{n}\sum|Y-X|^2n1YX2,实质上应该不影响结果。
  • loss.backward():反向传播,计算叶子节点偏导。
  • w.data -= step * w.grad:梯度下降迭代过程,对权重向量进行更新。
  • w.grad.zero_():清空权重向量的grad值,防止梯度累积影响后续训练过程。这一步与上一步的梯度下降迭代一起称为优化过程。

其实pytorch中已经有了相关损失函数、线性计算、优化过程的函数,下面看看如何基于pytorch这些函数来做线性回归的训练。

1、导入相关库

import torch
import matplotlib.pyplot as pltfrom torch import nn, optim
from time import perf_counter

导入如上库,其中:

  • torch:pytorch库
  • matplotlib.pyplot:数据图形绘制库
  • torch下的nn和optim:nn是Neural Network的缩写,optim则是优化器相关
  • time下的perf_counter用于计算训练耗时

2、准备数据

用之前生成的数据,其中y是用y = 1.2 * x + 3 + 0.2 * torch.rand(x.size())生成的,即y‌≈1.2x+3y‌ \approx 1.2x + 3y1.2x+3。并且通过view函数把一行50列的数据转换成50行一列的数据,方便后续计算:

x = torch.Tensor([-5.0000, -4.7959, -4.5918, -4.3878, -4.1837, -3.9796, -3.7755, -3.5714, -3.3673, -3.1633, -2.9592, -2.7551,-2.5510, -2.3469, -2.1429, -1.9388, -1.7347, -1.5306, -1.3265, -1.1224, -0.9184, -0.7143, -0.5102, -0.3061,-0.1020, 0.1020, 0.3061, 0.5102, 0.7143, 0.9184, 1.1224, 1.3265, 1.5306, 1.7347, 1.9388, 2.1429, 2.3469, 2.5510,2.7551, 2.9592, 3.1633, 3.3673, 3.5714, 3.7755, 3.9796, 4.1837, 4.3878, 4.5918, 4.7959, 5.0000])
y = torch.Tensor([-2.9354, -2.6106, -2.5070, -2.1573, -2.0062, -1.7503, -1.3872, -1.2434, -1.0399, -0.7758, -0.3666, -0.2873,-0.0095, 0.3227, 0.4873, 0.8658, 1.0763, 1.2531, 1.4564, 1.7801, 2.0736, 2.1845, 2.4290, 2.6380, 2.9424, 3.3018,3.3983, 3.6191, 4.0433, 4.1419, 4.5190, 4.7428, 4.9229, 5.1000, 5.4449, 5.7140, 5.8567, 6.1416, 6.3126, 6.6015,6.9624, 7.1786, 7.4084, 7.5916, 7.9413, 8.1177, 8.4207, 8.5427, 8.8767, 9.1533])print(x.shape, y.shape)
# 输出torch.Size([50]) torch.Size([50])x = x.view(-1, 1)
y = y.view(-1, 1)print(x.shape, y.shape)
# 输出torch.Size([50, 1]) torch.Size([50, 1])

3、定义绘制数据图表函数

入参x、y是原始数据x、y;calcOutput是训练后根据x和模型权重计算的输出值;loss则是损失值:

def draw_result(x, y, calcOutput, loss):plt.scatter(x.numpy(), y.numpy())plt.plot(x.numpy(), calcOutput.data.numpy(), 'r-', lw=2)plt.text(0.5, 0, 'loss=%s' % loss.item())plt.show()

4、定义自己的模型

定义自己的线性回归模型类MyLinear,该类继承nn.Module。并且在该类的初始化函数__init__中定义linear,linear实际上是用nn中预设好的线性神经网络模块nn.linear来构造线性模型。nn.linear的in_features代表输入数据的维度,out_features则是代表输出参数的维度,我们这里的数据都是一维的,因此两个值都是1。

class MyLiner(nn.Module):def __init__(self):super(MyLiner, self).__init__()self.linear = nn.Linear(in_features=1, out_features=1)def forward(self, x):return self.linear(x)

5、定义训练函数

训练函数入参model就是我们的自定义模型实例;x、y是原始数据;times代表训练次数,默认5w次;lr(learning rate)代表学习率,也可以理解为步长,默认0.01。

函数里我们这里用nn预设值的均方差函数MSELoss(也就是前文提到的1n∑∣Y−X∣2\frac{1}{n}\sum|Y-X|^2n1YX2)来作为损失函数,梯度下降则改为optim下的随机梯度下降算法SGD。随机梯度下降相比于普通梯度下降,一方面可以避免一次性加载全部数据导致内存溢出问题,有能防止优化的时候陷入局部最小值。

在梯度下降的for循环迭代中,则是先把x给自定义模型计算当前权重下的输出值output,再用1n∑∣Y−X∣2\frac{1}{n}\sum|Y-X|^2n1YX2计算损失值。之后先把优化器optimizer的梯度清零防止累积影响后续训练,然后backward反向传播计算梯度,最后用step更新优化器的权重值。

训练后打印权重值model.parameters、损失值loss,并绘制数据图表

def train(model, x, y, times=50000, lr=1e-2):criterion = nn.MSELoss()optimizer = optim.SGD(model.parameters(), lr=lr)global loss, outputfor i in range(times):output = model(x)loss = criterion(output, y)optimizer.zero_grad()loss.backward()optimizer.step()print(list(model.parameters()))print(loss)draw_result(x, y, output, loss)

6、串联逻辑

把上面函数逻辑串联起来:

model = MyLinear()
start = perf_counter()
train(model, x, y)
end = perf_counter()
time = end - start
print("time: %s" % time)

7、整体代码

# my_linear.py
import torch
import matplotlib.pyplot as pltfrom torch import nn, optim
from time import perf_counterx = torch.Tensor([-5.0000, -4.7959, -4.5918, -4.3878, -4.1837, -3.9796, -3.7755, -3.5714, -3.3673, -3.1633, -2.9592, -2.7551,-2.5510, -2.3469, -2.1429, -1.9388, -1.7347, -1.5306, -1.3265, -1.1224, -0.9184, -0.7143, -0.5102, -0.3061,-0.1020, 0.1020, 0.3061, 0.5102, 0.7143, 0.9184, 1.1224, 1.3265, 1.5306, 1.7347, 1.9388, 2.1429, 2.3469, 2.5510,2.7551, 2.9592, 3.1633, 3.3673, 3.5714, 3.7755, 3.9796, 4.1837, 4.3878, 4.5918, 4.7959, 5.0000])
y = torch.Tensor([-2.9354, -2.6106, -2.5070, -2.1573, -2.0062, -1.7503, -1.3872, -1.2434, -1.0399, -0.7758, -0.3666, -0.2873,-0.0095, 0.3227, 0.4873, 0.8658, 1.0763, 1.2531, 1.4564, 1.7801, 2.0736, 2.1845, 2.4290, 2.6380, 2.9424, 3.3018,3.3983, 3.6191, 4.0433, 4.1419, 4.5190, 4.7428, 4.9229, 5.1000, 5.4449, 5.7140, 5.8567, 6.1416, 6.3126, 6.6015,6.9624, 7.1786, 7.4084, 7.5916, 7.9413, 8.1177, 8.4207, 8.5427, 8.8767, 9.1533])print(x.shape, y.shape)x = x.view(-1, 1)
y = y.view(-1, 1)print(x.shape, y.shape)def draw_result(x, y, calcOutput, loss):# if torch.cuda.is_available():#     output = output.cpu()plt.scatter(x.numpy(), y.numpy())plt.plot(x.numpy(), calcOutput.data.numpy(), 'r-', lw=2)plt.text(0.5, 0, 'loss=%s' % loss.item())plt.show()class MyLinear(nn.Module):def __init__(self):super(MyLinear, self).__init__()self.linear = nn.Linear(in_features=1, out_features=1)def forward(self, x):return self.linear(x)def train(model, x, y, times=50000, lr=1e-2):criterion = nn.MSELoss()optimizer = optim.SGD(model.parameters(), lr=lr)global loss, outputfor i in range(times):output = model(x)loss = criterion(output, y)optimizer.zero_grad()loss.backward()optimizer.step()print(list(model.parameters()))print(loss)draw_result(x, y, output, loss)model = MyLinear()
start = perf_counter()
train(model, x, y)
end = perf_counter()
time = end - start
print("time: %s" % time)

9、训练结果

执行python my_linear.py输出如下结果,可以看出训练出来损失值是0.0035,权重分别是1.2043和3.0897,和我们生成函数的1.2、3很接近,符合预期。

$ python my_linear.py 
torch.Size([50]) torch.Size([50])
torch.Size([50, 1]) torch.Size([50, 1])
[Parameter containing:
tensor([[1.2043]], requires_grad=True), Parameter containing:
tensor([3.0897], requires_grad=True)]
tensor(0.0035, grad_fn=<MseLossBackward0>)

从数据图形也能看出训练模型基本拟合原始数据:

在这里插入图片描述

http://www.dtcms.com/a/348423.html

相关文章:

  • ⭐CVPR2025 病理分析全能模型 CPath-Omni 横空出世
  • RAG智能问答为什么需要进行Rerank?
  • 春秋云镜 Flarum
  • UCIE Specification详解(二)
  • Linux学习-TCP网络协议
  • 基于springboot的高校后勤保修服务系统/基于android的高校后勤保修服务系统app
  • openFeign用的什么协议,dubbo用的什么协议
  • 【重学MySQL】八十七. 触发器管理全攻略:SHOW TRIGGERS与DROP TRIGGER实战详解
  • k8s下的网络通信之calico与调度
  • MySQL官方C/C++ 接口入门
  • 从栈到堆:深入理解C语言静态与动态链表的创建与管理
  • 利旧小天才儿童电话手表实现“一键寻车”功能
  • 线程整理文档
  • 使用UE5开发《红色警戒3》类战略养成游戏的硬件配置指南
  • 【Spring Cloud 微服务】3.智能路由器——深入理解与配置负载均衡
  • MySQL的更新语句执行过程涉及了哪些文件的写入,衍生了redo、undo、二进制日志在什么时候进行写入
  • 从 JUnit 深入理解 Java 注解与反射机制
  • HarmonyOS NEXT系列之元服务框架ASCF
  • 波兰密码破译机bomba:二战密码战的隐形功臣
  • 深入OpenHarmony OTA硬核升级
  • ComfyUI ZLUDA AMD conda 使用遇到的问题
  • stm32温控大棚测控系统(CO2+温湿度+光照)+仿真
  • Docker 容器(一)
  • 【ansible】5.在受管主机部署文件和Jinja2模板
  • 信誉代币的发行和管理机制是怎样的?
  • 基于角色的访问控制(RBAC)研究与Go语言实现
  • overleaf关于给参考文献添加DOI链接的问题
  • B站视频字幕提取工具
  • 当GitHub“断网”:从应急到终极方案,手把手搭建永不宕机的代码协作体系
  • 鸿蒙 ArkTS 开发:Number、Boolean、String 三种核心基本数据类型详解(附实战案例)