当前位置: 首页 > 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.xdnf.cn/news/1357453.html

相关文章:

  • elasticsearch 7.x elasticsearch 使用scroll滚动查询中超时问题案例
  • MySQL官方C/C++ 接口入门
  • Ubuntu24.04 安装 Zabbix
  • ComfyUI ZLUDA AMD conda 使用遇到的问题
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(十五)网格布局
  • 【229页PPT】某大型制药集团企业数字化转型SAP蓝图设计解决方案(附下载方式)
  • 目标检测数据集 第006期-基于yolo标注格式的汽车事故检测数据集(含免费分享)
  • 网络协议UDP、TCP
  • 管道符在渗透测试与网络安全中的全面应用指南
  • 【信息安全】英飞凌TC3xx安全调试口功能实现(调试口保护)
  • OSG库子动态库和插件等文件介绍
  • AlmaLinux 上 Python 3.6 切换到 Python 3.11
  • 从 JUnit 深入理解 Java 注解与反射机制
  • Flink元空间异常深度解析:从原理到实战调优指南
  • 数字防线:现代企业网络安全运维实战指南
  • Maven项目中settings.xml终极优化指南
  • 得物25年春招-安卓部分笔试题1
  • Flink 实时加购数据“维表补全”实战:从 Kafka 到 HBase 再到 Redis 的完整链路
  • GaussDB 数据库架构师修炼(十八) SQL引擎-分布式计划
  • vimware unbuntu18.04 安装之后,没有网络解决方案
  • AI与SEO关键词协同优化
  • 【小程序-慕尚花坊02】网络请求封装和注意事项
  • 个人搭建小网站教程(云服务器Ubuntu版本)
  • 不知道Pycharm怎么安装?Pycharm安装教程(附安装包)
  • MySQL數據庫開發教學(二) 核心概念、重要指令
  • GaussDB 数据库架构师修炼(十八) SQL引擎-统计信息
  • 请求上下文对象RequestContextHolder
  • LIANA | part2 results部分
  • 【贪心算法】day1
  • spring源码之事务篇(事务管理器整个流程)