[深度学习]神经网络线性回归简易实例

ops/2025/1/19 0:51:36/

线性回归简易实例

文章目录

  • 线性回归简易实例
    • 导入模块
    • 所模拟的模型
    • 生成数据
    • 获取数据
    • 定义模型
    • 定义LOSS
    • 使用模型拟合出真实参数
      • 实现梯度下降函数,用于更新参数
      • 训练函数
    • 完整代码

导入模块

python">import torch
import matplotlib.pyplot as plt #画图import random #随机
  • torch库帮助进行梯度计算和参数更新,实现训练过程(随机梯度下降、损失函数的计算等),提供了高效的张量计算和自动求导功能,使得训练机器学习模型更加简便和高效。
  • matplotlib.pyplot库用于绘制图像,使运行结果可视化。
  • random的作用是引入随机性。

所模拟的模型

假设数据符合一个如下图的线性回归模型:

image-20250117095452788

  • 输入数据x有四个维度。分别是外貌、性格、财富、内涵。
  • 输出数据y为恋爱次数。
  • w的四个维度为x的真实权值分为为8.1,2,2,4。分别对应外貌、性格、财富、内涵。
  • b的真实值为1.1。

神经网络的目的就是使用随机的w和b通过深度学习的方法找出真实的w和b的值。

生成数据

python">x = torch.normal(0, 1, (data_num, len(w)))
y = torch.matmul(x, w) + b #矩阵相乘

从正态分布中随机生成平均数为0,方差为1,数量为data_num,维度为len(w)的数据集x。对生成的数据集x与真实的w进行矩阵相乘加上真实的b得到一个符合假设模型的数据集。

计算过程如下图:

image-20250117103308984

python">noise = torch.normal(0, 0.01, y.shape) #噪声加到y上
y += noise

由于实际情况下,真实的数据不会完全符合模型,因此加入一些噪声更好的模拟真实的数据情况。

完整的生成数据代码:

python">def create_data(w, b, data_num): #生成数据x = torch.normal(0, 1, (data_num, len(w)))y = torch.matmul(x, w) + b #矩阵相乘noise = torch.normal(0, 0.01, y.shape) #噪声加到y上y += noisereturn x, ynum = 500 #生成的输入数据个数为500个true_w = torch.tensor([8.1, 2, 2, 4]) #设定真实的参数用于生成数据
true_b = torch.tensor(1.1)X, Y = create_data(true_w, true_b, num)plt.scatter(X[:, 0], Y, 1) #打印输入数据第一列和输出数据的关系
plt.show()

结果如下:

image-20250117102612641

获取数据

由于实际情况下,数据是收集得到的,因此实际的第一步操作是要获取数据。

python">def data_provider(data, label, batchsize):  #每次访问这个函数,就能提供一批数据length = len(label)indices = list(range(length))#把数据打乱,让数据具有普适性random.shuffle(indices)for each in range(0, length, batchsize):get_indices = indices[each: each+batchsize] #每次取batchsieze个数据get_data = data[get_indices]get_label = label[get_indices]yield get_data, get_label #有存档点的returnbatchsize = 16
  • data参数为输入数据集。

  • label参数为输出数据集。

  • 使用 random.shuffle 随机打乱 indices 列表中的元素顺序,这样每次训练时访问的数据顺序都不会固定,从而避免模型在训练过程中出现过拟合。

  • yield get_data, get_label 语句的作用是将当前批次的数据(get_data)和标签(get_label)返回给调用方,并且使得函数的执行暂停,待下一次调用时继续从当前位置执行。这使得 data_provider 函数成为一个生成器。具体来说过程如下:

    第一次调用 yield 后的执行流程

    1. 当你第一次迭代 data_provider(data, label, batchsize) 时:
      • 生成器函数从头开始执行。
      • 执行到 for 循环的第一步,获取当前批次的数据(get_data)和标签(get_label)。
      • 然后执行 yield get_data, get_label,这时函数暂停并返回 get_dataget_label
    2. 函数的状态
      • 此时,生成器函数的执行暂停,所有局部变量(如 indices, get_indices, get_data, get_label)都被保存下来,以便下一次继续使用。
      • 程序控制流回到调用 for 循环的地方,返回数据。

    第二次及以后调用时函数后的执行流程

    1. 恢复执行:生成器函数不会从头开始执行,而是从上次暂停的地方继续执行。也就是说,函数会从上次执行 yield 后的地方继续(在本例中是从 for 循环的下一个迭代开始,因为每循环一次,就遇到yield进行了暂停)。
    2. 继续执行
      • 在上次暂停后,生成器已经完成了 yield get_data, get_label,此时函数的执行状态被保留。
      • 生成器函数继续执行下一个批次的数据生成,并再次遇到 yield
      • 返回下一个批次的 get_dataget_label
    3. 暂停并返回数据:每次执行到 yield 时,函数会暂停并返回相应的批次数据,直到下一次调用。
  • batchsize设定每次所取的数据个数。

定义模型

