PyTorch:tensor-张量维度操作(拼接、维度扩展、压缩、转置、重复……) 小灰灰 2022-12-13 04:22 654阅读 0赞 张量维度操作(拼接、维度扩展、压缩、转置、重复……) note: torch.fun(tensor1)和tensor1.fun()都只会返回改变后的tensor,但是tensor本身的维度和数据都不会变。包括unsqueeze、expand等等。 [\-柚子皮-][-_-] ### torch.cat多个tensor直接拼接 ### torch.cat(seq, dim=0, out=None) 在指定的维度dim上对序列seq进行连接操作。 参数: seq (sequence of Tensors) - Python序列或相同类型的张量序列 dim (int, optional) - 沿着此维度连接张量 out (Tensor, optional) - 输出参数 例子: x = torch.randn(2, 3) x \-0.5866 -0.3784 -0.1705 \-1.0125 0.7406 -1.2073 \[torch.FloatTensor of size 2x3\] torch.cat((x, x), 0) \-0.5866 -0.3784 -0.1705 \-1.0125 0.7406 -1.2073 \-0.5866 -0.3784 -0.1705 \-1.0125 0.7406 -1.2073 \[torch.FloatTensor of size 4x3\] torch.cat((x, x), 1) \-0.5866 -0.3784 -0.1705 -0.5866 -0.3784 -0.1705 \-1.0125 0.7406 -1.2073 -1.0125 0.7406 -1.2073 \[torch.FloatTensor of size 2x6\] ### torch.stack扩张再拼接 ### torch.[stack][](tensors, dim=0, \*, out=None) x = torch.randn(3, 4) torch.stack((x, x), 0).size() \# torch.Size(\[2, 3, 4\]) torch.stack((x, x), 1).size() \#torch.Size(\[3, 2, 4\]) ### torch.squeeze(input, dim=None, out=None) 压缩张量 ### 参数: input (Tensor) – 输入张量 dim (int, optional) – 如果给定,则只会在给定维度压缩 out (Tensor, optional) – 输出张量 除去输入张量input中数值为1的维度,并返回新的张量。如果输入张量的形状为(A\*1\*B\*C\*1\*D),那么输出张量的形状为( A\*B\*C\*D)。 当通过dim参数指定维度时,维度压缩操作只会在指定的维度上进行。如果输入向量的形状为(A\*1\*B),squeeze(input, 0)会保持张量的维度不变,只有在执行squeeze(input, 1)时,输入张量的形状会被压缩至( A\*B )。 如果一个张量只有1个维度,那么它不会受到上述方法的影响。 squeeze有个缺陷,即size所有维度都是1时,squeeze后维度全没了,所以当知道需要对某个维度进行squeeze时,尽量指定dim。 a = torch.tensor(\[\[0.4965\]\]) a.size() \#torch.Size(\[1, 1\]) a.squeeze().size() \#torch.Size(\[\]) 输出的张量与原张量**共享内存**,如果改变其中的一个,另一个也会改变。 为何只去掉 1 呢?多维张量本质上就是一个变换,如果维度是 1 ,那么,1 仅仅起到扩充维度的作用,而没有其他用途,因而,在进行降维操作时,为了加快计算,是可以去掉这些 1 的维度。 例子: x = torch.zeros(2, 1, 2, 1, 2) x.size() torch.Size(\[2, 1, 2, 1, 2\]) y = torch.squeeze(x) y.size() torch.Size(\[2, 2, 2\]) y = torch.squeeze(x, 0) y.size() torch.Size(\[2, 1, 2, 1, 2\]) y = torch.squeeze(x, 1) y.size() torch.Size(\[2, 2, 1, 2\]) ### torch.unsqueeze(input, dim, out=None)/tensor.unsqueeze扩展张量维度 ### 返回一个新的张量,对输入的既定位置插入维度 1。注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。 如果dim为负,则将会被转化dim+input.dim()+1。 **参数** tensor (Tensor) – 输入张量 dim (int) – 插入维度的索引 out (Tensor, optional) – 结果张量 Note: tensor1.unsqueeze(1)可以使用tensor1\[:, None, :, :, :\]来等价代替,这时tensor1的维度从\[a,b,c,d\]变成\[a,1,b,c,d\]。同理,tensor1.unsqueeze(0).unsqueeze(3)通过x\[None, :, :, None, :\]等价代替,维度从\[a,b,c\]变成\[1,a,b,1,c\]。 **tensor.unsqueeze\_和tensor.unsqueeze/torch.unsqueeze 的区别** torch.unsqueeze\_(tensor1,1)相当于tensor1.unsqueeze(1)。 区别在于 tensor1.unsqueeze\_ 是 in\_place 操作,即unsqueeze\_ 则会对自己改变。torch.unsqueeze 不会对使用 unsqueeze 的 tensor 进行改变,想要获取 unsqueeze 后的值必须赋予个新值。 **示例:** x = torch.Tensor(\[1, 2, 3, 4\]) \# torch.Tensor是默认的tensor类型(torch.FlaotTensor)的简称。 print(x.size()) \# torch.Size(\[4\]) print(torch.unsqueeze(x, 0)) \# tensor(\[\[1., 2., 3., 4.\]\]) print(torch.unsqueeze(x, 0).size()) \# torch.Size(\[1, 4\]) print(torch.unsqueeze(x, 1)) \# tensor(\[\[1.\], \# \[2.\], \# \[3.\], \# \[4.\]\]) print(torch.unsqueeze(x, 1).size()) \# torch.Size(\[4, 1\]) print(torch.unsqueeze(x, -1)) \# tensor(\[\[1.\], \# \[2.\], \# \[3.\], \# \[4.\]\]) print(torch.unsqueeze(x, -1).size()) \# torch.Size(\[4, 1\]) print(torch.unsqueeze(x, -2)) \# tensor(\[\[1., 2., 3., 4.\]\]) print(torch.unsqueeze(x, -2).size()) \# torch.Size(\[1, 4\]) \[[torch.unsqueeze() 和 torch.squeeze()][torch.unsqueeze_ _ torch.squeeze]\] ### torch.Tensor.expand(\*sizes)扩大张量 ### 返回张量的一个**新视图**,可以将张量的单个维度扩大为更大的尺寸。 张量也可以扩大为更高维,新增加的维度将附在前面。 扩大张量不需要分配新内存,仅仅是新建一个张量的视图。任意一个一维张量在不分配新内存情况下都可以扩展为任意的维度。 传入-1则意味着维度扩大不涉及这个维度。 参数:sizes (torch.Size or int...) – 想要扩展的目标维度 示例1: a = torch.tensor(\[\[1, 2\], \[3, 4\], \[5, 6\]\]) a1 = (a \*\* 2).sum(1).expand(3, 4) \# 因为新增加的维度将附在前面,所以size=(3)时,不能直接expand为(3,4) a1 = torch.sum((a \*\* 2), 1, keepdim=True).expand(3, 4) \# size=(3,1)可以expand为(3,4) 示例2: x = torch.Tensor(\[\[1\], \[2\], \[3\]\]) x.size() torch.Size(\[3, 1\]) x.expand(3, 4) 1 1 1 1 2 2 2 2 3 3 3 3 \[torch.FloatTensor of size 3x4\] ### Flatten张量 ### >>> t = torch.tensor(\[\[\[1, 2\], \[3, 4\]\], \[\[5, 6\], \[7, 8\]\]\]) >>> torch.flatten(t) tensor(\[1, 2, 3, 4, 5, 6, 7, 8\]) >>> torch.flatten(t, start\_dim=1) tensor(\[\[1, 2, 3, 4\], \[5, 6, 7, 8\]\]) \[torch.[flatten][](input, start\_dim=0, end\_dim=-1) \] [\-柚子皮-][-_-] ### torch.Tensor.repeat(\*sizes)重复张量 ### 沿着指定的维度重复张量。不同于expand()方法,本函数**复制**的是张量中的数据。 参数:size (torch.size ot int...) - 沿着每一维重复的次数 例子: x = torch.Tensor(\[1, 2, 3\]) x.repeat(3, 2) 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 \[torch.FloatTensor of size 3x6\] ### torch.Tensor.unfold(dim, size, step) ### 返回一个新的张量,其中元素复制于有原张量在dim维度上的数据,复制重复size次,复制时的步进值为step。 参数: dim (int) - 目标维度 size (int) - 复制重复的次数(展开维度) step (int) - 步长 例子: x = torch.arange(1, 8) x 1 2 3 4 5 6 7 \[torch.FloatTensor of size 7\] x.unfold(0, 2, 1) 1 2 2 3 3 4 4 5 5 6 6 7 \[torch.FloatTensor of size 6x2\] x.unfold(0, 2, 2) 1 2 3 4 5 6 \[torch.FloatTensor of size 3x2\] ### torch.Tensor.narrow(dimension, start, length)缩小张量 ### 返回一个经过缩小后的张量。操作的维度由dimension指定。缩小范围是从start开始到start+length。执行本方法的张量与返回的张量共享相同的底层内存。 参数: dimension (int) – 要进行缩小的维度 start (int) – 开始维度索引 length (int) – 缩小持续的长度 例子: x = torch.Tensor(\[\[1, 2, 3\], \[4, 5, 6\], \[7, 8, 9\]\]) x.narrow(0, 0, 2) 1 2 3 4 5 6 \[torch.FloatTensor of size 2x3\] x.narrow(1, 1, 2) 2 3 5 6 8 9 \[torch.FloatTensor of size 3x2\] ### torch.gather(input, dim, index, out=None) ### 沿给定轴dim,将输入索引张量index指定位置的值进行聚合。index的类型必须是LongTensor类型的。index的大小就是输出的大小。 对一个3维张量,输出可以定义为: out\[i\]\[j\]\[k\] = tensor\[index\[i\]\[j\]\[k\]\]\[j\]\[k\] \# dim=0 out\[i\]\[j\]\[k\] = tensor\[i\]\[index\[i\]\[j\]\[k\]\]\[k\] \# dim=1 out\[i\]\[j\]\[k\] = tensor\[i\]\[j\]\[index\[i\]\[j\]\[k\]\] \# dim=3 gather中index实际上是索引,具体是行还是列的索引要看dim。 比如对于\[\[1,2,3\],\[4,5,6\]\],指定dim=1,也就是横向,索引就是列号。index是\[\[0,1\],\[2,0\]\],那么看index第一行,列0指的是1, 列1指的是2,同理,第二行为6,4,这样就输出为\[\[1,2\], \[6,4\]。 b = torch.Tensor(\[\[1,2,3\],\[4,5,6\]\]) print b index\_1 = torch.LongTensor(\[\[0,1\],\[2,0\]\]) index\_2 = torch.LongTensor(\[\[0,1,1\],\[0,0,0\]\]) print torch.gather(b, dim=1, index=index\_1) print torch.gather(b, dim=0, index=index\_2) 1 2 3 4 5 6 \[torch.FloatTensor of size 2x3\] 1 2 6 4 \[torch.FloatTensor of size 2x2\] 1 5 6 1 2 3 \[torch.FloatTensor of size 2x3\] gather在one-hot为输出的多分类问题中,可以把最大值坐标作为index传进去,然后提取到每一行的正确预测结果,这也是gather可能的一个作用: def cross\_entropy(logits, target): batch\_size = logits.size(0) log\_probs\_flat = functional.log\_softmax(logits) losses\_flat = -torch.gather(log\_probs\_flat, dim=1, index=target) loss = losses\_flat.sum() / batch\_size return loss \[[Pytorch中的torch.gather函数的含义][Pytorch_torch.gather]\]\[[pytorch之torch.gather方法][pytorch_torch.gather]\] ### torch.Tensor.view(\*args) 张量变形 ### 返回一个有相同数据但是不同形状的新的向量。 返回的装两必须与原张量有相同的数据和相同的元素个数,但是可以有不同的尺寸。 参数: args (torch.Size or int....) - 理想的指定尺寸 示例1: x = torch.randn(4, 4) x.size() torch.Size(\[4, 4\]) y = x.view(16) y.size() torch.Size(\[16\]) 示例2: embs = torch.Tensor(\[\[\[1, 2\], \[1, 2\]\], \[\[3, 4\], \[3, 4\]\], \[\[5, 6\], \[5, 6\]\]\]) print(embs.size()) embs = embs.view(embs.size(0), embs.size(1) \* embs.size(2)) print(embs.size()) torch.Size(\[3, 2, 2\]) torch.Size(\[3, 4\]) view和下面的resize最大的区别是,resize的张量不能是grad的:RuntimeError: cannot resize variables that require grad ### torch.Tensor.resize\_(\*sizes)重设张量尺寸 ### 将张量的尺寸调整为指定的大小。如果元素个数比当前的内存大小大,就将底层存储大小调整为与新元素数目一致的大小。 如果元素个数比当前内存小,则底层存储不会被改变。原来张量中被保存下来的元素将保持不变,但新内存将不会被初始化。 参数: sizes (torch.Size or int....) - 需要调整的大小 例子: x = torch.Tensor(\[\[1, 2\], \[3, 4\], \[5, 6\]\]) x.resize\_(2, 2) x 1 2 3 4 \[torch.FloatTensor of size 2x2\] ### 交换张量的维度 ### ### 二维张量交换torch.t(x)/tensor.t()/tensor.T ### Expects input to be <= 2-D tensor and transposes dimensions 0 and 1. \[[torch.t(input)][torch.t_input] → Tensor\] torch.Tensor.t (Python method, in torch.Tensor) torch.Tensor.T (Python attribute, in torch.Tensor) ### 交换多维张量的两个维度torch.transpose()/tensor.transpose(dim0, dim1) ### torch.transpose(input, dim0, dim1) → Tensor 输出和输入是共享内存的。 transpose中的两个维度参数的顺序是可以交换位置的,即transpose(x, 0, 1,) 和transpose(x, 1, 0)效果是相同的。 >>> x = torch.randn(2, 3) >>> x tensor(\[\[ 1.0028, -0.9893, 0.5809\], \[-0.1669, 0.7299, 0.4942\]\]) >>> torch.transpose(x, 0, 1) tensor(\[\[ 1.0028, -0.1669\], \[-0.9893, 0.7299\], \[ 0.5809, 0.4942\]\]) ### torch.Tensor.permute(\*dims)置换张量维度 ### 将执行本方法的张量的维度换位。 参数:dim (int) - 指定换位顺序 **例子:** x = torch.randn(2, 3, 5) x.size() torch.Size(\[2, 3, 5\]) x.permute(2, 0, 1).size() torch.Size(\[5, 2, 3\]) from: [\-柚子皮-][-_-] ref: \[[张量维度操作(拼接、维度扩展、压缩、转置、重复……)][Link 1]\] [-_-]: https://me.csdn.net/pipisorry [stack]: https://pytorch.org/docs/stable/generated/torch.stack.html [torch.unsqueeze_ _ torch.squeeze]: https://zhuanlan.zhihu.com/p/86763381 [flatten]: https://pytorch.org/docs/stable/generated/torch.flatten.html [Pytorch_torch.gather]: https://blog.csdn.net/edogawachia/article/details/80515038 [pytorch_torch.gather]: https://blog.csdn.net/Lucky_Rocks/article/details/79676095 [torch.t_input]: https://pytorch.org/docs/stable/generated/torch.t.html [Link 1]: https://zhuanlan.zhihu.com/p/31495102
还没有评论,来说两句吧...