自求导实现线性回归与PyTorch张量详解

目录

  • 前言
  • 一、自求导的方法实现线性回归
  • 1.1自求导的方法实现线性回归的理论讲解
  • 1.1.1 线性回归是什么?
  • 1.1.2线性回归方程是什么?
  • 1.1.3散点输入
  • 1.2参数初始化
  • 1.2.1 参数与超参数
  • 1.2.1.1 参数定义
  • 1.2.1.2 参数内容
  • 1.2.1.3 超参数定义
  • 1.2.1.4 超参数内容
  • 1.2.2 参数设定
  • 1.3 损失函数
  • 1.4 开始迭代
  • 1.5 反向传播
  • 1.6 显示频率设置
  • 1.9 梯度下降显示
  • 2.0 自求导实现线性回归程序 
  • 二、深度学习框架Pytorch的tensor
  • 2.2 PyTorch是什么?
  • 2.3 PyTorch的特点
  • 2.4 tensor是什么?
  • 2.5 torch 安装命令
  • 2.6 tensor的存储机制
  • 2.6.1 tensor
  • 2.6.2 数据类型
  • 2.6.2.1 基本构成
  • 2.6.2.2 计算方式
  • 2.6.2.3 实战计算
  • 2.6.3  Storage 存储与共享
  • 2.7 tensor的步长
  • 2.8 tensor的偏移
  • 2.9 Tensor的连续性
  • 2.9.1 tensor的连续性是什么?
  • 2.9.2 tensor的不连续性是什么?
  • 2.9.3 不连续的缺点与解决方案
  • 总结

前言

书接上文

线性回归的前向传播、反向传播与数学求解详解-CSDN博客文章浏览阅读1k次,点赞40次,收藏19次。本文从前向传播的代码实现出发,展示了如何利用线性模型对二维数据进行拟合及误差分析,接着深入讲解了反向传播中的学习率和梯度下降算法的理论基础及优化方法,结合Python代码动态演示了参数更新和损失函数的变化过程;最后,文章通过数学推导详细揭示了线性回归模型参数的计算公式,并用代码实现了数学解法的拟合过程,帮助读者全面掌握线性回归的基本原理、优化方法及编程实现。 https://blog.csdn.net/qq_58364361/article/details/147264719?spm=1011.2415.3001.10575&sharefrom=mp_manage_link


一、自求导的方法实现线性回归

从以下2个方面对自求导的方法实现线性回归算法进行介绍
1.自求导的方法实现线性回归算法理论讲解
2.编程实例与步骤
上面这2方面的内容,让大家,掌握并理解自求导的方法实现线性回归算法。


1.1自求导的方法实现线性回归的理论讲解

在了解前向传播、反向传播、损失函数、学习率、梯度下降这些概念后,我们就可以通过自求导的方式来实现线性回归算法。


1.1.1 线性回归是什么?

定义:

线性回归是一种用于建立自变量与因变量之间关系的统计方法。

它假设因变量(或响应变量)与一个或多个自变量(或预测变量)之间的关系是线性的。

其主要目标是通过拟合一个线性模型来预测因变量的数值。


1.1.2线性回归方程是什么?

公式:

线性回归模型可以表示为:

Y=β_0+β_1X_1+β_2X_2+...+β_nX_n+ε

其中:

Y是因变量

X_1,X_2,...,X_n是自变量

β_0,β_1,...,β_n是模型的系数,表示自变量对因变量的影响。

ε是误差项,表示模型无法解释的随机误差


1.1.3散点输入

算法实现需要的数据,一些散点,将它们绘制在一个二维坐标中,其分布如下图所示:


1.2参数初始化

1.2.1 参数与超参数

1.2.1.1 参数定义

模型中可调整的变量,它们用来捕捉数据中的模式和特征。这些参数在模型训练过程中被不断调整以最小化损失函数或优化某种目标。


1.2.1.2 参数内容

权重(Weights):用来表示不同输入特征与神经元之间的连接强度

偏置(Biases):用于调整每个神经元的激活阈值,使模型能够更好地拟合数据。


1.2.1.3 超参数定义

超参数不是通过训练数据学习得到的,而是在训练过程之前需要手动设置的参数。


1.2.1.4 超参数内容

包括学习率正则化参数迭代次数批量大小神经网络层数和每层的神经元数量激活函数

学习率(Learning Rate):用于控制优化算法中每次更新参数时的步长。较小的学习率会导致训练收敛较慢,而较大的学习率可能导致训练不稳定或震荡。

正则化参数(Regularization Parameter):用于控制正则化的强度,如L1正则化和L2正则化。较大的正则化参数会增强正则化效果,有助于防止过拟合。

迭代次数(Number of Iterations):用于控制训练的迭代次数。迭代次数太小可能导致模型未完全学习数据的特征,而迭代次数太大可能导致过拟合。

