线性回归神经网络从0到1

1.线性方程和向量乘法

深度学习的基础就是从线性回归方程的理论进入的。简单的线性回归方程为

y=Xw+b+\epsilon

比如大家日常中买房子,价格受到哪些因素影响呢?

比如房龄、交通、是否是学区、有无配套超市、公园,这些基本是外部条件,内部条件诸如几梯几户、层高、容积率、面积、朝向等这些,这样一看如果使用上面的模型构建一个房屋价格预测的神经网络模型,参数非常多w_1,w_2,...w_i,...w_n这么多个参数影响了房屋的价格。所谓线性回归(regression)是能为一个或者多个自变量与因变量之间关系建模的一类方法。回归在数学中经常用来表示输入和输出之间的关系。

所以上面的房屋价格如果只考虑面积和房龄的话,预测模型就变成了

f_{house-price}=w_{area}*x_{area} + w_{age}*w_{age} + b

b称为偏执,或者截距;预测值所依据的自变量称为特征或者协变量,把试图预测的目标称为标签或者目标。。所以整体的预测值就可以描述为

\hat{y} = w_1x_1+w_2x_2+...+w_dx_d + b

我们用矩阵表示出来就是

\hat{y} =w^tx + b

向量x是对于单个数据样本特征。使用符号表示的矩阵就是X \in R^ {n*d}。就可以很方便的引用整个数据集的n个样本。其中X的每一行就是一个样本,每一列就是一种特征。对于特征集合X,预测值通过矩阵-向量乘法表示为

\hat{y} =Xw + b

2.正态分布和平方损失

正态分布和线性回归之间的关系很密切。 正态分布(normal distribution),也称为高斯分布(Gaussian distribution), 最早由德国数学家高斯(Gauss)应用于天文学研究。 我们定义正态分布的时候,就是有一个随机变量x具有均值\mu和方差\sigma^2(标准差\sigma),其正态分布概率密度函数如下

p(x|\mu,\sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x-\mu)^2}{2\sigma^2}}

在后面的方程中我们假设噪声服从正态分布。

如果使用函数来实现

def normal(x, mu, sigma):p = 1/ math.sqrt(2 * math.pi * sigma**2)return p* np.exp(-0.5 / sigma**2 * (x-mu)**2)# 注意torch.normal定义中
torch.normal(mean: _float, std: _float, size: Sequence[Union[_int, SymInt]]...)
mean: 正态分布的均值,可以是一个数值也可以是一个张量
std: 正态分布的标准差,可以是一个数值也可以是一个张量
size:输出随机数的形状,可以是一个整数用于生成size大小的一维张量;也可以是一个元组,用于生成相应形状的多维张量

3.样本刷选

现在我们从市场上获取了一批输入数据,即有一批特征值。因为我们最终是寻找w,b参数。所以虽然开始不知道最终具体的w,b是多少,但是可以根据经验值填写一个 

w=\begin{bmatrix} 2\\ -3.4\end{bmatrix}, b=4.2

所以使用参数模型w,b,\epsilon.其中 \epsilon作为噪声项,服从均值为0的正态分布。这就是我们第一章节中的

y=Xw+b+\epsilon

import random  # 导入random,用于需要随机化初始的权重,以及随机梯度下降
import torch
from d2l import torch as d2ldef synthetic_data(w, b, num_examples):"""生成y=xW +b+噪声:param w::param b::param num_examples: 指定生成样本的数量:return:"""X = torch.normal(0, 1, (num_examples, len(w)))  # 生成均值为0,方差为1的,是num个样本,列数是wy = torch.matmul(X, w) + b  # Matrix Multiplication 两个相乘y += torch.normal(0, 0.01, y.shape)  # 加入一个随机噪音,均值为0方差为1return X, y.reshape((-1, 1))  # 做成一个列向量返回

📢注意:features中的每一行都包含一个二维数据样本, labels中的每一行都包含一维标签值(一个标量) 

    x = torch.arange(12).reshape(2,6)print(x)y = x.reshape((-1,1))print(y)

 这里还有一个就是,之前很多时候我们使用的时候都是

torch.arange(24).reshape(2,3,4)

reshape的参数都是整数,但是上面的y.reshape((-1,1))是什么意思呢?

-1作为一个维度参数时,表示该维度的大小由数组的实际大小和其它维度决定。换句话说NumPy会自动计算这个维度的大小以保持数组元素总数不变。1表示新形状中的另一个维度大小为1。因此,当你对一个数组或矩阵调用.reshape((-1, 1))时,你实际上是在告诉NumPy将原数组重塑为一个列向量(即每列只有一个元素的二维数组)。也就是说,无论输入数组有多少个元素,结果都将是一个两维数组,其中每个原始元素占据一行,且仅有一列。参考

    x = torch.arange(12).reshape(2,6)print(x)y = x.reshape((-1,1))print(y)

