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

深度学习之张量

目录

一、Tensor基础

概念

特点

数据类型

二、Tensor张量的创建

基本创建方式

torch.tensor

torch.Tensor

torch.IntTensor

线性张量

随机张量

随机数种子

随机张量

三、Tensor常见属性

获取属性

切换设备

类型转换

四、Tensor数据转换

Tensor与Numpy

张量转numpy

numpy转张量

五、Tensor常见操作

获取元素值

阿达玛积

Tensor相乘

形状操作

reshape

view

内存连续性

view变形操作

transpose

permute

变维

降维

升维

广播机制

六、自动微分

计算梯度

标量梯度计算

向量梯度计算

多标量梯度计算

多向量梯度计算

梯度上下文控制

控制梯度计算

累计梯度

梯度清零

总结


一、Tensor基础

概念

张量是一个多维数组,通俗来说可以看作是扩展了标量、向量、矩阵的更高维度的数组。张量的维度决定了它的形状(Shape),例如:

  • 标量 是 0 维张量,如 a = torch.tensor(5)

  • 向量 是 1 维张量,如 b = torch.tensor([1, 2, 3])

  • 矩阵 是 2 维张量,如 c = torch.tensor([[1, 2], [3, 4]])

  • 更高维度的张量,如3维、4维等,通常用于表示图像、视频数据等复杂结构。

特点

    动态计算图:PyTorch 支持动态计算图,这意味着在每一次前向传播时,计算图是即时创建的。

    GPU 支持:PyTorch 张量可以通过 .to('cuda') 移动到 GPU 上进行加速计算。

    自动微分:通过 autograd 模块,PyTorch 可以自动计算张量运算的梯度,这对深度学习中的反向传播算法非常重要。

数据类型

PyTorch中有3种数据类型:浮点数、整数、布尔。其中,浮点数和整数又分为8位、16位、32位、64位,加起来共9种。

为什么要分为8位、16位、32位、64位呢?

场景不同,对数据的精度和速度要求不同。通常,移动或嵌入式设备追求速度,对精度要求相对低一些。精度越高,往往效果也越好,自然硬件开销就比较高。

二、Tensor张量的创建

基本创建方式

torch.tensor

这里的tensor是小写,是根据指定的数据创建张量。

import torch
import numpy as npdef test1():# 1.用标量创建张量tensor = torch.tensor(5)print(tensor.shape)# 2.使用numpy随机一个数组创建张量tensor = torch.tensor(np.random.randn(3, 5))print(tensor)print(tensor.shape)# 3.根据list创建tensortensor = torch.tensor([[1, 2, 3], [4, 5, 6]])print(tensor)print(tensor.shape)print(tensor.dtype)# 调用函数方法
if __name__ == '__main__':test1()

如果出现如下错误:

UserWarning: Failed to initialize NumPy: _ARRAY_API not found

一般是因为numpy和pytorch版本不兼容,可以选择降低numpy版本

torch.Tensor

这里的Tensor是大写,根据形状创建张量,也可用来创建指定数据的张量

import torch
import numpy as npdef test2():# 1.根据形状创建张量tensor1 = torch.Tensor(2, 3)print(tensor1)# 2.也可以是具体的值tensor2 = torch.Tensor([[1, 2, 3], [4, 5, 6]])print(tensor2, tensor2.shape, tensor2.dtype)tensor3 = torch.Tensor([10])print(tensor3, tensor3.shape, tensor3.dtype)# 指定tensor数据类型tensor1 = torch.Tensor([1,2,3]).short()print(tensor1)tensor1 = torch.Tensor([1,2,3]).int()print(tensor1)tensor1 = torch.Tensor([1,2,3]).float()print(tensor1)tensor1 = torch.Tensor([1,2,3]).double()print(tensor1)if __name__ == "__main__":test2()

torch.Tensor与torch.tensor区别