批量大小(Batch Size):用于控制每次训练时用于更新参数的样本数量。批量大小的选择会影响训练速度和内存消耗。

神经网络层数和每层的神经元数量(Number of Layers and Neurons per Layer):用于定义神经网络的结构。

激活函数(Activation Function):用于控制神经网络每个神经元的输出范围,如Sigmoid、ReLU等。


1.2.2 参数设定

在前向传播实验中,知道了参数不同时对应的损失函数值也不同,所以需要先初始化一下参数和超参数,进行一次前向传播,得到损失值,这样才能通过反向传播减小损失,使直线的拟合效果更好。这里通过“参数初始化”组件来初始化w和b以及学习率这三个参数/超参数


1.3 损失函数

与前向传播实验和反向传播实验不同,此时b的值不再是0,也就意味着损失函数不仅仅受到w的影响,还会受到b的影响,将 y=wx+b 带入损失函数的表达式后,新的损失函数就变成了如下图所示的表达式:

1.4 开始迭代

迭代次数通常指的是反向传播的次数,即通过反向传播来更新模型的参数,直到达到一定的迭代次数或者达到收敛的条件为止。

迭代的次数越多,模型参数就越接近最优解,从而使得损失函数达到最小值,但是可能会造成过拟合(过拟合在之后的实验会讲到)。

一般来说,迭代次数需要根据具体情况来确定,通常需要进行多次迭代来更新模型参数,直到达到收敛的条件为止,在“开始迭代”组件中默认的是500次。

1.5 反向传播

当参数和损失函数都设置好之后,就开始反向传播了,也就是损失函数对w和b进行求导并且不断更新w和b的过程,是一个复合函数

求导的过程。损失函数对w和b的求导过程如下:


1.6 显示频率设置

求导完成之后,使用梯度下降的方法来更新w和b的值。为了更好的在实验中看现象,这里有一个“显示频率设置”组件,就是每经过多少次迭代,绘制一次当前参数的拟合线及损失函数的大小。


1.9 梯度下降显示

迭代的结果通过“梯度下降显示”组件进行查看。如下图所示,38.4是w 的实时值,24.58是b的实时值,42.68是最后的损失值。

除此之外,该组件还有三个图,左边的是实时的直线图,参数每更新一次,该直线就更新一次,右边的是损失值的图像,显示的是经过迭代后的损失值的大小,下方的图是W和B随着不断的更新而变化的等高线图


