[PyTorch中文文档]-Package参考-torch-索引,切片,连接,换位Indexing, Slicing, Joining, Mutating Ops torch.cat

torch.cat(inputs, dimension=0) → Tensor

在给定维度上对输入的张量序列seq 进行连接操作。
torch.cat()可以看做 torch.split() 和 torch.chunk()的反操作。 cat() 函数可以通过下面例子更好的理解。
参数:
inputs (sequence of Tensors) – 可以是任意相同Tensor 类型的python 序列
dimension (int, optional) – 沿着此维连接张量序列。
例子:

>>> x = torch.randn(2, 3)
>>> x

 0.5983 -0.0341  2.4918
 1.5981 -0.5265 -0.8735
[torch.FloatTensor of size 2x3]

>>> torch.cat((x, x, x), 0)

 0.5983 -0.0341  2.4918
 1.5981 -0.5265 -0.8735
 0.5983 -0.0341  2.4918
 1.5981 -0.5265 -0.8735
 0.5983 -0.0341  2.4918
 1.5981 -0.5265 -0.8735
[torch.FloatTensor of size 6x3]

>>> torch.cat((x, x, x), 1)
 0.5983 -0.0341  2.4918  0.5983 -0.0341  2.4918  0.5983 -0.0341  2.4918
 1.5981 -0.5265 -0.8735  1.5981 -0.5265 -0.8735  1.5981 -0.5265 -0.8735
[torch.FloatTensor of size 2x9]

torch.chunk(tensor, chunks, dim=0)

torch.chunk(tensor, chunk_num, dim)与torch.cat()原理相反,它是将tensor按dim(行或列)分割成chunk_num个tensor块,返回的是一个元组。

a = torch.Tensor([[1,2,4]])
b = torch.Tensor([[4,5,7], [3,9,8], [9,6,7]])
c = torch.cat((a,b), dim=0)
print(c)
print(c.size())
print('********************')
d = torch.chunk(c,4,dim=0)
print(d)
print(len(d))

torch.gather(input, dim, index, out=None) → Tensor

作用:收集输入的特定维度指定位置的数值
参数:
input(tensor): 待操作数。不妨设其维度为(x1, x2, …, xn)
dim(int): 待操作的维度。
index(LongTensor): 如何对input进行操作。其维度有限定,例如当dim=i时,index的维度为(x1, x2, …y, …,xn),既是将input的第i维的大小更改为y,且要满足y>=1(除了第i维之外的其他维度,大小要和input保持一致)。
out: 注意输出和index的维度是一致的

import torch
a = torch.tensor([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15] ])
index = torch.tensor([[0, 2],[3, 4], [1, 4]])
print(torch.gather(a, 1, index))
#tensor([[ 1,  3],
#                [ 9, 10],
#                [12, 15]])

torch.index_select(input, dim, index, out=None) → Tensor

沿着指定维度对输入进行切片,取index中指定的相应项(index为一个LongTensor),然后返回到一个新的张量, 返回的张量与原始张量Tensor有相同的维度(在指定轴上)。

注意: 返回的张量不与原始张量共享内存空间。
参数:
input (Tensor) – 输入张量
dim (int) – 索引的轴
index (LongTensor) – 包含索引下标的一维张量
out (Tensor, optional) – 目标张量

>>> x = torch.randn(3, 4)
>>> x

 1.2045  2.4084  0.4001  1.1372
 0.5596  1.5677  0.6219 -0.7954
 1.3635 -1.2313 -0.5414 -1.8478
[torch.FloatTensor of size 3x4]

>>> indices = torch.LongTensor([0, 2])
>>> torch.index_select(x, 0, indices)

 1.2045  2.4084  0.4001  1.1372
 1.3635 -1.2313 -0.5414 -1.8478
[torch.FloatTensor of size 2x4]

>>> torch.index_select(x, 1, indices)

 1.2045  0.4001
 0.5596  0.6219
 1.3635 -0.5414
[torch.FloatTensor of size 3x2]

torch.masked_select(input, mask, out=None) → Tensor

根据掩码张量mask中的二元值,取输入张量中的指定项( mask为一个 ByteTensor),将取值返回到一个新的1D张量,
张量 mask须跟input张量有相同数量的元素数目,但形状或维度不需要相同。 注意: 返回的张量不与原始张量共享内存空间。
参数:
input (Tensor) – 输入张量
mask (ByteTensor) – 掩码张量,包含了二元索引值
out (Tensor, optional) – 目标张量

>>> x = torch.randn(3, 4)
>>> x
tensor([[ 0.3552, -2.3825, -0.8297,  0.3477],
        [-1.2035,  1.2252,  0.5002,  0.6248],
        [ 0.1307, -2.0608,  0.1244,  2.0139]])
