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

Tensor常见操作

一、Tensor常见操作

在深度学习中,Tensor是一种多维数组,用于存储和操作数据,我们需要掌握张量各种运算。

1. 获取元素值

我们可以把单个元素tensor转换为Python数值,这是非常常用的操作

import torch
​
​
def test002():data = torch.tensor([18])print(data.item())pass
​
​
if __name__ == "__main__":test002()
​

注意:

  • 和Tensor的维度没有关系,都可以取出来!

  • 如果有多个元素则报错

  • 仅适用于CPU张量,如果张量在GPU上,需先移动到CPU

  • gpu_tensor = torch.tensor([1.0], device='cuda')
    value = gpu_tensor.cpu().item()  # 先转CPU再提取

2. 元素值运算

常见的加减乘除次方取反开方等各种操作,带有_的方法则会替换原始值。

import torch
​
​
def test001():# 生成范围 [0, 10) 的 2x3 随机整数张量data = torch.randint(0, 10, (2, 3))print(data)# 元素级别的加减乘除:不修改原始值print(data.add(1))print(data.sub(1))print(data.mul(2))print(data.div(3))print(data.pow(2))
​# 元素级别的加减乘除:修改原始值data = data.float()data.add_(1)data.sub_(1)data.mul_(2)data.div_(3.0)data.pow_(2)print(data)
​
​
if __name__ == "__main__":test001()
​

3. 阿达玛积(点积)

阿达玛积是指两个形状相同的矩阵或张量对应位置的元素相乘。它与矩阵乘法不同,矩阵乘法是线性代数中的标准乘法,而阿达玛积是逐元素操作。假设有两个形状相同的矩阵 A和 B,它们的阿达玛积 C=A∘B定义为:

$$
C_{ij}=A_{ij}×B_{ij}
$$

其中:

  • Cij 是结果矩阵 C的第 i行第 j列的元素。

  • Aij和 Bij分别是矩阵 A和 B的第 i行第 j 列的元素。

在 PyTorch 中,可以使用mul函数或者*来实现;

import torch
​
​
def test001():data1 = torch.tensor([[1, 2, 3], [4, 5, 6]])data2 = torch.tensor([[2, 3, 4], [2, 2, 3]])print(data1 * data2)
​
​
def test002():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__":test001()test002()
​

4. Tensor相乘

矩阵乘法是线性代数中的一种基本运算,用于将两个矩阵相乘,生成一个新的矩阵。

假设有两个矩阵:

  • 矩阵 A的形状为 m×n(m行 n列)。

  • 矩阵 B的形状为 n×p(n行 p列)。

矩阵 A和 B的乘积 C=A×B是一个形状为 m×p的矩阵,其中 C的每个元素 Cij,计算 A的第 i行与 B的第 j列的点积。计算公式为:

$$
C_{ij}=∑_{k=1}^nA_{ik}×B_{kj}
$$

矩阵乘法运算要求如果第一个矩阵的shape是 (N, M),那么第二个矩阵 shape必须是 (M, P),最后两个矩阵点积运算的shape为 (N, P)。

在 PyTorch 中,使用@或者matmul完成Tensor的乘法。

import torch
​
​
def test006():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__":test006()
​

5. 形状操作

在 PyTorch 中,张量的形状操作是非常重要的,因为它允许你灵活地调整张量的维度和结构,以适应不同的计算需求。

5.1 reshape

可以用于将张量转换为不同的形状,但要确保转换后的形状与原始形状具有相同的元素数量。

import torch
​
​
def test001():data = torch.randint(0, 10, (4, 3))print(data)# 1. 使用reshape改变形状data = data.reshape(2, 2, 3)print(data)
​# 2. 使用-1表示自动计算data = data.reshape(2, -1)print(data)
​
​
if __name__ == "__main__":test001()
​

5.2 view

view进行形状变换的特征:

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

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

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

5.2.1 内存连续性

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

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

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

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

执行结果:

正常情况下的张量: True
转置操作的张量: False
tensor([[1, 4],[2, 5],[3, 6]])
Traceback (most recent call last):File "e:\01.深度学习\01.参考代码\14.PyTorch.内存连续性.py", line 20, in <module>test001()File "e:\01.深度学习\01.参考代码\14.PyTorch.内存连续性.py", line 13, in test001tensor = tensor.view(2, -1)
RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.
5.2.2 和reshape比较

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

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

5.2.3 view变形操作
import torch
​
​
def test002():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__":test002()
​

5.3 transpose

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

torch.transpose(input, dim0, dim1)

参数

  • input: 输入的张量。

  • dim0: 要交换的第一个维度。

  • dim1: 要交换的第二个维度。

import torch
​
​
def test003():data = torch.randint(0, 10, (3, 4, 5))print(data, data.shape)# 使用transpose进行形状变换transpose_data = torch.transpose(data,0,1)# transpose_data = data.transpose(0, 1)print(transpose_data, transpose_data.shape)
​
​
if __name__ == "__main__":test003()
​

transpose 返回新张量,原张量不变

转置后的张量可能是非连续的(is_contiguous() 返回 False),如果需要连续内存(如某些操作要求),可调用 .contiguous():

y = x.transpose(0, 1).contiguous()

5.4 permute

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

torch.permute(input, dims)

参数

  • input: 输入的张量。

  • dims: 一个整数元组,表示新的维度顺序。

import torch
​
​
def test004():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__":test004()
​

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

重排后的张量可能是非连续的(is_contiguous() 返回 False),必要时需调用 .contiguous():

y = x.permute(2, 1, 0).contiguous()