2.0 自求导实现线性回归程序 

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspecfrom 机器学习.test import iter_num_list  # 导入外部模块中的iter_num_list(此处未使用)# 1. 准备数据:散点坐标
data = [[-0.5, 7.7],[1.8, 98.5],[0.9, 57.8],[0.4, 39.2],[-1.4, -15.7],[-1.4, -37.3],[-1.8, -49.1],[1.5, 75.6],[0.4, 34],[0.8, 62.3]]# 转换为numpy数组,便于矩阵运算
data = np.array(data)
x_data = data[:, 0]  # 取第一列作为x数据
y_data = data[:, 1]  # 取第二列作为y数据# 初始化线性模型参数w和b
w = 0
b = 0# 设置学习率
learning_rate = 0.01# 定义损失函数(均方误差)
def loss_function(x_data, y_data, w, b):predicted = np.dot(x_data, w) + b  # 线性预测y_mean = np.mean((y_data - predicted) ** 2)  # 均方误差计算return y_mean# 创建画布,采用2行2列的格子布局
fig = plt.figure("show figure")
gs = gridspec.GridSpec(2, 2)# 左上子图:绘制散点图及拟合直线
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_xlabel('X')
ax1.set_ylabel('y')
ax1.set_title('figure1 data')# 左下子图:绘制损失随迭代变化图
ax2 = fig.add_subplot(gs[1, 0])
ax2.set_xlabel('iter')
ax2.set_ylabel('e')
ax2.set_title('figure2 data')# 右上子图:绘制损失函数关于w和b的三维表面
ax3 = fig.add_subplot(gs[0, 1], projection='3d')# 设置权重w和偏置b的取值范围
w_values = np.linspace(-20, 80, 100)
b_values = np.linspace(-20, 80, 100)# 生成网格数据用于绘制曲面
W, B = np.meshgrid(w_values, b_values)# 初始化对应损失函数值矩阵
loss_values = np.zeros_like(W)# 计算每个(w, b)组合的损失值
for i, w_value in enumerate(w_values):for j, b_value in enumerate(b_values):loss_values[j, i] = loss_function(x_data, y_data, w_value, b_value)# 绘制三维曲面图(颜色映射采用viridis)
ax3.plot_surface(W, B, loss_values, cmap='viridis', alpha=0.8)# 设置三维坐标轴标签和标题
ax3.set_xlabel('w')
ax3.set_ylabel('b')
ax3.set_zlabel('loss')
ax3.set_title('figure3  surface plot')# 右下子图:绘制损失函数的等高线填充图
ax4 = fig.add_subplot(gs[1, 1])
ax4.set_xlabel('w')
ax4.set_ylabel('b')
ax4.set_title('coutour plot')
ax4.contourf(W, B, loss_values, levels=20, cmap='viridis')# 迭代次数设置
num_iterations = 100# 初始化列表,用于存储损失(sh)、迭代次数(cs)、和参数轨迹(gj)
sh = []  # 记录每次迭代的损失
cs = []  # 记录迭代次数
gj = []  # 记录每次迭代的(w, b)参数值轨迹# 梯度下降主循环
for i in range(1, num_iterations + 1):gj.append((w, b))  # 保存当前参数yc = np.dot(x_data, w) + b  # 预测值e = np.mean((y_data - yc) ** 2)  # 当前均方误差sh.append(e)  # 记录损失cs.append(i)  # 记录迭代次数# 计算梯度(损失对w和b的偏导数)dw = (-2 * (y_data - yc).dot(x_data)) / len(x_data)db = np.mean(-2 * (y_data - yc))# 参数更新,梯度下降法w = w - learning_rate * dwb = b - learning_rate * db# 每隔10次迭代或第1次迭代,更新绘图显示f = 10if i % f == 0 or i == 1:# 清空左上子图,重新绘制散点和拟合直线ax1.clear()ax1.set_xlabel('X')ax1.set_ylabel('y')ax1.set_title('figure1 data')ax1.scatter(x_data, y_data, c='b', marker='o')  # 绘制散点x_min, x_max = x_data.min(), x_data.max()y_min, y_max = w * x_min + b, w * x_max + bax1.plot([x_min, x_max], [y_min, y_max], c='r')  # 绘制拟合直线# 清空左下子图,重新绘制损失随迭代次数的变化曲线ax2.clear()ax2.set_xlabel('iter')ax2.set_ylabel('e')ax2.set_title('figure2 data')ax2.plot(cs, sh, c='g')  # 绘制损失曲线# 绘制右上三维曲面上的梯度下降轨迹if len(gj) > 0:g_w, g_b = zip(*gj)  # 解包轨迹参数# 绘制轨迹点(散点线)ax3.plot(g_w, g_b, [loss_function(x_data, y_data, w_, b_) for w_, b_ in gj], c='b')ax3.set_xlim(-20, 80)ax3.set_ylim(-20, 80)ax3.set_xlabel('w')ax3.set_ylabel('b')ax3.set_zlabel('loss')ax3.set_title('figure3  surface plot')# 绘制当前参数对应的点,用黑点高亮ax3.scatter(w, b, loss_function(x_data, y_data, w, b), c='b', s=20)# 右下等高线图绘制迭代轨迹曲线ax4.plot(g_w, g_b)# 暂停0.01秒,更新动画效果

二、深度学习框架Pytorch的tensor

从以下4个方面对深度学习框架Pytorch的tensor进行介绍
1.PyTorch是什么?
2.tensor是什么?
3.tensor的存储机制
4.tensor的连续性
上面这4方面的内容,让大家,掌握并理解深度学习框架Pytorch的tensor。


2.2 PyTorch是什么?

概念:

PyTorch是一个开源的深度学习框架,由Meta公司(原名:Facebook)的人工智能团队开发和维护。它提供了一个灵活、动态的计算图计算模型,使得在深度学习领域进行实验和开发变得更加简单和直观

pytorch网址

PyTorch documentation — PyTorch 2.6 documentationhttps://pytorch.org/docs/stable/index.html


2.3 PyTorch的特点

2.1动态计算图

PyTorch使用动态计算图,这意味着计算图在运行时构建的,而不是在编译时静态定义的。

2.2 自动求导(微分)

PyTorch提供了自动求导机制,称为Autograd。它能够自动计算张量的梯度,这对于训练神经网络和其他深度学习模型非常有用。

2.3 丰富的神经网络库

PyTorch 提供了丰富的神经网络库,包括各种各样的层,损失函数、优化器等。这些库使得构建和训练神经网

络变得更加容易。

2.4支持GPU加速

PyTorch 充分利用了GPU的并行计算能力,能够在GPU上高效地进行计算,加速模型训练过程。


2.4 tensor是什么?

tensor是一种多维数组,类似于NumPy的ndarray.它是Pytorch中最基本的数据结构,用于存储和操作数据。

tensor可以是标量向量矩阵或者更高维度的数组,可以包含整数、浮点数或者其他数据类型的元素。

PyTorch的Tensor和NumPy的ndarray非常相似,但在设计和功能上有一些不同之处。主要的区别包括:GPU加速自动求导动态计算图


2.5 torch 安装命令

python -m pip install --upgrade pip

pip install torch==2.4.1 -i https://pypi.tuna.tsinghua.edu.cn/simple