输出如下所示:

 我们调用上面的函数

    true_w = torch.tensor([2, -3.4])true_b = 4.2features, labels = synthetic_data(true_w, true_b, 1000)print('output features:', features)print(f'output labels: {labels}')

输出如下所示,和上面的理解是一致的

即features特征值是一个每一行都包含一个二维数组的样本,labels即预测值每一行都包含一个一维标签值 。

我们看看特征值和标签之间的散点分布图。

    d2l.set_figsize()# 这里的detach是从pytorch detach出来之后才能转到numpy中d2l.plt.scatter(features[:, 0].detach().numpy(), labels.detach().numpy(), 1);d2l.plt.show()

 现在我们的基础数据已经构造完成。接下来一个重要的事情需要定义个函数,每次读取一个小批量。

4.小批量数据构造

为什么要使用小批量,而不是使用全部的样本呢,因为每次计算梯度需要对损失函数求导,损失函数是对我们样本平均损失,所以求解一次梯度函数需要把所有样本重新计算一遍,这个训练过程太贵了,所以在神经网络实际训练几乎不用全部的样本。同样一个神经网络模型的训练过程可能需要数分钟数个小时,甚至更久。因为要计算几百步,甚至几千步才能求解出最终的结果。所以我们定义损失函数之后,只要能求解得到一个“差不多”的解就可以,而且在多维复杂的模型中,很少能得到准确解。所以我们损失函数就是多个采样数据各自损失最后求平均得到最终的损失函数。所以我们采样b个样本i_1,i_2...i_b来求解近似。

\frac{1}{b} \sum_{i \in I_b} \ell(\mathbf{x}_i, y_i, \mathbf{w})

所以这里的采样的b个样本,如果 b很大,则计算出的结果相对比较精确但是计算复杂度很高;如果b比较小,计算比较容易但是精确度可能会很差。毕竟梯度的计算复杂度是和样本的个数线性相关的。

def data_iter(batch_size, features, labels):""":param batch_size::param features::param labels::return:"""num_examples = len(features)indices = list(range(num_examples))# shuffle这些样本是随机读取的,没有特定的顺序random.shuffle(indices)  # 把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]

测试下这个函数

    batch_size = 10for X, y in data_iter(batch_size, features, labels):print('小批量数据:', X, '\n', y)break

 

5.定义模型

def linreg(X, w, b):"""线性规划模型:param X::param w::param b::return:"""return torch.matmul(X, w) + b
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

这是一个均值为零,方差为0.01的正太分布函数。我们需要计算梯度requires_grad=True.对于偏差\epsilon来说。我们直接给出一个0,当然也需要不断地调整,所以需要计算梯度。

6.定义损失函数

def squared_loss(y_hat, y):"""定义损失函数,就是均方误差:param y_hat: 预测值:param y: 真实值:return:"""# y.reshape(y_hat.shape) 确保两者大小一样return (y_hat - y.reshape(y_hat.shape)) **2 / 2

其中\hat{y}是预测值,y是我们的真实值。原则上两个个数是一样的,但是计算中可能是一个行向量,一个是列向量。所以使用.shape函数统一下。

7.定义优化算法

def sgd(params, lr, batch_size):"""小批量随机梯度下降:param params: params 包含了w和b:param lr:学习率:param batch_size::return:"""with torch.no_grad(): # 更新的时候不要更新梯度for param in params:param -= lr * param.grad / batch_sizeparam.grad.zero_() # 把梯度设置为0,下次计算梯度的时候就和上次不会相关了

with*作用:torch.no_grad() 是一个上下文管理器(context manager),它告诉 PyTorch 在这个块内不需要计算梯度。这意味着任何在此块内的操作都不会被加入到自动求导图中(即不会跟踪这些操作以进行反向传播),从而节省内存和计算资源。
原因:当确定某些操作(如参数更新)不需要参与梯度计算时,使用 torch.no_grad() 可以提高效率。特别是在推理阶段或手动更新参数时,我们通常不需要追踪这些操作的梯度。

将param.grad.zero_()的原因主要有:

  • 将当前参数的梯度设置为零。这是因为在默认情况下,PyTorch 的反向传播会累加梯度而不是覆盖它们。如果不重置梯度,那么在下一次反向传播时,新计算出的梯度会被加到旧的梯度上,导致不正确的更新。
  • 为什么需要这样做:每次参数更新后,我们应该清除之前的梯度信息,以便于下一轮迭代中正确地计算新的梯度并进行更新。

