从 X 入门Pytorch——Tensor的索引,切片,拼接,拆分,Reduction操作

本文参加新星计划人工智能(Pytorch)赛道: https://bbs.csdn.net/topics/613989052
承接上文:自己深度学习环境搭建和免费环境使用+Tensor构造+Tensor基本操作: 从 X 入门深度学习(Pytorch版本)

这里写目录标题

    • 1 Tensor的索引和切片
    • 2 Tensor的转换
    • 3 Tensor的拼接
    • 4 Tensor的拆分
    • 5 Tensor的规约操作

1 Tensor的索引和切片

汇总:

NameOut
a[i, j, k, …] = a[i][j][k][…]获取张量a的具体数据
a[start : end : step, start1 : end1 : step1, ]获取张量a第一维[start, end)步长为step的数据,第二维类似,详情看例子1-3
a[…, start : end : step]获取张量a前面维度所有数据,只针对最后维度数据进行切片,详情看例子4
布尔索引详情看例子5
整数索引详情看例子6
torch.nonzero()获得数据中非0的位置 详情看例子7
torch.where(condition, x, y)conditon成立是,使用x中的数据,否则使用y中的数据,见例子8

a为高维张量

例子:
获取张量中的一个具体数据:

import torch
x = torch.randint(0,24, (2, 3, 4))
print(x)
print(x[1,2,3], x[1][2][3], x[1][2])

out:
tensor([[[ 3, 16, 17, 16],
         [ 0, 20, 15, 19],
         [23, 16,  3, 11]],

        [[20, 20, 18,  0],
         [13,  6, 19, 15],
         [ 3, 20,  0, 18]]])
tensor(18) tensor(18) tensor([ 3, 20,  0, 18])

切片
以前也知道,但是一直没太搞清楚,这次重新学了一下,大概把规律都掌握了:
一般都是使用start : end : step来表示获取的数据范围,范围是前闭后开,step表示步长,Pytorch不支持负步长,但是支持负索引,-1指的是该维度下的最后一个索引,结合张量索引的知识点,你把他放在那个维度上,它就对那个维度起作用。
例子1:含有步长的切片

x = torch.arange(0,24).view(2,3,4)
print(x)
print(x[:, 0:3:2, ])  # 获取的是第二维上索引为0,2的数据

out:

例子2:不含有步长的切片,同时使用两种方式联合的索引

x = torch.arange(0,24).view(2,3,4)
print(x)
print(x[0][0:2])  # 获取的是第一维下的0索引后第二维下索引为0,1的全部数据 等价与x[0, 0:2]


例子3:含有负索引的切片

x = torch.arange(0,24).view(2,3,4)
print(x)
print(x[0, 0:2, 0:-1:2])  # 重点可以看一下第三维

例子4:前面维度我都要,针对最后维度的数据进行切片

x = torch.arange(0,2*3*4*5).view(2,3,4,5)
print(x)
print(x[...,0:2, 0:5:2])


例子5:布尔索引

x = torch.arange(0, 9).view(3, 3)
# x4 = torch.ones(3,3)*4
print(x)  # 0-8的二维张量
index = x > 4  # 判断位置对应位置上是否大于数据4, 类似于对4进行广播成和x相同维度的数据,然后逐元素比大小
# index4 = x >x4
# print(index4)
print(index)
print(x[index])  # 针对位置值为True的数据进行获取, 获取后的数据组成一维数据

print("**************")
y = torch.randint(0,9,(3, 3))
dex = y > 4
print(y)
print(y[dex])

例子6:整数索引

x = torch.arange(0, 9).view(3, 3)
print(x)
rows = [0,1]
cols = [1,2]
print(x[rows, cols])  # 获取的数据是(0,1)和(1,2)位置上的数据组成的一维张量


例子7: torch.nonzero()
这个在单目标分割中,计算评价指标和部分损失函数时会遇到

x = torch.randint(0,2,(1,2,3,4))
print(x)
index = torch.nonzero(x) # 得到x中非0数据的位置信息,同时将每个位置组成一个一维数据,一共是二维张量
print(index)  
print(len(index), index.shape)


例子8: torch.where(condition, x, y) 使用

x = torch.randn(4,3)
y = torch.ones(4,3)
m = torch.where(x>0, x, y)  # 这里的condition可以不用x,只需要和x,y相同维度的数据就可以了,功能类似于将布尔索引的高级使用
print(x)
print(y)
print(m)

print("使用布尔索引完成上述例子")
index = x > 0  # condition
print(index)  # 得到位置信息
for i in range(len(x)):
    for j in range(len(x[i])):
        if index[i, j]:
            m[i, j] = x[i, j]
        else:
            m[i, j] = y[i, j]
print(m)

2 Tensor的转换

汇总:

NameOut
a.nelement()返回元素个数
a.ndimension()返回张量轴的个数
a.size()返回张量维度信息
a.shape返回张量维度信息
a.viw(i, j, …)对a进行数据维度变换,修改返回值,原始值也改变 ,实际中这个用的多
a.reshape(i, j, k)对a进行数据维度变换,修改返回值,原始值不一定改变
以上两个中的参数允许存在最多一个 -1用来通过已确定的维度,计算-1位置上的维度,见例2
torch.squeeze(a)去掉a中维度为1的轴, 不指定就去掉所有,指定就去掉指定位置的,见例3
torch.unsqueeze(b, i)在b中i的位置田间一个维度为1的轴,见例4
torch.transpose(b, 1, 0)将b的维度调换位置,类似于二维矩阵的转置操作,见例5
torch.t(b)是transpose的简化书写
a.permute(i, j, k,…)将a中数据的位置按照i,j,k的位置进行重现调整,类似于高维矩阵的转置操作,见例6

a为高维张量, b是二维张量
例子1:

a = torch.rand(3,4,5,6,7)
print("元素个数:", a.nelement())
print("轴的个数:", a.ndimension())
print("维度信息:", a.size())
print("维度信息:", a.shape)

out:
元素个数: 2520
轴的个数: 5
维度信息: torch.Size([3, 4, 5, 6, 7])
维度信息: torch.Size([3, 4, 5, 6, 7])

例子2:使用-1进行维度推算

a = torch.randint(0,3,(3, 4))
print(a, a.shape)
b = a.view(-1,2)
print(b, b.shape)

out:
tensor([[0, 2, 0, 1],
        [2, 2, 0, 0],
        [1, 0, 0, 0]]) torch.Size([3, 4])
tensor([[0, 2],
        [0, 1],
        [2, 2],
        [0, 0],
        [1, 0],
        [0, 0]]) torch.Size([6, 2])

例3:去掉张量中维度为1的轴

x = torch.randint(0,2, (1,1,1,2,4,1,1))
print(x.shape)
print(torch.squeeze(x, 2).shape)
print(torch.squeeze(x).shape)

out:
torch.Size([1, 1, 1, 2, 4, 1, 1])
torch.Size([1, 1, 2, 4, 1, 1])
torch.Size([2, 4])

例4: 给张量指定位置添加一个维度为1的轴

x = torch.randint(0,2,(3, 4))
print(x.shape)
print(torch.unsqueeze(x, 1).shape)

out:
torch.Size([3, 4])
torch.Size([3, 1, 4])

例5: 二维张量的转置操作

x = torch.arange(0,12).view(2,6)
print(x)
print("view操作,将数据重新写一下:\n",x.view(6, 2))  #注意二维张量的转置和View的区别
print("转置操作,将数据按照原来维度进行调换:\n",torch.transpose(x, 1, 0))  #注意二维张量的转置和View的区别
print("转置操作,将数据按照原来维度进行调换:\n",torch.t(x))  # torch.t是简化书写

out:
tensor([[ 0,  1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10, 11]])
view操作,将数据重新写一下:
 tensor([[ 0,  1],
        [ 2,  3],
        [ 4,  5],
        [ 6,  7],
        [ 8,  9],
        [10, 11]])
转置操作,将数据按照原来维度进行调换:
 tensor([[ 0,  6],
        [ 1,  7],
        [ 2,  8],
        [ 3,  9],
        [ 4, 10],
        [ 5, 11]])
转置操作,将数据按照原来维度进行调换:
 tensor([[ 0,  6],
        [ 1,  7],
        [ 2,  8],
        [ 3,  9],
        [ 4, 10],
        [ 5, 11]])

例6:高维数据的转置

x = torch.randn(3,4,2,5)
print(x.shape)
y = x.permute(1,0,2,3)  # 一定要注意区分view和转置的区别
print(y.shape)

out:
torch.Size([3, 4, 2, 5])
torch.Size([4, 3, 2, 5])

3 Tensor的拼接

汇总:

NameOut
torch.cat((a, b) , dim=)已有的轴上拼接矩阵,默认轴为0,给定轴的维度可以不同,其余轴的维度必须相同
torch.stack((a, b) , dim=)新的轴上拼接,默认轴为0,要求被拼接的轴的维度都相同

a, b 的轴最多只有一个可以不同

例子:torch.cat

import torch
a = torch.arange(0,6).view(2,3)
b = torch.ones(2,4)
print(a)
print(b)
# torch.cat
c = torch.cat([a,b],dim=1)
print("a和b在指定的轴上拼接\n", c)
d = torch.cat((a, a))
print("a和a在默认的轴上拼接\n", d)

out:
tensor([[0, 1, 2],
        [3, 4, 5]])
tensor([[1., 1., 1., 1.],
        [1., 1., 1., 1.]])
a和b在指定的轴上拼接
 tensor([[0., 1., 2., 1., 1., 1., 1.],
        [3., 4., 5., 1., 1., 1., 1.]])
a和a在默认的轴上拼接
 tensor([[0, 1, 2],
        [3, 4, 5],
        [0, 1, 2],
        [3, 4, 5]])