!pip install torch==2.4.1 -i Simple Index

import torch""" 01
-------------------打印标量 向量 矩阵
"""# 打印一个标量张量
# 标量是只有一个数值的张量,这里值为3.14
scalar_tensor = torch.tensor(3.14)
print("scalar_tensor:", scalar_tensor, "\n")# 打印一个向量张量
# 向量是1维张量,这里包含5个元素:[1, 2, 3, 4, 5]
vector_tensor = torch.tensor([1, 2, 3, 4, 5])
print("vector_tensor:", vector_tensor, "\n")# 打印一个矩阵张量
# 矩阵是2维张量,这里是2行2列的矩阵[[1, 2], [3, 4]]
matrix_tensor = torch.tensor([[1, 2], [3, 4]])
print("matrix_tensor:", matrix_tensor, "\n")
D:\python_huanjing\.venv1\Scripts\python.exe C:\Users\98317\PycharmProjects\study_python\机器学习\test.py 
scalar_tensor: tensor(3.1400) vector_tensor: tensor([1, 2, 3, 4, 5]) matrix_tensor: tensor([[1, 2],[3, 4]]) 进程已结束,退出代码为 0

2.6 tensor的存储机制

2.6.1 tensor

在PyTorch中,tensor包含了两个部分,即Storage 和metadata。Storage(存储):存储是tensor中包含的实际的底层缓冲区,它是一维数组,存储了tensor的元素值。不同tensor可能共享相同的存储,即使它们具有不同的形状和步幅。存储是一块连续的内存区域,实际上存储了tensor中的数据。

Metadata(元数据):元数据是tensor的描述性信息,包括tensor的形状、数据类型、步幅、存储偏移量、设备等。元数据提供了关于tensor的结构和属性信息,但并不包括tensor中的实际数据。元数据允许PyTorch知道如何正确地解释存储中的数据以及如何访问它们。

描述性信息元数据:

tensor

tensor:tensor([[1,2,3],[4,5,6]])

Metadata

形状

数据类型

步幅/步长

存储偏移量

设备

Storage

一维数组

import torch

import torch# tensor 存储示例
# 创建一个2行3列的浮点数张量
tensor_2_3_float = torch.tensor([[1.0, 2.0, 3.0], [4, 5, 6]])# 打印张量的数据类型(dtype),比如float32
print(tensor_2_3_float.dtype, "\n")# 打印张量的底层存储结构(storage),显示存储的数据信息
print(tensor_2_3_float.storage(), "\n")# 将底层存储的数据转换为列表,方便查看具体元素顺序
print(tensor_2_3_float.storage().tolist(), "\n")# 打印存储偏移量,表示张量数据起始位置相对底层存储的偏移索引
print(tensor_2_3_float.storage_offset(), "\n")# 再次打印存储偏移量,结果相同
print(tensor_2_3_float.storage_offset(), "\n")
D:\python_huanjing\.venv1\Scripts\python.exe C:\Users\98317\PycharmProjects\study_python\机器学习\test.py 
torch.float32 1.02.03.04.05.06.0
[torch.storage.TypedStorage(dtype=torch.float32, device=cpu) of size 6] [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] 0 0 C:\Users\98317\PycharmProjects\study_python\机器学习\test.py:11: UserWarning: TypedStorage is deprecated. It will be removed in the future and UntypedStorage will be the only storage class. This should only matter to you if you are using storages directly.  To access UntypedStorage directly, use tensor.untyped_storage() instead of tensor.storage()print(tensor_2_3_float.storage(), "\n")进程已结束,退出代码为 0

2.6.2 数据类型

整型、无符号整数类型

浮点型

torch.Float16,也被称为FP16或半精度浮点数,是一种用于表示浮点数的数据类型,在计算机科学中广泛应用于各种领域。以下是对Float16的详细说明:


2.6.2.1 基本构成

Float16使用16位(即2个字节)来表示一个浮点数,这16位被分为三部分:

符号位:1位,用于表示数的正负。0代表正数,1代表负数。

指数位:5位,用于表示数的大小。其范围是00001~11110,对应的十进制数是1~30。为了得到实际的指数值,需要从这些值中减去一个偏置值15,因此实际指数的范围是-14~15。

尾数位:10位,用于表示数的精度。其范围是0~1023,这些值除以1024后得到实际的尾数值,范围是0~0.9990234375。


2.6.2.2 计算方式

Float16类型的数的计算公式是:


2.6.2.3 实战计算

对于给出的float16值:0011101000000000

根据计算公式得出:为0.75

符号位:0(表示这是一个正数)

指数部分:01110(二进制),转换为十进制是2^3+2^2+2^1=8+4+2=14

小数部分(尾数):1000000000(二进制)

接下来,将指数部分转换为实际的指数值。在float16中,指数的偏移量是15,因为最大为2^(5-1)-1=15,所以实际的指数是14-15=-1。