python">def fun(x, w, b): #模型pred_y = torch.matmul(x, w) + breturn pred_y

定义线性回归模型,使用该模型拟合数据的关系,获取预测值。

公式如下图:

image-20250117115904083

定义LOSS

python">def maeLoss(pre_y, y):return torch.sum(abs(pre_y-y))/len(y)

定义LOSS函数,用于计算预测值和真实数据的误差。

公式如下图:

image-20250117115841166

使用模型拟合出真实参数

实现梯度下降函数,用于更新参数

梯度下降,更新参数的方法如下图:

image-20250117110748652

首先,设置一个初始的权重 w 0 w^0 w0​(w的第0个版本),然后计算损失函数L(衡量模型预测结果与真实结果之间差异的函数),然后计算损失函数相对于参数的梯度。梯度表示了损失函数在某个点的斜率,指示了在当前参数下,损失函数增加或减少的方向和大小。例如,对于权重 w 0 w^0 w0,其梯度是损失函数对权重的导数。然后使用如下公式更新参数:

image-20250117112124861

知道参数的损失函数值符合我们的需求。其中学习率learning rate决定了优化算法(如梯度下降)在每一步中调整模型权重的幅度。所有参数包括偏置在梯度下降过程中操作相当。

梯度下降代码的具体代码实现

python">def sgd(paras, lr):    #随机梯度下降,更新参数with torch.no_grad():  #属于这句代码的部分,不计算梯度for para in paras:para -= para.grad*lr #不能写成para = para - para.grad*lrpara.grad.zero_() #使用过的梯度,归零lr = 0.03 #学习度
w_0 = torch.normal(0, 0.01, true_w.shape, requires_grad=True)  #这个需要计算梯度
b_0 = torch.tensor(0.01, requires_grad=True)
  • with torch.no_grad() 表示在此代码块中的操作不会计算梯度,防止在执行参数更新操作时计算不必要的梯度。因为推理参数阶段,不需要计算梯度,只进行前向传播来获取输出,只有在进行优化更新参数时需要使用梯度。
  • para.grad.zero_()用来将当前参数的梯度归零的。因为在PyTorch中,每次反向传播时,梯度会默认被累加。为了防止梯度不断累加导致的错误,我们需要在每次更新参数之后,将这些梯度清零。
  • lr = 0.03,设置学习度
  • w_0 = torch.normal(0, 0.01, true_w.shape, requires_grad=True)来从正态分布中随机初始化权重,其中:0是均值,0.01是标准差,true_w.shape表示权重 的形状和真实权重 true_w 相同,requires_grad=True表示该张量需要计算梯度。
  • b_0 = torch.tensor(0.01, requires_grad=True)定义了初始的偏置 b_0。它使用 torch.tensor() 创建了一个数值为 0.01 的标量,并且同样设置了 requires_grad=True,表示这个值需要计算梯度。

训练函数

使用定义的模型和LOSS函数,进行训练,得到参数,具体代码如下:

python">epochs = 50 #训练的次数for epoch in range(epochs):data_loss = 0for batch_x, batch_y in data_provider(X, Y, batchsize):pred_y = fun(batch_x, w_0, b_0)loss = maeLoss(pred_y, batch_y)loss.backward()sgd([w_0, b_0], lr)data_loss += lossprint("epoch %03d: loss: %.6f"%(epoch, data_loss)) #打印训练次数,以及误差print("真实的函数值是", true_w, true_b)
print("训练得到的参数值是", w_0, b_0)idx = 0
plt.plot(X[:, idx].detach().numpy(), X[:, idx].detach().numpy()*w_0[idx].detach().numpy()+b_0.detach().numpy())
plt.scatter(X[:, idx], Y, 1) #用来选择第idx个特征(即 X[:, idx])来绘制模型的预测结果和真实数据。
plt.show() #打印
  • epochs = 50设定训练的次数。
  • for batch_x, batch_y in data_provider(X, Y, batchsize):使用data_provider获取batchsize个数的数据。
  • pred_y = fun(batch_x, w_0, b_0),使用当前的权重偏置计算出预测的输出值。
  • loss = maeLoss(pred_y, batch_y),计算真实值和预测值的误差。
  • loss.backward() 是用来执行反向传播过程的,它会根据损失函数 loss 计算所有可训练参数(如 w_0b_0)的梯度。。
  • sgd([w_0, b_0], lr)这是一个基于 随机梯度下降(SGD) 的优化步骤,更新模型参数。sgd 函数根据计算出的梯度更新 w_0b_0 的值,学习率由 lr 指定。具体来说,sgd 会使用每个参数的梯度来调整它们的值,从而最小化损失函数。

输出结果如下图:

image-20250117114951811

image-20250117115056182

完整代码

