当前位置: 首页 > 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.xdnf.cn/news/1368397.html

相关文章:

  • pycharm 远程连接服务器报错
  • Java基础第二课:hello word
  • 160.在 Vue3 中用 OpenLayers 解决国内 OpenStreetMap 地图加载不出来的问题
  • 从行业智能体到一站式开发平台,移动云推动AI智能体规模化落地
  • Windows 命令行:mkdir 命令
  • 三菱FX5U PLC访问字变量的某一位
  • Elasticsearch精准匹配与全文检索对比
  • 如何从零开始学习黑客技术?网络安全入门指南
  • 读《精益数据分析》:用户行为热力图
  • 【算法--链表题2】19.删除链表的倒数第 N 个节点:通俗详解
  • 腾讯开源OpenTenBase深度实践:企业级分布式HTAP数据库部署全攻略
  • Qt数据结构与编码技巧全解析
  • Spring - 文件上传与下载:真正的企业开发高频需求——Spring Boot文件上传与下载全场景实践指南
  • 基于stm32的物联网OneNet火灾报警系统
  • 支持向量机(SVM)内容概述
  • Hive高阶函数之行转列JSON数据解析
  • uniapp 引入使用u-view 完整步骤,u-view 样式不生效
  • 要闻集锦|阿里官网调整为四大业务板块;华为云重组多个事业部涉及上千人;群核科技在港交所更新招股书
  • 开源 python 应用 开发(十三)AI应用--百度智能云TTS语音合成
  • vscode 配置 + androidStudio配置
  • uniapp 自动升级-uni-upgrade-center
  • 复盘一个诡异的Bug之FileNotFoundException
  • 【实时Linux实战系列】实时信号处理在通信中的应用
  • leetcode-python-383赎金信
  • 为什么选择爱普生TG5032CFN温补晶振—可穿戴设备?
  • MATLAB Figure画布中绘制表格详解
  • PySINDy
  • 扩展现有的多模块 Starter
  • 【yocto】Yocto Project 核心:深入了解.bbclass文件
  • DevSecOps 集成 CI/CD Pipeline:实用指南