将小数部分转成十进制:2^(9)=512; 512/1024=0.5; 0.5+1=1.5

最终计算方法:(-1)^符号位×2^(-1)×1.5=0.75。


2.6.3  Storage 存储与共享

tensor结构图

对张量进行操作时(比如调整形状(不是reshape是view),转置等),它不会创建一个新的张量,而是返回一个指向相同数据的视图。即PyTorch通常会共享相同的存储对象,以节省内存和提高效率。

import torch# 验证storage存储与共享
# 1. 查看两个张量的底层存储是否相同,判断它们是否共享存储
# 2. 通过比较存储的内容和内存地址,确认它们是否指向同一块内存空间
# 3. 如果两者的底层存储内容和内存地址都一致,则说明它们共享同一份数据# 使用 arange 生成0到11的连续整数,共12个元素
# 然后使用 reshape 将其变形成3行4列的张量
tensorA = torch.arange(12).reshape(3, 4)# 打印张量tensorA的底层storage内容(以列表形式)
print(tensorA.storage().tolist())# 对tensorA进行转置操作,交换第0维和第1维,生成tensorB
tensorB = tensorA.transpose(0, 1)# 打印tensorB的底层storage内容(以列表形式)
# 可观察转置操作后底层存储数据是否发生变化
print(tensorB.storage().tolist(), "\n")# 打印tensorA存储内容的内存地址(指针)
print(tensorA.storage().data_ptr(), "\n")# 打印tensorB存储内容的内存地址(指针)
print(tensorB.storage().data_ptr(), "\n")# 打印tensorA对象的id(内存地址,用于区分不同对象)
print(id(tensorA), "\n")# 打印tensorB对象的id,和tensorA相比确认是否为不同对象
print(id(tensorB), "\n")
D:\python_huanjing\.venv1\Scripts\python.exe C:\Users\98317\PycharmProjects\study_python\机器学习\test.py 
C:\Users\98317\PycharmProjects\study_python\机器学习\test.py:13: UserWarning: TypedStorage is deprecated. It will be removed in the future and UntypedStorage will be the only storage class. This should only matter to you if you are using storages directly.  To access UntypedStorage directly, use tensor.untyped_storage() instead of tensor.storage()print(tensorA.storage().tolist())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 5948693287232 5948693287232 1573108881744 1573115855632 进程已结束,退出代码为 0

Storage存储的具体过程

在PyTorch中,张量的存储是通过torch.Storage类来管理的。张量的值被分配在连续的内存块中,这些内存块中,这些内存块是大小可变的一维数组,可以包含不同类型的数据,如float或int32。

具体来说,当我们创建一个张量时,PyTorch会根据我们提供的数据和指定的数据类型来分配一块连续的内存空间。这块内存空间由torch.Storage对象管理,而张量本身则提供了一种视图,让我们可以通过索引来访问这些数据。

此外,PyTorch还提供了一系列的函数和方法来操作张量,包括改变形状,获取元素、拼接和拆分等。这些操作通常不会改变底层的存储,而是返回一个新的张量视图,这个视图指向相同的数据但是可能有不同的形状或索引方式。

总的来说,张量的存储实现是PyTorch能够高效进行张量运算的关键。通过管理一块连续的内存空间,并提供了丰富的操作方法,使得用户可以方便地对多维数组进行各种计算和变换。


2.7 tensor的步长

步长指的是在每个维度上移动一个元素时在底层存储中需要跨越的元素数。

import torch""" 
04
展示张量的步长(stride)概念及其转置操作对步长和存储的影响
"""
# 创建一个3行4列的张量,元素为0到11,数据类型为float32
tensor_A = torch.arange(12, dtype=torch.float32).reshape(3, 4)# 打印原张量
print(tensor_A, "\n")# 打印原张量的步长,每个维度跨越内存元素的步长
print(tensor_A.stride(), "\n")# 打印原张量的转置(交换行列)
print(tensor_A.T, "\n")# 打印转置后张量的步长,步长的变化反映了维度的交换
print(tensor_A.T.stride(), "\n")# 打印转置张量底层存储的所有元素,存储不变只是视图变换
print(tensor_A.T.untyped_storage().tolist())
D:\python_huanjing\.venv1\Scripts\python.exe C:\Users\98317\PycharmProjects\study_python\机器学习\test.py 
tensor([[ 0.,  1.,  2.,  3.],[ 4.,  5.,  6.,  7.],[ 8.,  9., 10., 11.]]) (4, 1) tensor([[ 0.,  4.,  8.],[ 1.,  5.,  9.],[ 2.,  6., 10.],[ 3.,  7., 11.]]) (1, 4) [0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64, 0, 0, 224, 64, 0, 0, 0, 65, 0, 0, 16, 65, 0, 0, 32, 65, 0, 0, 48, 65]进程已结束,退出代码为 0