例子:torch.stack()
这个用法还是很抽象的,建议从结果倒退结果,最直观的是最后两个维度的呈现:

import torch
a = torch.arange(0,6).view(2,3)
b = torch.ones(2,3)
print(a, a.shape)
print(b, b.shape)
# torch.cat
c = torch.stack([a,b],dim=2)
print("a和b在指定的轴上拼接\n", c, c.shape)
d = torch.stack((a, a))
print("a和a在默认的轴上拼接\n", d, d.shape)

out:
tensor([[0, 1, 2],
        [3, 4, 5]]) torch.Size([2, 3])
tensor([[1., 1., 1.],
        [1., 1., 1.]]) torch.Size([2, 3])
a和b在指定的轴上拼接
 tensor([[[0., 1.],
         [1., 1.],
         [2., 1.]],

        [[3., 1.],
         [4., 1.],
         [5., 1.]]]) torch.Size([2, 3, 2])
a和a在默认的轴上拼接
 tensor([[[0, 1, 2],
         [3, 4, 5]],

        [[0, 1, 2],
         [3, 4, 5]]]) torch.Size([2, 2, 3])

4 Tensor的拆分

汇总:

NameOut
torch.split(a, list, dim=)传入的是拆分后维度的大小,可以传入list,也可以传入整数,不够的放最后
torch.chunk(a, x, dim=)传入的是拆分的矩阵个数

a 是高维张量,list为列表,x为整数
例子:torch.split()

import torch

a = torch.randn(10, 3)
print("传入的是维度大小列表:")
for x in torch.split(a, [1, 2, 3, 4], dim=0):
    print(x.shape)

print("传入的是维度大小整数:")
for x in torch.split(a, 4, dim=0):   # 注意返回值是由tensor组成的元组
    print(x.shape)

out:
传入的是维度大小列表:
torch.Size([1, 3])
torch.Size([2, 3])
torch.Size([3, 3])
torch.Size([4, 3])
传入的是维度大小整数:
torch.Size([4, 3])
torch.Size([4, 3])
torch.Size([2, 3])

例子:torch.chunk()

import torch

a = torch.randn(15, 6)

print("传入的是拆分后的个数:")
for x in torch.chunk(a, 3, dim=1):  
    print(x.shape)

out:
传入的是拆分的个数:
torch.Size([15, 2])
torch.Size([15, 2])
torch.Size([15, 2])

5 Tensor的规约操作

汇总:

NameOut
torch.max(a, dim=)计算a中指定轴的最大值,默认是求最大值(不返回地址)指定轴返回(最大值,最大值位置)
torch.cumsum(a, dim=)沿着指定轴计算累加
torch.cumprod(a, dim=)沿着指定轴计算累乘
a.mean()求均值
a.median求中值
a.std()求协方差
a.max()求最大值
torch.unique(a)寻找张量a中出现了哪些元素

a为高维张量
例子1:torch.max()

a = torch.tensor([[3,1],[4,7]])
print(a)
print(torch.max(a))  # 全局最大值
print(torch.max(a, dim=1))   # 在第二维度上找最大值,同时返回其位置(除指定轴外的位置,例返回【0,1】和指定轴1组成了位置信息,[0,1]和[1,1])

out:
tensor([[3, 1],
        [4, 7]])
tensor(7)
torch.return_types.max(
values=tensor([3, 7]),
indices=tensor([0, 1]))

例子2:torch.cumsum()

a = torch.tensor([[3,1,3],[4,7,4],[4,5,2]])
print(a)
print(torch.cumsum(a, dim=1))  # 按照横轴计算每一列的累加,然后放在对应的位置上


例子3: torch.cumprod()

a = torch.tensor([[3,1,3],[4,7,4],[4,5,2]])
print(a)
print(torch.cumprod(a, dim=0))  # 按照列轴计算每一行的累乘,然后放在对应的位置上


例子4:a.mean(), a.std()等

a = torch.tensor([[3,1,3],[4,7,4],[4,5,2]], dtype=torch.float)
print(a)
print("未指定轴,则计算全局的相关信息:")
print(a.max(), a.std(), a.median(), a.mean())
print("输出指定轴下的信息:")
print("Max_out:", a.max(dim=1),"\n ***")  # 返回最大值 及 位置
print("Str_out:", a.std(dim=1),"\n ***")   # 返回协方差信息
print("Median_out:", a.median(dim=1),"\n ***")  # 返回中间值 及 位置
print("Mean_out:", a.mean(dim=1),"\n ***")  # 返回均值


例子5:torch.unique()

x = torch.randint(0,15,(3,3))
print(x)
print(torch.unique(x)) # 得到x中出现的元素

out:
tensor([[14,  3,  4],
        [ 2,  3,  7],
        [12,  0,  6]])
tensor([ 0,  2,  3,  4,  6,  7, 12, 14])

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2023年11月29日
下一篇 2023年11月29日

相关推荐