特性torch.Tensor()torch.tensor()
数据类型推断强制转为 torch.float32根据输入数据自动推断(如整数→int64
显式指定 dtype不支持支持(如 dtype=torch.float64
设备指定不支持支持(如 device='cuda'
输入为张量时的行为创建新副本(不继承原属性)默认共享数据(除非 copy=True
推荐使用场景需要快速创建浮点张量需要精确控制数据类型或设备

torch.IntTensor

用于创建指定类型的张量,还有诸如Torch.FloatTensor、 torch.DoubleTensor、 torch.LongTensor......等。

如果数据类型不匹配,那么在创建的过程中会进行类型转换,要尽可能避免,防止数据丢失。

import torchdef test3():# 创建指定形状的张量t1 = torch.IntTensor(2, 3)print(t1)t2 = torch.FloatTensor(3, 3)print(t2, t2.dtype)t3 = torch.DoubleTensor(3, 3)print(t3, t3.dtype)t4 = torch.LongTensor(3, 3)print(t4, t4.dtype)t5 = torch.ShortTensor(3, 3)print(t5, t5.dtype)if __name__ == "__main__":test3()

线性张量

使用torch.arange 和 torch.linspace 创建线性张量:

import torch
import numpy as np# 不用科学计数法打印
torch.set_printoptions(sci_mode=False)def test4():# 1.创建线性张量r1 = torch.arange(0, 10, 2)print(r1)# 2.在指定空间按照元素个数生成张量:等差r2 = torch.linspace(3, 10, 10)   # star  end  stepprint(r2)r2 = torch.linspace(3, 10000000, 10)print(r2)if __name__ == "__main__":test4()

随机张量

使用torch.randn 创建随机张量。 使用随机数种子。

随机数种子

import torchdef test1():# 设置随机数种子torch.manual_seed(123)# 获取随机数种子print(torch.initial_seed())if __name__ == "__main__":test1()

随机张量

在 PyTorch 中,种子影响所有与随机性相关的操作,包括张量的随机初始化、数据的随机打乱、模型的参数初始化等。通过设置随机数种子,可以做到模型训练和实验结果在不同的运行中进行复现。

import torchdef test001():# 1.设置随机数种子torch.manual_seed(123)# 2.获取随机数种子,需要查看种子时调用print(torch.initial_seed())# 3.生成随机张量,均匀分布(范围 [0, 1))# 创建2个样本,每个样本3个特征print(torch.rand(2, 3))# 4.生成随机张量:标准正态分布(均值 0,标准差 1)print(torch.randn(2, 3))# 5.原生服从正态分布:均值为2, 方差为3,形状为1*4的正态分布print(torch.normal(mean=2, std=3, size=(1, 4)))if __name__ == "__main__":test001()

三、Tensor常见属性

获取属性

import torch
def test1():data = torch.tensor([1, 2, 3])# 张量的数据类型、所在设备、形状print(data.dtype, data.device, data.shape)if __name__ == "__main__":test1()

切换设备

import torch
def test001():data = torch.tensor([1, 2, 3])print(data.dtype, data.device, data.shape)# 把数据切换到GPU进行运算device = "cuda" if torch.cuda.is_available() else "cpu"data = data.to(device)print(data.device)if __name__ == "__main__":test001()

类型转换

import torch
def test001():data = torch.tensor([1, 2, 3])print(data.dtype)  # torch.int64# 1. 使用type进行类型转换data = data.type(torch.float32)print(data.dtype)  # float32data = data.type(torch.float16)print(data.dtype)  # float16# 2. 使用类型方法data = data.float()print(data.dtype)  # float32# 16 位浮点数,torch.float16,即半精度data = data.half()print(data.dtype)  # float16data = data.double()print(data.dtype)  # float64data = data.long()print(data.dtype)  # int64data = data.int()print(data.dtype)  # int32#  使用dtype属性data = torch.tensor([1, 2, 3], dtype=torch.half)print(data.dtype)if __name__ == "__main__":test001()

四、Tensor数据转换

共享内存问题:PyTorch与NumPy的转换默认共享内存,修改会影响原始数据

Tensor与Numpy

张量转numpy

def test1():# 张量转numpy   浅拷贝t_tensor= torch.tensor([1,2,5])t_numpy= t_tensor.numpy()t_numpy[0]=2#深拷贝t_numpy1=t_tensor.numpy().copy()print(t_tensor)print(t_numpy)print(t_numpy1)if __name__=='__main__':test1()

numpy转张量

def test3():#numpy转张量   浅拷贝t_numpy=np.array([1,2,3])t_tensor=torch.from_numpy(t_numpy)print(t_numpy)print(t_tensor)#深拷贝t_numpy=np.array([[1,3,2],[4,6,2]])t_tensor=torch.tensor(t_numpy)print(t_numpy)print(t_tensor)if __name__=='__main__':test3()

五、Tensor常见操作

获取元素值

def test1():t = torch.tensor(10)print(t.item())t2=torch.tensor([[10]])print(t2.item())if __name__=='__main__':test1()

阿达玛积

import torch
# 点积:对应位置相乘但是不相加
def test1():data1 = torch.tensor([[1, 2, 3], [4, 5, 6]])data2 = torch.tensor([[2, 3, 4], [2, 2, 3]])print(data1 * data2)def test2():data1 = torch.tensor([[1, 2, 3], [4, 5, 6]])data2 = torch.tensor([[2, 3, 4], [2, 2, 3]])print(data1.mul(data2))if __name__ == "__main__":test1()test2()

Tensor相乘

import torch
def test6():data1 = torch.tensor([[1, 2, 3],[4, 5, 6]])data2 = torch.tensor([[3, 2],[2, 3],[5, 3]])print(data1 @ data2)print(data1.matmul(data2))if __name__ == "__main__":test6()

形状操作

reshape

import torch
def test001():#0-10随机生成4行3列数据data = torch.randint(0, 10, (4, 3))print(data)# 1. 使用reshape改变形状# 包含 2 个块,每个块包含 2 行,每行包含 3 个元素data = data.reshape(2, 2, 3)print(data)# 2. 使用-1表示自动计算data = data.reshape(2, -1)print(data)if __name__ == "__main__":test001()

view

view进行形状变换的特征:

  • 张量在内存中是连续的;

  • 返回的是原始张量视图,不重新分配内存,效率更高;

  • 如果张量在内存中不连续,view 将无法执行,并抛出错误。

与reshape比较:

view:高效,但需要张量在内存中是连续的;

reshape:更灵活,但涉及内存复制;

内存连续性

张量的内存布局决定了其元素在内存中的存储顺序。对于多维张量,内存布局通常按照最后一个维度优先的顺序存储,即先存列,后存行。例如,对于一个二维张量 A,其形状为 (m, n),其内存布局是先存储第 0 行的所有列元素,然后是第 1 行的所有列元素,依此类推。

如果张量的内存布局与形状完全匹配,并且没有被某些操作(如转置、索引等)打乱,那么这个张量就是连续的

PyTorch 的大多数操作都是基于 C 顺序的,我们在进行变形或转置操作时,很容易造成内存的不连续性。

import torch
def test1():tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])print("正常情况下的张量:", tensor.is_contiguous())# 对张量进行转置操作tensor = tensor.t()print("转置操作的张量:", tensor.is_contiguous())print(tensor)# 此时使用view进行变形操作# view要求张量连续tensor = tensor.view(2, -1)print(tensor)if __name__ == "__main__":test1()

view变形操作
import torch
def test2():tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])# 将 2x3 的张量转换为 3x2reshaped_tensor = tensor.view(3, 2)print(reshaped_tensor)# 自动推断一个维度,每个维度两个数据reshaped_tensor = tensor.view(-1, 2)print(reshaped_tensor)if __name__ == "__main__":test2()