8.训练

 现在结合上面的过程进行训练

if __name__ == '__main__':true_w = torch.tensor([2, -3.4])true_b = 4.2features, labels = synthetic_data(true_w, true_b, 1000)# print('output features:', features)# print(f'output labels: {labels}')## d2l.set_figsize()# # 这里的detach是从pytorch detach出来之后才能转到numpy中# d2l.plt.scatter(features[:, 0].detach().numpy(), labels.detach().numpy(), 1);## # d2l.plt.show()## # features就是自变量,输入值;labels是标签,这个就是因变量,输出值batch_size = 10# for X, y in data_iter(batch_size, features, labels):#     print('小批量数据:', X, '\n', y)#     break# #w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)b = torch.zeros(1, requires_grad=True)# 训练的过程lr  = 0.03  # 学习率num_epochs = 3 # 把数据扫3遍net = linreg # 模型,就是我们linreg,之所以这样写,就是后续可以快速替换为其他模型loss = squared_loss # 均方损失for epoch in range(num_epochs):for X, y in data_iter(batch_size, features, labels):l = loss(net(X, w, b), y)l.sum().backward()  # 求和之后计算梯度sgd([w,b], lr, batch_size)with torch.no_grad():train_l = loss(net(features, w, b), labels)print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')print(f'b的估计误差: {true_b - b}')

输出如下所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/906874.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

11|省下钱买显卡,如何利用开源模型节约成本?

不知道课程上到这里,你账户里免费的5美元的额度还剩下多少了?如果你尝试着完成我给的几个数据集里的思考题,相信这个额度应该是不太够用的。而ChatCompletion的接口,又需要传入大量的上下文信息,实际消耗的Token数量其…

文章代码|皮层/表皮特异性转录因子 bZIP89 的自然变异决定了玉米侧根发育和抗旱能力

数据和材料可用性:评估本文结论所需的所有数据都包含在论文和/或补充材料中。本研究中的大量 RNA-seq 读数存放在 NCBI 序列读取档案 (www.ncbi.nlm.nih.gov/sra) 中,登录代码为 SRP446501/PRJNA980895。scRNA-seq、DAP-seq 和 DN…

铠大师:让用户畅享多元应用,助力鸿蒙生态发展

在全球信息技术产业格局加速重构的背景下,中国科技力量正以开放包容的姿态重塑操作系统生态范式。 5月19日,华为在成都举办的nova14系列及鸿蒙电脑新品发布会上,正式对外发布搭载了鸿蒙系统的笔记本电脑HUAWEI MateBook Pro与HUAWEI MateBoo…

初学Transformer架构和注意力机制

文章目录 说明一 LLM 简介二 Transformer 架构2.1 Transformer的架构组成2.1.1 输入嵌入 (Input Embedding)2.1.2 编码器 (Encoder) 的结构解码器 (Decoder) 的结构2.1.3 输出层 (Output Layer)结构 2.2 编码和解码器的独立输入理解 三 注意力机制 说明 本文适合初学者&#x…

基于PySide6与pycatia的CATIA几何阵列生成器开发实践

引言:参数化设计的工业价值 在航空航天、汽车制造等领域,复杂几何图案的批量生成是模具设计与机械加工的核心需求。传统手动建模方式存在效率低下、参数调整困难等问题。本文基于PySide6+pycatia技术栈,实现了一套支持​​动态参数配置​​、​​智能几何阵列生成​​的自动…

PDF 编辑批量拆分合并OCR 识别

各位办公小能手们!你们有没有过被PDF文件折磨得死去活来的经历?反正我是有,每次要编辑PDF,那叫一个费劲啊!不过呢,今天我要给大家介绍一款神器——WPS PDF to Word,有了它,PDF编辑那…

棒球比赛暗号百科·棒球1号位

关于棒球比赛暗号百科介绍,涵盖基本概念、历史演变、常见类型及经典案例: 棒球比赛暗号百科 一、定义与作用 棒球暗号是球员、教练团队通过手势、动作、语言或道具传递战术指令的密码系统,旨在隐蔽沟通攻防策略,避免对手破解。其…

Python实现基于线性回归的空气质量预测系统并达到目标指标

为了实现基于线性回归的空气质量预测系统并达到目标指标,以下是完整的Python代码实现: import pandas as pd import numpy as np from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import StandardScal…

236.二叉树的最近公共祖先