tensor([[ 0, 1, 2, 3],

[ 4, 5, 6, 7],

[ 8, 9, 10, 11]])

(4, 1)

第一个数字4表示矩阵的行(第一个维度)上移动一个元素时需要跨越的存储单元数。因为矩阵的每行包含4个元素,所以每次沿着行移动一个元素需要跨越4个存储单元。

第二个数字1表示在矩阵的列(第二个维度)上移动一个元素时需要跨越的存储单元数,因为矩阵的列数是1,所以在列上移动一个元素时只需要跨越一个存储单元。


2.8 tensor的偏移

偏移是指从张量的第一个元素开始的索引位置。

偏移程序演示

tensor的偏移

import torch""" 04
张量偏移(storage_offset)示例说明
"""
# 创建一个3行4列的浮点型张量,元素为0到11
tensor_A = torch.arange(12, dtype=torch.float32).reshape(3, 4)# 打印张量tensor_A的内容
print("tensor_A的内容:\n", tensor_A)# 打印张量tensor_A底层存储的所有元素列表
print("tensor_A的底层存储元素列表:\n", tensor_A.storage().tolist())# 打印tensor_A的存储偏移量,指示张量数据在底层存储中的起始位置
print("tensor_A的存储偏移量:\n", tensor_A.storage_offset())# 利用切片选取tensor_A第2行到第3行、第2列的数据,生成子张量tensorB
tensorB = tensor_A[1:3, 1:2]# 打印子张量tensorB的内容
print("tensorB的内容:\n", tensorB)# 打印tensorB的存储偏移量,可以看到相对于底层存储的起始位置发生了变化
print("tensorB的存储偏移量:\n", tensorB.storage_offset())# 打印tensorB底层存储的所有元素,注意存储仍为tensor_A共享的完整元素列表
print("tensorB的底层存储元素列表:\n", tensorB.storage().tolist())
D:\python_huanjing\.venv1\Scripts\python.exe C:\Users\98317\PycharmProjects\study_python\机器学习\test.py 
C:\Users\98317\PycharmProjects\study_python\机器学习\test.py:13: UserWarning: TypedStorage is deprecated. It will be removed in the future and UntypedStorage will be the only storage class. This should only matter to you if you are using storages directly.  To access UntypedStorage directly, use tensor.untyped_storage() instead of tensor.storage()print("tensor_A的底层存储元素列表:\n", tensor_A.storage().tolist())
tensor_A的内容:tensor([[ 0.,  1.,  2.,  3.],[ 4.,  5.,  6.,  7.],[ 8.,  9., 10., 11.]])
tensor_A的底层存储元素列表:[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0]
tensor_A的存储偏移量:0
tensorB的内容:tensor([[5.],[9.]])
tensorB的存储偏移量:5
tensorB的底层存储元素列表:[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0]进程已结束,退出代码为 0

2.9 Tensor的连续性

2.9.1 tensor的连续性是什么?

Tensor的连续性指的是其元素在内存中按照其在张量中的顺序紧密存储,没有间隔。

生成的tensor根据"行优先"策略,在展开后与Storage存储的顺序一致,即该tensor连续


2.9.2 tensor的不连续性是什么?

对上面的tensor进行转置操作

生成的tensor根据"行优先"策略,在展开后与Storage存储的顺序不一致,即该tensor不连续


2.9.3 不连续的缺点与解决方案

当对Tensor进行某些操作,如转置(transpose)时,可能会导致Tensor变得不连续。

连续的tensor优势

高效的内存访问:连续的张量在内存中占用一块连续的空间,这使得CPU可以高效地按顺序访问数据,减少了内存寻址的时间,从而提高了数据处理的速度。

优化的计算性能:在进行数学运算时,连续张量可以减少数据的移动和复制,因为数据已经按照计算所需的顺序排序排列,这样可以减少计算中的延迟,提高整体的计算性能。

其它:在不连续的tensor上进行view()操作会报错

连续性和非连续性编程