>>> mask = x.ge(0.5)
>>> mask
tensor([[False, False, False, False],
        [False, True, True, True],
        [False, False, False, True]])
>>> torch.masked_select(x, mask)
tensor([ 1.2252,  0.5002,  0.6248,  2.0139])

使用方法其实挺明显的,就是把input与mask相对应起来,取出mask中True所对应位置的数据,组成一维的tensor。
注意:mask和input的形状可以不相同,但是它们必须是可以广播的。并且返回tensor和原tensor使用不同的内存,相互独立。

torch.nonzero(input, out=None) → LongTensor

找出tensor中非零的元素的索引。返回一个包含输入 input 中非零元素索引的张量.输出张量中的每行包含 input 中非零元素的索引。
torch.nonzero(input, *, out=None, as_tuple=False)


image.png
import torch
 
label = torch.tensor([[1,0,0],
                      [1,0,1]])
print(label.nonzero())
 
输出:
tensor([[0, 0],
        [1, 0],
        [1, 2]])

有时我们只想得到一种元素对应的索引,比如我们只想要1对应的索引:

import torch
 
label = torch.tensor([[1,0,0],
                      [3,0,1]])
print((label==1).nonzero())
 
输出:
tensor([[0, 0],
        [1, 2]])

或者,我们想要一定条件下的元素的索引,比如大于1的元素的索引:

import torch
 
label = torch.tensor([[1,0,0],
                      [3,0,1]])
print((label>1).nonzero())
 
输出:
tensor([[1, 0]])

torch.split(tensor, split_size, dim=0)

将输入张量分割成相等形状的chunks(如果可分)。 如果沿指定维的张量形状大小不能被split_size 整分, 则最后一个分块会小于其它分块。
参数:
tensor (Tensor) – 待分割张量
split_size (int) – 单个分块的形状大小
dim (int) – 沿着此维进行分割

split_size_or_sections为int型时

import torch
 
x = torch.rand(4,8,6)
y = torch.split(x,2,dim=0) #按照4这个维度去分,每大块包含2个小块
for i in y :
    print(i.size())
 
output:
torch.Size([2, 8, 6])
torch.Size([2, 8, 6])
 
y = torch.split(x,3,dim=0)#按照4这个维度去分,每大块包含3个小块
for i in y:
    print(i.size())
 
output:
torch.Size([3, 8, 6])
torch.Size([1, 8, 6])

split_size_or_sections为list型时。

import torch
 
x = torch.rand(4,8,6)
y = torch.split(x,[2,3,3],dim=1)
for i in y:
    print(i.size())
 
output:
torch.Size([4, 2, 6])
torch.Size([4, 3, 6])
torch.Size([4, 3, 6])
 
 
y = torch.split(x,[2,1,3],dim=1) #2+1+3 等于7,报错
for i in y:
    print(i.size())
 