在树结构中,祖先指的是一个节点的父节点或更高层级的父节点。公共祖先是指同时为节点p和q的祖先的节点。最近公共祖先(LCA)则是指在所有公共祖先中,距离p和q最近的那个节点。寻找LCA的方法可以按以下情况进行分析: 当…

面试题总结一

第一天 1. 快速排序 public class QuickSort {public static void quickSort(int[] arr, int low, int high) {if (low < high) {// 分区操作&#xff0c;获取基准元素的最终位置int pivotIndex partition(arr, low, high);// 递归排序基准元素左边的部分quickSort(arr, …

Stable Diffusion底模对应的VAE推荐

以下是主流Stable Diffusion底模对应的VAE推荐表格&#xff1a; 底模版本推荐VAE类型说明SD1.5SD1.5专用VAE通常使用vae-ft-mse-840000-ema-pruned.safetensorsSD2.0SD1.5兼容VAE或SD2专用VAE部分SD2模型需配套512-ema-only.vae.ptSD3内置VAESD3系列模型通常自带集成VAE无需额…

北斗导航 | 基于matlab的多波束技术的卫星通信系统性能仿真

基于多波束技术的低轨(LEO)卫星通信系统 **1. 仿真场景建模**1.1 LEO卫星轨道参数设置1.2 地面终端分布**2. 多波束天线模型**2.1 波束方向图生成2.2 频率复用方案**3. 链路预算与干扰分析**3.1 自由空间路径损耗3.2 信噪比(SNR)计算**4. 动态资源调度算法**4.1 基于流量需…

uni-app学习笔记十--vu3 computed的运用(一)

vue官方推荐使用计算属性来描述依赖响应式状态的复杂逻辑&#xff0c;computed具有缓存的作用&#xff0c;一个计算属性仅会在其响应式依赖更新时才重新计算&#xff0c;这意味着只要 相关值 不改变&#xff0c;无论多少次访问 都会立即返回先前的计算结果&#xff0c;从而在一…

多模态大模型详解

首先&#xff0c;得明确多模态大模型的定义和核心能力&#xff0c;比如处理文本、图像、音频、视频等多种数据模态。 其次是技术架构&#xff0c;可能需要分模块描述&#xff0c;比如感知层、特征提取、融合策略等&#xff0c;还有技术趋势如模型轻量化、开源生态。 应用场景…

如何通过UI设计提高用户留存率?

在竞争激烈的移动应用市场中&#xff0c;提高用户留存率是开发者的关键目标。UI 设计在实现这一目标中起着举足轻重的作用。精心设计的 UI 不仅能够吸引新用户&#xff0c;还能促使现有用户持续使用。以下是通过 UI 设计提升用户留存率的几种关键方法。 优化用户体验 用户体验…

Linux(6)——第一个小程序(进度条)

目录 一、行缓冲区的概念 二、\r与\n 三、进度条代码书写与展示 1.如何表示进度条是在加载的 2.整体框架 3.书写 3.1makefile: 3.2process.h: 3.3process.c: 3.4main.c&#xff1a; 3.5美化 一、行缓冲区的概念 首先&#xff0c;我们来见一见行缓冲区&#xff0c;…

51页 @《人工智能生命体 新启点》中國龍 原创连载

《 人工智能生命体 新启点 》一书&#xff0c;以建立意识来建立起生命体&#xff0c;让其成为独立、自主的活动个体&#xff1b;也就可以理解为建立生命体的思想指导。 让我们能够赋予他灵魂&#xff01;

微软全新开源命令行文本编辑器:Edit — 致敬经典,拥抱现代

名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、引言:命令行的新利器二、Edit:致敬经典,拥抱现代1. 命令行的“新升级”2. 为什么要有 Edit?三、核心功能与特性一览1. 完全开源、MIT 许可证…

使用MybatisPlus实现sql日志打印优化

背景&#xff1a; 在排查无忧行后台服务日志时&#xff0c;一个请求可能会包含多个执行的sql&#xff0c;经常会遇到SQL语句与对应参数不连续显示&#xff0c;或者参数较多需要逐个匹配的情况。这种情况下&#xff0c;如果需要还原完整SQL语句就会比较耗时。因此&#xff0c;我…

go多线程压测监控

实现了 go多协程压力测试实现了Monitor&#xff0c;异步统计qps、时延、cpu(client端)等指标&#xff0c;周期printStat。只需要把单条执行func传给Monitor即可命令行传参ctrlc之后正常退出(mock cpu 占用) 代码见 https://gitee.com/bbjg001/golearning/tree/master/others/…