import torch"""06 
连续性和非连续性示例说明
"""
# 创建一个包含0到11的张量,并将其形状调整为3行4列
tensorA = torch.arange(12).reshape(3, 4)  # arange生成0到11的序列,reshape调整形状为3x4# 将tensorA展平成一维张量,默认按行优先顺序
print("tensorA展平结果:", tensorA.flatten())  # 按行优先展平# 转置tensorA,交换0轴和1轴,生成tensorB
tensorB = tensorA.transpose(0, 1)# 尝试将tensorB展平成一维张量,默认按行优先顺序
print("tensorB展平结果:", tensorB.flatten())# 打印tensorB数据在内存中的起始地址
print("tensorB数据起始地址:", tensorB.data_ptr())# 判断tensorB是否是内存中连续存储的张量,返回False表示不连续
print("tensorB是否连续:", tensorB.is_contiguous())# 由于tensorB不是连续的,不能直接使用view改变形状,以下语句会报错
# tensorB.view(1, 12)# 将tensorB转化为内存连续的张量,生成新的tensorB
tensorB = tensorB.contiguous()# 对转化后的tensorB执行展平操作,按行优先顺序展开
print("转化为连续后tensorB展平结果:", tensorB.flatten())# 查看tensorB底层存储中的元素列表
print("tensorB底层存储元素列表:", tensorB.storage().tolist())# 打印转化后tensorB的数据起始地址,地址可能改变
print("连续化后tensorB数据起始地址:", tensorB.data_ptr())# 使用view成功改变tensorB的形状为1行12列
print("使用view改变形状为(1,12):", tensorB.view(1, 12))
D:\python_huanjing\.venv1\Scripts\python.exe C:\Users\98317\PycharmProjects\study_python\机器学习\test.py 
tensorA展平结果: tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
tensorB展平结果: tensor([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])
tensorB数据起始地址: 4949521994112
tensorB是否连续: False
转化为连续后tensorB展平结果: tensor([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])
tensorB底层存储元素列表: [0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11]
连续化后tensorB数据起始地址: 4949521994432
使用view改变形状为(1,12): tensor([[ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11]])
C:\Users\98317\PycharmProjects\study_python\机器学习\test.py:34: UserWarning: TypedStorage is deprecated. It will be removed in the future and UntypedStorage will be the only storage class. This should only matter to you if you are using storages directly.  To access UntypedStorage directly, use tensor.untyped_storage() instead of tensor.storage()print("tensorB底层存储元素列表:", tensorB.storage().tolist())进程已结束,退出代码为 0

解决方案:

通过contiguous()方法将不连续的张量转换为连续的张量。

如果tensor不是连续的,则会重新开辟一块内存空间保证数据是在内存中是连续的。

如果tensor是连续的,则contiguous()无操作

不论是reshape view 或者其他的操作 如果连续就只改变形状不改变storage ,如果不连续就直接申请新的内存确保连续。


总结

        本文系统介绍了自求导方法实现线性回归的理论基础与具体实现步骤,首先阐述线性回归的定义、模型方程及参数初始化,详细讲解了损失函数构建、迭代优化过程及反向传播求导更新参数的原理与过程,辅以完整的Python编程实例,直观展示了梯度下降的迭代效果和损失变化。此外,文章深入解析了深度学习框架PyTorch中的张量(tensor)结构,包括其定义、存储机制、数据类型以及连续性等关键概念,说明了tensor底层的Storage及元数据构成,探讨了步长和偏移对内存访问的影响,并通过代码示例演示了tensor的存储共享、不连续性的成因及解决方案,帮助读者全面理解PyTorch tensor的底层机制及高效操作方法,为实际深度学习模型开发打下坚实基础。

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

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

相关文章

2025年机电一体化、机器人与人工智能国际学术会议(MRAI 2025)

重要信息 时间:2025年4月25日-27日 地点:中国济南 官网:http://www.icmrai.org 征稿主题 机电一体化机器人人工智能 传感器和执行器 3D打印技术 智能控制 运动控制 光电系统 光机电一体化 类人机器人 人机界面 先进的运动控制 集成制造系…

线性代数 | 知识点整理 Ref 3

注:本文为 “线性代数 | 知识点整理” 相关文章合辑。 因 csdn 篇幅合并超限分篇连载,本篇为 Ref 3。 略作重排,未整理去重。 图片清晰度限于引文原状。 如有内容异常,请看原文。 《线性代数》总复习要点、公式、重要结论与重点释…

CFD中的动量方程非守恒形式详解

在计算流体力学(CFD)中,动量方程可以写成守恒形式和非守恒形式,两者在数学上等价,但推导方式和应用场景不同。以下是对非守恒形式的详细解释: 1. 动量方程的守恒形式 首先回顾守恒形式的动量方程&#xff…

Leetcode 1504. 统计全 1 子矩形

1.题目基本信息 1.1.题目描述 给你一个 m x n 的二进制矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 1 。 1.2.题目地址 https://leetcode.cn/problems/count-submatrices-with-all-ones/description/ 2.解题方法 2.1.解题思路 单调栈 时间复杂度&…

【Docker】运行错误提示 unknown shorthand flag: ‘d‘ in -d ----详细解决方法

使用docker拉取Dify的时候遇到错误 错误提示 unknown shorthand flag: d in -dUsage: docker [OPTIONS] COMMAND [ARG...]错误原因解析 出现 unknown shorthand flag: d in -d 的根本原因是 Docker 命令格式与当前版本不兼容,具体分为以下两种情况: 新…