output:
split_with_sizes expects split_sizes to sum exactly to 8 (input tensor's size at dimension 1), but got split_sizes=[2, 1, 3]

torch.squeeze(input, dim=None, out=None)

核心功能:
这个函数主要对数据的维度进行压缩,去掉维数为1的的维度。比如:是一行或者一列这种,一个一行三列(1,3)的数去掉第一个维数为一的维度之后就变成(3)行。b=torch.squeeze(a,N) 就是将a中所有为1的维度删掉,不为1的维度没有影响。

参数说明:
input (Tensor): 输入张量(the input tensor.)
dim (int, optional): 将输入Tensor的第dim个维度位置进行压缩,如果输入Tensor此处维度为1则压缩成功,否则失败。如果该参数给定,则输入张量将仅在该维度上压缩(if given, the input will be squeezed only in this dimension.),如果该参数不给定,则默认将输入Tensor所有维度为1的进行压缩。参数dim的取值范围为:[-input.dim(), input.dim()-1] 。

x = torch.zeros(2, 1, 2, 1, 2)
x
>>>
tensor([[[[[0., 0.]],

          [[0., 0.]]]],



        [[[[0., 0.]],

          [[0., 0.]]]]])
print(x.size())
>>> torch.Size([2, 1, 2, 1, 2])
y = torch.squeeze(x)
y
>>>
tensor([[[0., 0.],
         [0., 0.]],

        [[0., 0.],
         [0., 0.]]])
print(y.size())
>>> torch.Size([2, 2, 2])

# 如果第一个维度为一,则将其进行压缩;否则,不能压缩
y = torch.squeeze(x, 0)  # 或者 y = torch.squeeze(x, dim=0)
print(y.size())
>>> torch.Size([2, 1, 2, 1, 2])

# 如果第二个维度为一,则将其进行压缩
y = torch.squeeze(x, 1)  # 或者 y = torch.squeeze(x, dim=1)
print(y.size())
>>> torch.Size([2, 2, 1, 2])

# 如果第三个维度为一,则将其进行压缩;否则,不能压缩
y = torch.squeeze(x, 2)  # 或者 y = torch.squeeze(x, dim=2)
print(y.size())
>>> torch.Size([2, 1, 2, 1, 2])

# 如果第四个维度为一,则将其进行压缩
y = torch.squeeze(x, dim=3)   # 或者 y = torch.squeeze(x, dim=3)
print(y.size())
torch.Size([2, 1, 2, 2])

# 如果第五个维度为一,则将其进行压缩
y = torch.squeeze(x, dim=4)   # 或者 y = torch.squeeze(x, dim=4)
print(y.size())
torch.Size([2, 1, 2, 1, 2])

torch.unsqueeze(input, dim)

核心功能:
在tensor的某个维度上添加一个维数为1的维度,这个功能用view()函数也可以实现。比如:原本有个三行的数据(3),在0的位置加了一维就变成一行三列(1,3)。a.unsqueeze(N) 就是在a中指定位置N加上一个维数为1的维度。还有一种形式就是b=torch.unsqueeze(a,N) a就是在a中指定位置N加上一个维数为1的维度。这一功能尤其在神经网络输入单个样本时很有用,由于pytorch神经网络要求的输入都是mini-batch型的,维度为[batch_size, channels, w, h],而一个样本的维度为[c, w, h],此时用unsqueeze()增加一个维度变为[1, c, w, h]就很方便了。

参数说明:
input (Tensor):输入张量(the input tensor.)
dim (int):插入维数为一的维度的位置(the index at which to insert the singleton dimension.)参数dim的取值范围为:[-input.dim() - 1, input.dim() + 1)

备注: 以0为分界,正向取值和反向取值的效果相同,其原理类似DataFrame中的正向、反向切片操作。正向取值时,0表示行,1表示列;反向取值时,-1表示列,-2表示行。
\quad
例如:若input。dim()==1,此时,dim的取值范围为[-2,2),正向取值时——dim=0(表示:行维度为1,即:新生成Tensor的shape为 torch.Size([1, 100]) );dim=1(表示:列维度为1,即:新生成Tensor的shape为 torch.Size([100, 1]) ))。反向取值时——dim=-2(表示:行维度为1,即:新生成Tensor的shape为 torch.Size([1, 100]) );dim=-1(表示:列维度为1,即:新生成Tensor的shape为 torch.Size([100, 1]) )

a = torch.linspace(-1, 1, 100)  # 生成-1到1的100个数构成的等差数列
print(a.shape)
>>> torch.Size([100])

x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1) # dim=1,表示列方向维度为1
print(x.shape)
>>> torch.Size([100, 1])

x = torch.tensor([1, 2, 3, 4])
torch.unsqueeze(x, 0)
>>> tensor([[ 1,  2,  3,  4]])
torch.unsqueeze(x, 1)
>>> tensor([[ 1],
            [ 2],
            [ 3],
            [ 4]])

x = torch.zeros(2, 2, 2)
print(x.shape)
>>> torch.Size([2, 2, 2])
# 在input的第三个维度上扩充维度1
y = torch.unsqueeze(x, dim=2)
print(y.shape)
>>> torch.Size([2, 2, 1, 2])

torch.stack(sequence, dim=0)

torch.stack()函数和torch.cat()有所不同,torch.stack()并不在已有的维度进行拼接,而是沿着新的维度进行拼接。

我在使用torch.stack()产生了两个问题:
1.怎么确定新的维度产生在哪里?
2.指定了新维度后要怎么拼接?

下面我以两个张量来说明,分别是A和B

A = torch.arange(6.0).reshape(2,3)
B = torch.linspace(0,10,6).reshape(2,3)
A= tensor([[0., 1., 2.],
        [3., 4., 5.]])       
B= tensor([[ 0.,  2.,  4.],
        [ 6.,  8., 10.]])       

既然知道函数会为张量产生一个新维度,那么我们可以假设,令A和B维度升级,从(2,3)变为(1,2,3),即:

A1= tensor([[[0., 1., 2.],
        [3., 4., 5.]]])       
B1= tensor([[[ 0.,  2.,  4.],
        [ 6.,  8., 10.]]])       
#A1、B1比A、B在最外层多了一组括号[]