python">import torch
import matplotlib.pyplot as plt #画图import random #随机def create_data(w, b, data_num): #生成数据x = torch.normal(0, 1, (data_num, len(w)))y = torch.matmul(x, w) + b #矩阵相乘noise = torch.normal(0, 0.01, y.shape) #噪声加到y上y += noisereturn x, ynum = 500true_w = torch.tensor([8.1, 2, 2, 4])
true_b = torch.tensor(1.1)X, Y = create_data(true_w, true_b, num)# plt.scatter(X[:, 0], Y, 1)
# plt.show()def data_provider(data, label, batchsize):  #每次访问这个函数,就能提供一批数据length = len(label)indices = list(range(length))#把数据打乱,让数据具有普适性random.shuffle(indices)for each in range(0, length, batchsize):get_indices = indices[each: each+batchsize] #每次取batchsieze个数据get_data = data[get_indices]get_label = label[get_indices]yield get_data, get_label #有存档点的returnbatchsize = 16# for batch_x, batch_y in data_provider(X, Y, batchsize):
#      print(batch_x, batch_y)def fun(x, w, b): #模型pred_y = torch.matmul(x, w) + breturn pred_ydef maeLoss(pre_y, y):return torch.sum(abs(pre_y-y))/len(y)def sgd(paras, lr):    #随机梯度下降,更新参数with torch.no_grad():  #属于这句代码的部分,不计算梯度for para in paras:para -= para.grad*lr #不能写成para = para - para.grad*lrpara.grad.zero_() #使用过的梯度,归零lr = 0.03
w_0 = torch.normal(0, 0.01, true_w.shape, requires_grad=True)  #这个需要计算梯度
b_0 = torch.tensor(0.01, requires_grad=True)
# print(w_0, b_0)epochs = 50for epoch in range(epochs):data_loss = 0for batch_x, batch_y in data_provider(X, Y, batchsize):pred_y = fun(batch_x, w_0, b_0)loss = maeLoss(pred_y, batch_y)loss.backward()sgd([w_0, b_0], lr)data_loss += lossprint("epoch %03d: loss: %.6f"%(epoch, data_loss))print("真实的函数值是", true_w, true_b)
print("训练得到的参数值是", w_0, b_0)idx = 0
plt.plot(X[:, idx].detach().numpy(), X[:, idx].detach().numpy()*w_0[idx].detach().numpy()+b_0.detach().numpy())
plt.scatter(X[:, idx], Y, 1)
plt.show()

http://www.ppmy.cn/ops/151233.html

相关文章

SpiderFlow平台v0.5.0之引入selenium插件

引入selenium插件 首先到码云下载插件点击下载​编辑到本地并导入到工作空间或安装到maven库在spider-flow/spider-flow-web/pom.xml中引入插件 <!-- 引入selenium插件 --> <dependency><groupId>org.spiderflow</groupId><artifactId>spider-…

重拾Python学习,先从把python删除开始。。。

自己折腾就是不行啊&#xff0c;屡战屡败&#xff0c;最近终于找到前辈教我 第一步 删除Python 先把前阵子折腾的WSL和VScode删掉。还是得用spyder&#xff0c;跟matlab最像&#xff0c;也最容易入手。 从VScode上搞python&#xff0c;最后安装到appdata上&#xff0c;安装插…

MES设备日志采集工具

永久免费: <下载> <使用说明> 用途 定时全量或增量采集工控机,电脑文件或日志. 优势 开箱即用: 解压直接运行.不需额外下载.管理设备: 后台统一管理客户端.无人值守: 客户端自启动,自更新.稳定安全: 架构简单,兼容性好,通过授权控制访问. 架构 技术架构: Asp…

记录点android升级内容

Cleartext HTTP traffic to yun.tjwzkj.com not permitted 在android中不仅要由网络权限<uses-permission android:name"android.permission.INTERNET"/>&#xff0c;而且需要在Application中增加android:usesCleartextTraffic"true" 还可以创建xml…

【Python】深入探讨Python中的单例模式:元类与装饰器实现方式分析与代码示例

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门&#xff01; 解锁Python编程的无限可能&#xff1a;《奇妙的Python》带你漫游代码世界 单例模式&#xff08;Singleton Pattern&#xff09;是一种常见的设计模式&#xff0c;它确保一个类只有一个实例&…

Jmeter Beanshell脚本批量提取接口的值生成csv文档

beanshell脚本 步骤 1、前置条件是接口已能调通&#xff0c;能把返回数据提取出来 2、在接口下添加Beanshell后置处理程序 3、编成脚本&#xff0c;直接执行验证 4、批量执行后可以生成多个

C++项目目录结构以及.vscode文件下的文件详解

&#x1f3ac; Verdure陌矣&#xff1a;个人主页 &#x1f389; 个人专栏: 《C/C》 | 《转载or娱乐》 &#x1f33e; 种完麦子往南走&#xff0c; 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ 摘要&#xff1a; 本文推荐一个较为全面和规范的开发…

Luggage Lock( The 2021 ICPC Asia Shenyang Regional Contest )

Luggage Lock&#xff08; The 2021 ICPC Asia Shenyang Regional Contest &#xff09; 题面描述&#xff1a; Eileen has a big luggage and she would pick a lot of things in the luggage every time when A-SOUL goes out for a show. However, if there are too many …