transpose

transpose 用于交换张量的两个维度,注意,是2个维度,它返回的是原张量的视图。

import torch
def test3():data = torch.randint(0, 10, (3, 4, 5))print(data, data.shape)# 使用transpose进行形状变换,原始数据的0维度和1维度transpose_data = torch.transpose(data,0,1)# transpose_data = data.transpose(0, 1)print(transpose_data, transpose_data.shape)if __name__ == "__main__":test3()

permute

通过重新排列张量的维度来返回一个新的张量,不改变张量的数据,只改变维度的顺序。

import torch
def test4():data = torch.randint(0, 10, (3, 4, 5))print(data, data.shape)# 使用permute进行多维度形状变换permute_data = data.permute(1, 2, 0)print(permute_data, permute_data.shape)if __name__ == "__main__":test4()

和 transpose 一样,permute 返回新张量,原张量不变。

变维

unsqueeze:用于在指定位置插入一个大小为 1 的新维度。

squeeze:用于移除所有大小为 1 的维度,或者移除指定维度的大小为 1 的维度。

降维
import torchdef test006():data = torch.randint(0, 10, (1, 4, 5, 1))print(data, data.shape)# 进行降维操作data1 = data.squeeze(0).squeeze(-1)print(data.shape)# 移除所有大小为 1 的维度data2 = torch.squeeze(data)# 尝试移除第 1 维(大小为 3,不为 1,不会报错,张量保持不变。)data3 = torch.squeeze(data, dim=1)print("尝试移除第 1 维后的形状:", data3.shape)if __name__ == "__main__":test006()

升维
import torch
def test7():data = torch.randint(0, 10, (32, 32, 3))print(data.shape)# 升维操作data = data.unsqueeze(0)print(data.shape)if __name__ == "__main__":test7()

广播机制

广播机制允许在对不同形状的张量进行计算,而无需显式地调整它们的形状。广播机制通过自动扩展较小维度的张量,使其与较大维度的张量兼容,从而实现按元素计算。

广播机制需要遵循以下规则:

  • 每个张量的维度至少为1

  • 满足右对齐

