detach() 和 .data PyTorch0.4中,.data
仍保留,但建议使用 .detach()
, 区别在于 .data
返回和 x
的相同数据 tensor
, 但不会加入到x
的计算历史里,且require s_grad = False
, 这样有些时候是不安全的, 因为 x.data
不能被 autograd
追踪求微分 。 .detach()
返回相同数据的 tensor
,且 requires_grad=False
,但能通过 in-place
操作报告给 autograd
在进行反向传播的时候. 举例:tensor.data
1 2 3 4 5 6 7 8 9 10 11 12 >>> a = torch.tensor([1,2,3.], requires_grad =True) >>> out = a.sigmoid() >>> c = out.data >>> c.zero_() tensor([ 0., 0., 0.]) >>> out tensor([ 0., 0., 0.]) >>> out.sum().backward() >>> a.grad tensor([ 0., 0., 0.])
tensor.detach()
1 2 3 4 5 6 7 8 9 10 11 12 >>> a = torch.tensor([1,2,3.], requires_grad =True) >>> out = a.sigmoid() >>> c = out.detach() >>> c.zero_() tensor([ 0., 0., 0.]) >>> out tensor([ 0., 0., 0.]) >>> out.sum().backward() RuntimeError: one of the variables needed for gradient computation has been modified by an
torch.cat() 张量拼接 对张量沿着某一维度进行拼接。连接后数据的总维数不变。,ps:能拼接的前提是对应的维度相同!!!
例如对两个2维tensor(分别为2*3
,1*3
)进行拼接,拼接完后变为3*3
的2维 tensor。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 In [1 ]: import torch In [2 ]: torch.manual_seed(1 ) Out[2 ]: <torch._C.Generator at 0x19e56f02e50 > In [3 ]: x = torch.randn(2 ,3 ) In [4 ]: y = torch.randn(1 ,3 ) In [5 ]: x Out[5 ]: tensor([[ 0.6614 , 0.2669 , 0.0617 ], [ 0.6213 , -0.4519 , -0.1661 ]]) In [6 ]: y Out[6 ]: tensor([[-1.5228 , 0.3817 , -1.0276 ]]) In [9 ]: torch.cat((x,y),0 ) Out[9 ]: tensor([[ 0.6614 , 0.2669 , 0.0617 ], [ 0.6213 , -0.4519 , -0.1661 ], [-1.5228 , 0.3817 , -1.0276 ]])
以上dim=0
表示按列进行拼接,dim=1
表示按行进行拼接。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 In [11 ]: z = torch.randn(2 ,2 ) In [12 ]: z Out[12 ]: tensor([[-0.5631 , -0.8923 ], [-0.0583 , -0.1955 ]]) In [13 ]: x Out[13 ]: tensor([[ 0.6614 , 0.2669 , 0.0617 ], [ 0.6213 , -0.4519 , -0.1661 ]]) In [14 ]: torch.cat((x,z),1 ) Out[14 ]: tensor([[ 0.6614 , 0.2669 , 0.0617 , -0.5631 , -0.8923 ], [ 0.6213 , -0.4519 , -0.1661 , -0.0583 , -0.1955 ]])
torch.stack() 张量堆叠 torch.cat()
拼接不会增加新的维度,但torch.stack()
则会增加新的维度。
例如对两个1*2
维的 tensor 在第0个维度上stack,则会变为2*1*2
的 tensor;在第1个维度上stack,则会变为1*2*2
的tensor。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 In [22 ]: x = torch.randn(1 ,2 ) In [23 ]: y = torch.randn(1 ,2 ) In [24 ]: x.shape Out[24 ]: torch.Size([1 , 2 ]) In [25 ]: x = torch.randn(1 ,2 ) In [26 ]: y = torch.randn(1 ,2 ) In [27 ]: torch.stack((x,y),0 ) Out[27 ]: tensor([[[-1.8313 , 1.5987 ]], [[-1.2770 , 0.3255 ]]]) In [28 ]: torch.stack((x,y),0 ).shape Out[28 ]: torch.Size([2 , 1 , 2 ]) In [29 ]: torch.stack((x,y),1 ) Out[29 ]: tensor([[[-1.8313 , 1.5987 ], [-1.2770 , 0.3255 ]]]) In [30 ]: torch.stack((x,y),1 ).shape Out[30 ]: torch.Size([1 , 2 , 2 ])
torch.transpose() 矩阵转置 举例说明
1 2 3 torch.manual_seed(1 ) x = torch.randn(2 ,3 ) print (x)
原来x的结果:
1 2 3 0.6614 0.2669 0.0617 0.6213 -0.4519 -0.1661 [torch.FloatTensor of size 2x3]
将x的维度互换:x.transpose(0,1)
,其实相当于转置操作! 结果
1 2 3 4 0.6614 0.6213 0.2669 -0.4519 0.0617 -0.1661 [torch.FloatTensor of size 3x2]
torch.permute() 多维度互换 permute是更灵活的transpose,可以灵活的对原数据的维度进行调换,而数据本身不变。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 In [31 ]: x = torch.randn(2 ,3 ,4 ) In [32 ]: x Out[32 ]: tensor([[[ 0.7626 , 0.4415 , 1.1651 , 2.0154 ], [ 0.2152 , -0.5242 , -1.8034 , -1.3083 ], [ 0.4100 , 0.4085 , 0.2579 , 1.0950 ]], [[-0.5065 , 0.0998 , -0.6540 , 0.7317 ], [-1.4567 , 1.6089 , 0.0938 , -1.2597 ], [ 0.2546 , -0.5020 , -1.0412 , 0.7323 ]]]) In [33 ]: x.shape Out[33 ]: torch.Size([2 , 3 , 4 ]) In [34 ]: x.permute(1 ,0 ,2 ) Out[34 ]: tensor([[[ 0.7626 , 0.4415 , 1.1651 , 2.0154 ], [-0.5065 , 0.0998 , -0.6540 , 0.7317 ]], [[ 0.2152 , -0.5242 , -1.8034 , -1.3083 ], [-1.4567 , 1.6089 , 0.0938 , -1.2597 ]], [[ 0.4100 , 0.4085 , 0.2579 , 1.0950 ], [ 0.2546 , -0.5020 , -1.0412 , 0.7323 ]]]) In [35 ]: x.permute(1 ,0 ,2 ).shape Out[35 ]: torch.Size([3 , 2 , 4 ])
torch.squeeze() 和 torch.unsqueeze() 常用来增加或减少维度,如没有batch维度时,增加batch维度为1。
squeeze(dim_n)压缩,减少dim_n维度 ,即去掉元素数量为1的dim_n维度。 unsqueeze(dim_n),增加dim_n维度,元素数量为1。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 In [38 ]: x = torch.randn(1 ,3 ,4 ) In [39 ]: x.shape Out[39 ]: torch.Size([1 , 3 , 4 ]) In [40 ]: x Out[40 ]: tensor([[[-0.4791 , 0.2912 , -0.8317 , -0.5525 ], [ 0.6355 , -0.3968 , -0.6571 , -1.6428 ], [ 0.9803 , -0.0421 , -0.8206 , 0.3133 ]]]) In [41 ]: x.squeeze() Out[41 ]: tensor([[-0.4791 , 0.2912 , -0.8317 , -0.5525 ], [ 0.6355 , -0.3968 , -0.6571 , -1.6428 ], [ 0.9803 , -0.0421 , -0.8206 , 0.3133 ]]) In [42 ]: x.squeeze().shape Out[42 ]: torch.Size([3 , 4 ]) In [43 ]: x.unsqueeze(0 ) Out[43 ]: tensor([[[[-0.4791 , 0.2912 , -0.8317 , -0.5525 ], [ 0.6355 , -0.3968 , -0.6571 , -1.6428 ], [ 0.9803 , -0.0421 , -0.8206 , 0.3133 ]]]]) In [44 ]: x.unsqueeze(0 ).shape Out[44 ]: torch.Size([1 , 1 , 3 , 4 ])
torch.Tensor
有两个实例方法可以用来扩展某维的数据的尺寸,分别是 repeat()
和 expand()
。
expand() 返回当前张量在某维扩展更大后的张量。按照指定size扩充。
扩展(expand)张量不会分配新的内存,只是在存在的张量上创建一个新的视图(view),一个大小(size)等于1的维度扩展到更大的尺寸。 代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 In [45 ]: x = torch.randn(1 ,3 ) In [46 ]: x Out[46 ]: tensor([[-1.1352 , 0.3773 , -0.2824 ]]) In [47 ]: x.expand(2 , 3 ) Out[47 ]: tensor([[-1.1352 , 0.3773 , -0.2824 ], [-1.1352 , 0.3773 , -0.2824 ]]) In [48 ]: x.expand(2 , -1 ) Out[48 ]: tensor([[-1.1352 , 0.3773 , -0.2824 ], [-1.1352 , 0.3773 , -0.2824 ]])
repeat() 沿着特定的维度重复这个张量,按照倍数扩充;和expand()
不同的是,这个函数拷贝张量的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 In [53 ]: x Out[53 ]: tensor([[-1.1352 , 0.3773 , -0.2824 ]]) In [54 ]: x.shape Out[54 ]: torch.Size([1 , 3 ]) In [55 ]: x.repeat(2 ,3 ) Out[55 ]: tensor([[-1.1352 , 0.3773 , -0.2824 , -1.1352 , 0.3773 , -0.2824 , -1.1352 , 0.3773 , -0.2824 ], [-1.1352 , 0.3773 , -0.2824 , -1.1352 , 0.3773 , -0.2824 , -1.1352 , 0.3773 , -0.2824 ]]) In [56 ]: x.repeat(2 ,3 ).shape Out[56 ]: torch.Size([2 , 9 ])
torch.narrow() PyTorch 中的narrow()
函数起到了筛选一定维度上的数据作用。个人感觉与x[begin:end]
相同!
参考官网:torch.narrow()
用法:torch.narrow(input, dim, start, length) → Tensor
返回输入张量的切片操作结果。 输入tensor和返回的tensor共享内存。
参数说明:
input (Tensor)
– 需切片的张量dim (int)
– 切片维度start (int)
– 开始的索引length (int)
– 切片长度示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 In [1 ]: import torch In [2 ]: x = torch.randn(3 ,3 ) In [3 ]: x Out[3 ]: tensor([[ 1.2474 , 0.1820 , -0.0179 ], [ 0.1388 , -1.7373 , 0.5934 ], [ 0.2288 , 1.1102 , 0.6743 ]]) In [4 ]: x.narrow(0 , 1 , 2 ) Out[4 ]: tensor([[ 0.1388 , -1.7373 , 0.5934 ], [ 0.2288 , 1.1102 , 0.6743 ]]) In [5 ]: x.narrow(1 , 1 , 2 ) Out[5 ]: tensor([[ 0.1820 , -0.0179 ], [-1.7373 , 0.5934 ], [ 1.1102 , 0.6743 ]])
torch.unbind() torch.unbind()
移除指定维后,返回一个元组,包含了沿着指定维切片后的各个切片。
参考官网:torch.unbind()
用法:torch.unbind(input, dim=0) → seq
返回指定维度切片后的元组。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 In [6 ]: x Out[6 ]: tensor([[ 1.2474 , 0.1820 , -0.0179 ], [ 0.1388 , -1.7373 , 0.5934 ], [ 0.2288 , 1.1102 , 0.6743 ]]) In [7 ]: torch.unbind(x, 0 ) Out[7 ]: (tensor([ 1.2474 , 0.1820 , -0.0179 ]), tensor([ 0.1388 , -1.7373 , 0.5934 ]), tensor([0.2288 , 1.1102 , 0.6743 ])) In [8 ]: torch.unbind(x, 1 ) Out[8 ]: (tensor([1.2474 , 0.1388 , 0.2288 ]), tensor([ 0.1820 , -1.7373 , 1.1102 ]), tensor([-0.0179 , 0.5934 , 0.6743 ]))
torch.gather() 参考官网:torch.gather
用法:torch.gather(input, dim, index, out=None, sparse_grad=False) → Tensor
收集输入的特定维度dim
指定位置index
的数值。
对于一个三维tensor,结果如下:
1 2 3 out[i][j][k] = input[index[i][j][k]][j][k] # if dim == 0 out[i][j][k] = input[i][index[i][j][k]][k] # if dim == 1 out[i][j][k] = input[i][j][index[i][j][k]] # if dim == 2
参数说明:
input (Tensor)
– 输入张量dim (int)
– 索引维度index (LongTensor)
– 收集元素的索引out (Tensor, optional)
– 目标张量sparse_grad (bool,optional)
– 输入为稀疏张量直接看官网解释有点不明白,参考另一文章的实例说明:https://blog.csdn.net/cpluss/article/details/90260550
在序列标注问题上,我们给每一个单词都标上一个标签。不妨假设我们有4个句子,每个句子的长度不一定相同,标签如下:
1 2 3 4 5 6 input = [ [2, 3, 4, 5], [1, 4, 3], [4, 2, 2, 5, 7], [1] ]
上例中有四个句子,长度分别为4,3,5,1,其中第一个句子的标签为2,3,4,5。我们知道,处理自然语言问题时,一般都需要进行padding,即将不同长度的句子padding到同一长度,以0为padding,那么上述经padding后变为:
1 2 3 4 5 6 input = [ [2, 3, 4, 5, 0, 0], [1, 4, 3, 0, 0, 0], [4, 2, 2, 5, 7, 0], [1, 0, 0, 0, 0, 0] ]
那么问题来了,现在我们想获得每个句子中最后一个词语的标签,该怎么得到呢?既是,第一句话中的5,第二句话中的3,第三句话中7,第四句话中的1。
此时就需要用gather函数。
此时我们的input就是填充之后的tensor,dim=1, index就是各个句子的长度,即[[4],[3],[5],[1]]。之所以维度是4*1,是为了满足index维度和input维度之间的关系(讲解参数时有讲)。
代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 In [26 ]: import torch ...: input = [ ...: [2 , 3 , 4 , 5 , 0 , 0 ], ...: [1 , 4 , 3 , 0 , 0 , 0 ], ...: [4 , 2 , 2 , 5 , 7 , 0 ], ...: [1 , 0 , 0 , 0 , 0 , 0 ] ...: ] ...: input = torch.tensor(input ) ...: ...: length = torch.LongTensor([[4 ],[3 ],[5 ],[1 ]]) ...: ...: out = torch.gather(input , 1 , length-1 ) ...: out Out[26 ]: tensor([[5 ], [3 ], [7 ], [1 ]])