华为OD机试真题——攀登者2(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录全流程解析/备考攻略/经验分享 华为OD机试真题《攀登者2…

qt硬件与软件通信中 16进制与十进制转化

1. 首先上代码, 这是在qt语言上的操作 截取 01 03 0C 00 00 00 00 00 00 00 0C 00 0C 00 0C 93 70 这串16进制数值进行处理,截取这样一段内容 00 0C 00 0C 00 0C 字节数组转字符串。从bytearray数组转换为string. QString CustomTcpSocket::recieveInfo() {QByteArr…

图形变换算法

一、学习目的 (1)掌握多面体的存储方法。 (2)掌握图形的几何变换及投影变换。 (3)掌握三维形体不同投影方法的投影图的生成原理。 (4)掌握多面体投影图绘制的编程方法。 二、学…

【JAVAFX】自定义FXML 文件存放的位置以及使用

情况 1:FXML 文件与调用类在同一个包中(推荐) 假设类 MainApp 的包是 com.example,且 FXML 文件放在 resources/com/example 下: 项目根目录 ├── src │ └── sample │ └── Main.java ├── src/s…

Ubuntu20.04安装企业微信

建议先去企业微信官网看一下有没有linux版本,没有的话在按如下方式安装,不过现在是没有的。 方案 1、使用docker容器 2、使用deepin-wine 3、使用星火应用商店 4. 使用星火包deepin-wine 5、使用ukylin-wine 本人对docker不太熟悉,现…

CSS appearance 属性:掌握UI元素的原生外观

在现代网页设计中,为了达到一致的用户体验,我们有时需要让HTML元素模仿操作系统的默认控件样式。CSS中的appearance属性提供了一种简便的方式来控制这些元素是否以及如何显示其默认外观。本文将详细介绍appearance属性,并通过实际代码示例来展…

十四、C++速通秘籍—函数式编程

目录 上一章节: 一、引言 一、函数式编程基础 三、Lambda 表达式 作用: Lambda 表达式捕获值的方式: 注意: 四、函数对象 函数对象与普通函数对比: 五、函数适配器 1、适配普通函数 2、适配 Lambda 表达式 …

大模型Rag-指令调度

本文主要记录根据用户问题指令,基于大模型做Rag,匹配最相关描述集进行指令调度,可用于匹配后端接口以及展示答案及图表等。 1.指令查询处理逻辑 1.实现思路 指令识别:主要根据用户的问题q计算与指令描述集is [i0, ... , im]和指…

音视频学习 - ffmpeg 编译与调试

编译 环境 macOS Ventrua 13.4 ffmpeg 7.7.1 Visual Studio Code Version: 1.99.0 (Universal) 操作 FFmpeg 下载源码 $ cd ffmpeg-x.y.z $ ./configure nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.If you think configure made a mistake…

golang-常见的语法错误

https://juejin.cn/post/6923477800041054221 看这篇文章 Golang 基础面试高频题详细解析【第一版】来啦~ 大叔说码 for-range的坑 func main() { slice : []int{0, 1, 2, 3} m : make(map[int]*int) for key, val : range slice {m[key] &val }for k, v : …

音视频之H.265/HEVC预测编码

H.265/HEVC系列文章: 1、音视频之H.265/HEVC编码框架及编码视频格式 2、音视频之H.265码流分析及解析 3、音视频之H.265/HEVC预测编码 预测编码是视频编码中的核心技术之一。对于视频信号来说,一幅图像内邻近像素之间有着较强的空间相关性,相邻图像之…

基于政务问答的dify接口请求测试

Dify 的智能体后端服务 API 为开发者提供便捷方式,能让前端应用直接调用大语言模型能力。在请求时,需先前往应用左侧导航的 “API Access” 部分,在此可查看文档和管理访问凭据。为保障安全,API 密钥应通过后端调用,避…

VMware Workstation 保姆级 Linux(CentOS) 创建教程(附 iso)

文章目录 一、下载二、创建 一、下载 CentOS-7.9-x86_64-DVD-2009.iso 二、创建 VMware Workstation 保姆级安装教程(附安装包) VMware Workstation 保姆级安装教程(附安装包) VMware Workstation 保姆级安装教程(附安装包)

扩增子分析|基于R语言microeco包进行微生物群落网络分析(network网络、Zi-Pi关键物种和subnet子网络图)

一、引言 microeco包是福建农林大学姚敏杰教授团队开发的扩增子测序集成分析。该包综合了扩增子测序下游分析的多种功能包括群落组成、多样性、网络分析、零模型等等。通过简单的几行代码可实现复杂的分析。因此,microeco包发表以来被学界广泛关注,截止2…

GO语言-数据类型

文章目录 变量定义1. 整数类型2. 浮点类型3. 字符类型4. 布尔类型5. 字符串类型5.1 字符串的本质5.2 常用字符串处理函数(strings包)5.3 修改字符串的方式 6. 数据默认值7. 类型转换 变量定义 代码如下: package mainimport "fmt"var i1 1000 var i2 i…