import torch
def test6():data1d = torch.tensor([1, 2, 3])data2d = torch.tensor([[4], [2], [3]])print(data1d.shape, data2d.shape)# 进行计算:会自动进行广播机制print(data1d + data2d)if __name__ == "__main__":test6()

六、自动微分

自动微分模块torch.autograd负责自动计算张量操作的梯度,具有自动求导功能。自动微分模块是构成神经网络训练的必要模块,可以实现网络权重参数的更新,使得反向传播算法的实现变得简单而高效。

计算梯度

在上述代码中,x 和 y 是输入张量,即叶子节点,z 是中间结果,loss 是最终输出。每一步操作都会记录依赖关系:

z = x * y:z 依赖于 x 和 y。

loss = z.sum():loss 依赖于 z。

叶子节点

在 PyTorch 的自动微分机制中,叶子节点(leaf node) 是计算图中:

  • 由用户直接创建的张量,并且它的 requires_grad=True。

  • 这些张量是计算图的起始点,通常作为模型参数或输入变量。

特征:

  • 没有由其他张量通过操作生成。

  • 如果参与了计算,其梯度会存储在 leaf_tensor.grad 中。

  • 默认情况下,叶子节点的梯度不会自动清零,需要显式调用 optimizer.zero_grad() 或 x.grad.zero_() 清除。

判断叶子节点

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)  # 叶子节点
y = x ** 2  # 非叶子节点(通过计算生成)
z = y.sum()print(x.is_leaf)  # True
print(y.is_leaf)  # False
print(z.is_leaf)  # False

叶子节点与非叶子节点的区别

特性叶子节点非叶子节点
创建方式用户直接创建的张量通过其他张量的运算生成
is_leaf 属性TrueFalse
梯度存储梯度存储在 .grad 属性中梯度不会存储在 .grad,只能通过反向传播传递
是否参与计算图是计算图的起点是计算图的中间或终点
删除条件默认不会被删除在反向传播后,默认被释放(除非 retain_graph=True)

特点

  • 返回的张量是一个新的张量,与原始张量共享数据。

  • 对 x.detach() 的操作不会影响原始张量的梯度计算。

  • 推荐使用 detach(),因为它更安全,且在未来版本的 PyTorch 中可能会取代 data。

反向传播

使用tensor.backward()方法执行反向传播,从而计算张量的梯度。这个过程会自动计算每个张量对损失函数的梯度。例如:调用 loss.backward() 从输出节点 loss 开始,沿着计算图反向传播,计算每个节点的梯度。

梯度

计算得到的梯度通过tensor.grad访问,这些梯度用于优化模型参数,以最小化损失函数。

标量梯度计算

import torch
def test001():x = torch.tensor(10.5, requires_grad=True)print(x.requires_grad)  # True# 1. 默认y的requires_grad=Truey = x**2 + 2 * x + 3print(y.requires_grad)  # True# 2. 如果不需要y计算梯度-with进行上下文管理with torch.no_grad():y = x**2 + 2 * x + 3print(y.requires_grad)  # False# 3. 如果不需要y计算梯度-使用装饰器@torch.no_grad()def y_fn(x):return x**2 + 2 * x + 3y = y_fn(x)print(y.requires_grad)  # False# 4. 如果不需要y计算梯度-全局设置,需要谨慎torch.set_grad_enabled(False)y = x**2 + 2 * x + 3print(y.requires_grad)  # Falseif __name__ == "__main__":test001()

向量梯度计算

import torch
def test3():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)# 2. 操作张量y = x ** 2# 3. 计算梯度,也就是反向传播y.backward()# 4. 读取梯度值print(x.grad)if __name__ == "__main__":test3()

以上会报错:错误预警:RuntimeError: grad can be implicitly created only for scalar outputs

import torch
def test002():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)# 2. 操作张量y = x ** 2# 3. 损失函数loss = y.mean()# 4. 计算梯度,也就是反向传播loss.backward()# 5. 读取梯度值print(x.grad)if __name__ == "__main__":test002()

多标量梯度计算

由于 y 是一个向量,我们需要提供一个与 y 形状相同的向量作为 backward() 的参数,这个参数通常被称为 梯度张量(gradient tensor),它表示 y 中每个元素的梯度。

import torch
def test3():# 1. 创建两个标量x1 = torch.tensor(5.0, requires_grad=True, dtype=torch.float64)x2 = torch.tensor(3.0, requires_grad=True, dtype=torch.float64)# 2. 构建运算公式y = x1 ** 2 + 2 * x2 + 7# 3. 计算梯度,也就是反向传播y.backward()# 4. 读取梯度值print(x1.grad, x2.grad)# 输出:# tensor(10., dtype=torch.float64) tensor(2., dtype=torch.float64)
if __name__ == "__main__":test3()