这样,接下里就很好解释了。
参数dim表示相连维度在这3维里的索引,如用link表示连接维度:
dim=0时,(link,#,#)
dim=1时,(#,link,#)
dim=2时,(#,#,link)
link所在的维度是哪个,就把A1和B1对应维度里的元素逐个相连。

下面我对每个维度都演示一遍

dim=0
F1 = torch.stack((A,B),dim=0)
print('F1=',F1)
print('F1的维度是',F1.shape)
F1= tensor([[[ 0.,  1.,  2.],
         [ 3.,  4.,  5.]],
        [[ 0.,  2.,  4.],
         [ 6.,  8., 10.]]])
F1的维度是 torch.Size([2, 2, 3])
用上面的说法来理解,这相当于在A1和B1的第0维度里,每个元素依次相连,每对连接元素用[ ]包装。
A1的第0维度里只有A一个元素
B1的第0维度里只有B一个元素
因此如上所示,F1的结果其实就是[A,B]
dim=1
F2 = torch.stack((A,B),dim=1)
print('F2=',F2)
print('F2的维度是',F2.shape)
F2= tensor([[[ 0.,  1.,  2.],
         [ 0.,  2.,  4.]],
        [[ 3.,  4.,  5.],
         [ 6.,  8., 10.]]])
F2的维度是 torch.Size([2, 2, 3])

沿用上面的理解
A1的第1维度里的两个元素:[0. 1, 2],[3, 4, 5]
B1的第1维度里的两个元素:[0, 2, 4],[6, 8, 10]
[0. 1, 2]和[0, 2, 4]相连,[ ]包起来
[3, 4, 5]和[6, 8, 10]相连,[ ]包起来
最后给以上两组用[ ]包起来

dim=2
F3 = torch.stack((A,B),dim=2)
print('F3=',F3)
print('F3的维度是',F3.shape)
F3= tensor([[[ 0.,  0.],
         [ 1.,  2.],
         [ 2.,  4.]],
        [[ 3.,  6.],
         [ 4.,  8.],
         [ 5., 10.]]])
F3的维度是 torch.Size([2, 3, 2])

A1和B1的第2维度里每个元素依次相连,每对连接元素用[]包装
A1第2维度里的元素:0,1,2,3,4,5
B1第2维度里的元素:0,2,4,6,8,10
两两相连后打包[0,0] [1,2] [2,4] [3,6] [4,8] [5,10]
由于[0,1,2]和[0,2,4]的第1维度属性是0
[3,4,5]和[6,8,10]的第1维度属性是1
所以把第一维度属性是0的和是1的单独打包
即[[0,0],[1,2],[2,4]]和[[3,6],[4,8],[5,10]]
最后将以上两组一起[]包起来

torch.t(input, out=None) → Tensor

输入一个矩阵(2维张量),并转置0, 1维。 可以被视为函数transpose(input, 0, 1)的简写函数。

参数:
input (Tensor) – 输入张量
out (Tensor, optional) – 结果张量

>>> x = torch.randn(2, 3)
>>> x

 0.4834  0.6907  1.3417
-0.1300  0.5295  0.2321
[torch.FloatTensor of size 2x3]

>>> torch.t(x)

 0.4834 -0.1300
 0.6907  0.5295
 1.3417  0.2321
[torch.FloatTensor of size 3x2]

torch.transpose(input, dim0, dim1, out=None) → Tensor

返回输入矩阵input的转置。交换维度dim0和dim1。 输出张量与输入张量共享内存,所以改变其中一个会导致另外一个也被修改。

参数:
input (Tensor) – 输入张量
dim0 (int) – 转置的第一维
dim1 (int) – 转置的第二维

>>> x = torch.randn(2, 3)
>>> x

 0.5983 -0.0341  2.4918
 1.5981 -0.5265 -0.8735
[torch.FloatTensor of size 2x3]

>>> torch.transpose(x, 0, 1)

 0.5983  1.5981
-0.0341 -0.5265
 2.4918 -0.8735
[torch.FloatTensor of size 3x2]

torch.unbind(tensor, dim=0)[source]

移除指定维后,返回一个元组,包含了沿着指定维切片后的各个切片

参数:
tensor (Tensor) – 输入张量
dim (int) – 删除的维度

此方法就是将我们的input从dim进行切片,并返回切片的结果,返回的结果里面没有dim这个维度。
例如维度为0的时候,如下所示:

>>> torch.unbind(torch.tensor([[1, 2, 3],
>>>                            [4, 5, 6],
>>>                            [7, 8, 9]]))
(tensor([1, 2, 3]), tensor([4, 5, 6]), tensor([7, 8, 9]))
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容