维度顺序必须合法:dims 中的维度顺序必须包含所有原始维度,且不能重复或遗漏。例如,对于一个形状为 (2, 3, 4) 的张量,dims=(2, 0, 1) 是合法的,但 dims=(0, 1) 或 dims=(0, 1, 2, 3) 是非法的。

与 transpose() 的对比

特性permute()transpose()
功能可以同时调整多个维度的顺序只能交换两个维度的顺序
灵活性更灵活较简单
使用场景适用于多维张量适用于简单的维度交换

5.5 升维和降维

在后续的网络学习中,升维和降维是常用操作,需要掌握。

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

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

5.5.1 squeeze降维
torch.squeeze(input, dim=None)

参数

  • input: 输入的张量。

  • dim (可选): 指定要移除的维度。如果指定了 dim,则只移除该维度(前提是该维度大小为 1);如果不指定,则移除所有大小为 1 的维度。

import torch
​
​
def 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()
​
5.5.2 unsqueeze升维
torch.unsqueeze(input, dim)

参数

  • input: 输入的张量。

  • dim: 指定要增加维度的位置(从 0 开始索引)。

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

6. 广播机制

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

6.1 广播机制规则

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

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

  • 满足右对齐

6.2 广播案例

1D和2D张量广播

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

输出:

torch.Size([3]) torch.Size([3, 1])tensor([[5, 6, 7],[3, 4, 5],[4, 5, 6]])

2D 和 3D 张量广播

广播机制会根据需要对两个张量进行形状扩展,以确保它们的形状对齐,从而能够进行逐元素运算。广播是双向奔赴的。

import torch
​
​
def test001():# 2D 张量a = torch.tensor([[1, 2, 3], [4, 5, 6]])# 3D 张量b = torch.tensor([[[2, 3, 4]], [[5, 6, 7]]])print(a.shape, b.shape)# 进行运算result = a + bprint(result, result.shape)
​
​
if __name__ == "__main__":test001()
​

执行结果:

torch.Size([2, 3]) torch.Size([2, 1, 3])
tensor([[[ 3,  5,  7],[ 6,  8, 10]],
​[[ 6,  8, 10],[ 9, 11, 13]]]) torch.Size([2, 2, 3])

最终参与运算的a和b形式如下:

# 2D 张量
a = torch.tensor([[[1, 2, 3], [4, 5, 6]],[[1, 2, 3], [4, 5, 6]]])
​
# 3D 张量
b = torch.tensor([[[2, 3, 4], [2, 3, 4]], [[5, 6, 7], [5, 6, 7]]])
import torch
import numpy as np
'''
张量的形状操作
'''
# reshape 变形
def reshape_play():data = torch.randint(0,10,(4,3))print(data)# 使用reshape改变形状data = data.reshape(2,2,-1) # -1 自动计算print(data)# view 变形
def view_play():data = torch.randint(0,10,(4,3))print(data)# 转置data = data.t()# 内存不连续 报错data = data.view(2,2,-1)'''RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.'''print(data)# transpose 交换张量的两个维度
def transpose_play():data = torch.randint(0,10,(4,3))print(data.shape)data = torch.transpose(data,0, 1)print(data.shape)# permute 改变维度顺序
def permute_play():data = torch.randint(0,10,(1,4,3))print(data.shape)data = data.permute(1,2,0)print(data.shape)# squeeze 降维 unsqueeze 升维
def squeeze_play():data = torch.randint(0,10,(1,4,3))print(data.shape)'''只能移除大小为1的维度'''data = torch.squeeze(data,dim=0)print(data.shape)# 升维data = torch.unsqueeze(data,dim=1)print(data.shape)print("y.grad:", y.grad)  # 输出: tensor([1., 2., 3.])
if __name__ == '__main__':# reshape_play()# view_play()# transpose_play()# permute_play()# squeeze_play()

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

相关文章:

  • vscode使用cmake tool进行项目管理安装
  • Elasticsearch映射:优化搜索性能的关键
  • 【无标题】计数组合学7.21(有界部分大小的平面分拆)
  • JVM模型
  • 微信小程序web-view嵌套H5,小程序与H5通信
  • 不安全的服务器,不支持 FTP over TLS
  • 服务器从0到1微服务所需的环境的安装
  • 数据结构(一):算法的时间复杂度和空间复杂度
  • 双坡阳光房光伏设计,精准实现降本增效
  • 【Python】QT(PySide2、PyQt5):列表数据保存到文件,文件数据加载到列表
  • QT(QTableWidget)
  • Matlab使用——开发上位机APP,通过串口显示来自单片机的电压电流曲线,实现光伏I-V特性监测的设计
  • 盲盒一番赏小程序:打造个性化潮玩购物天堂
  • vs2022 Nuget包缓存下载路径配置
  • 国产机安装caj 国产机没法打开caj文件,国产机如何看论文?
  • AIGC(生成式AI)试用 35 -- AI Agent开发及工作流,LangFlow
  • github拉取OpenSSL SSL_read: Connection was reset, errno 10054
  • Element中table组件(el-table)右侧滚动条空白占位gutter处理
  • window电脑使用OpenSSL创建Ed25519密钥
  • 由倍讯科技研制的CCLinkIE转ModbusTCP网关,可达成与脉冲计数器的连接
  • Tesseract OCR之单词识别与字符分类器
  • Docker:部署Redis
  • 常见flex布局思路:flex布局上下结构
  • 2025中国生物制造科技创新论坛为何“花落”常德?
  • 新源布料厂进销存管理系统-项目分享
  • week5-[字符数组]查找
  • 木马免杀工具使用
  • 智汇云舟:视频孪生技术引领行业变革的场景应用实践
  • 第二十三天-FSMC简介
  • 技术速递|Model Context Protocol (MCP) 支持已上线 JetBrains、Eclipse 和 Xcode