多向量梯度计算

import torch
def test4():# 创建两个张量,并设置 requires_grad=Truex = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)y = torch.tensor([4.0, 5.0, 6.0], requires_grad=True)# 前向传播:计算 z = x * yz = x * y# 前向传播:计算 loss = z.sum()loss = z.sum()# 查看前向传播的结果print("z:", z)  # 输出: tensor([ 4., 10., 18.], grad_fn=<MulBackward0>)print("loss:", loss)  # 输出: tensor(32., grad_fn=<SumBackward0>)# 反向传播:计算梯度loss.backward()# 查看梯度print("x.grad:", x.grad)  # 输出: tensor([4., 5., 6.])print("y.grad:", y.grad)  # 输出: tensor([1., 2., 3.])if __name__ == "__main__":test4()

梯度上下文控制

梯度计算的上下文控制和设置对于管理计算图、内存消耗、以及计算效率至关重要。

控制梯度计算

import torch
def test1():x = torch.tensor(10.5, requires_grad=True)print(x.requires_grad)  # True# 1. 默认y的requires_grad=Truey = x**2 + 2 * x + 3print(y.requires_grad)  # True# 2. 如果不需要y计算梯度-with进行上下文管理with torch.no_grad():y = x**2 + 2 * x + 3print(y.requires_grad)  # False# 3. 如果不需要y计算梯度-使用装饰器@torch.no_grad()def y_fn(x):return x**2 + 2 * x + 3y = y_fn(x)print(y.requires_grad)  # False# 4. 如果不需要y计算梯度-全局设置,需要谨慎torch.set_grad_enabled(False)y = x**2 + 2 * x + 3print(y.requires_grad)  # Falseif __name__ == "__main__":test1()

累计梯度

默认情况下,当我们重复对一个自变量进行梯度计算时,梯度是累加的

import torch
def test2():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 5.3], requires_grad=True)# 2. 累计梯度:每次计算都会累计梯度for i in range(3):y = x**2 + 2 * x + 7z = y.mean()z.backward()print(x.grad)if __name__ == "__main__":test2()

梯度清零

import torch
def test2():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 5.3], requires_grad=True)# 2. 累计梯度:每次计算都会累计梯度for i in range(3):y = x**2 + 2 * x + 7z = y.mean()# 2.1 反向传播之前先对梯度进行清零if x.grad is not None:x.grad.zero_()z.backward()print(x.grad)if __name__ == "__main__":test2()# 输出:
# tensor([1.3333, 2.0000, 4.2000])
# tensor([1.3333, 2.0000, 4.2000])
# tensor([1.3333, 2.0000, 4.2000])

总结

以上便是此次对于张量的部分总结操作,如若文章有错或是您还有疑问,欢迎在评论区指正提出,我会尽快的帮助解决,感谢您的阅读!

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

相关文章:

  • ros2 单线程与多线程
  • MySQL相关概念和易错知识点(4)(分组查询、连接查询、合并查询、子查询)
  • M8-11 RFID模块通过RS485转Profinet网关与PLC通信的配置指南
  • springboot 2.4跨域变化和swagger结合的问题
  • 智能的本质
  • 递归---记忆化搜索
  • 前端Web在Vue中的知识详解
  • 【MySQL】事务的基本概念
  • 智慧物流仓储分拣:陌讯多模态识别方案让准确率↑29.3% 实战解析
  • js零基础入门
  • 零基础-动手学深度学习-10.1. 注意力提示
  • vs2022编译Activemq
  • AnyDesk远程工具免费版,v9.5.110绿色便携版,秒连远程桌面,剪贴板同步超实用
  • 网络管理实战
  • B.10.01.6-DDD领域驱动设计:从理论到落地的完整指南
  • 【LLM实战|langgraph】langgrpah基础
  • WD5030A 芯片,24V降12V,输出电流15A,高度集成实现高效能与低成本的完美平衡
  • 如何免费配置各类AI API_Key?(附接入后测试)
  • 创建一个django项目
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(15):文法+单词第5回
  • 生产环境某业务服务JVM调优总结
  • DAY35打卡
  • [IOMMU]面向芯片/SoC验证工程的IOMMU全景速览
  • FMS 2025存储峰会获奖技术全景解读
  • 【linux基础】Linux命令提示符解析与操作指南
  • c++ 容器vector基础
  • 北斗变形监测技术应用与案例解析
  • RK3568 U盘/TF卡镜像更新
  • Mysql笔记-系统变量\用户变量管理
  • 学习嵌入式第二十四天