最近pytorch使用的特别频繁, 这里总结一些pytorch中常用的张量(tensor)操作。

  1. tensor和array之间的转换

    A = t.ones(3,  4)
    # torch.tensor -> numpy.ndarray
    B = A.numpy()
    # numpy.ndarray -> torch.tensor
    C = t.from_numpy(B)
    # Note:
    # A, B, C共享内存, 修改任意一个, 3个都会同时改变. 
    # tensor和array之间的转换很快
    
  2. 从tensor中取值

    A = t.ones(5)
    # B仍然是一个Tensor, 只包含一个元素, 也称Scalar
    B = A[2]
    # 只包含一个元素的tensor才能使用item函数
    # item返回的才是数值
    V = B.item()
  3. 常见的tensor创建方式

    Tensor(sizes)基础构造函数
    tensor(data,)类似np.array的构造函数
    ones(sizes)全1Tensor
    zeros(sizes)全0Tensor
    eye(sizes)对角线为1,其他为0
    arange(s,e,step)从s到e,步长为step
    linspace(s,e,steps)从s到e,均匀切分成steps份
    rand/randn(*sizes)均匀/标准分布
    normal(mean,std)/uniform(from,to)正态分布/均匀分布
    randperm(m)随机排列
  4. 如何进行数据的拷贝

    # 1. 使用t.tensor()
    A = t.ones(5)
    # 拷贝A的数据给B
    B = t.tensor(A)
    
    # 此时,A和B不共享内存
    In [14]: id(A), id(B)
    Out[14]: (1751028332080, 1751295611024)
    
    # 2. 使用clone函数
    In [15]: c = A.clone()
    
    In [16]: id(A), id(c)
    Out[16]: (1751028332080, 1751295519912)
  5. inplace操作

    # Note:
    # pytorch中,所有以下划线结尾的函数 
    # 会修改Tensor本身, 比如add_, t_, sub_等
    In [18]: A.cos_()
    Out[18]:
    tensor([[ 0.5403,  0.5403,  0.5403,  0.5403],
            [ 0.5403,  0.5403, -0.6536,  0.5403],
            [ 0.5403,  0.5403,  0.5403,  0.5403]])
    
    In [19]: A.add_(2)
    Out[19]:
    tensor([[2.5403, 2.5403, 2.5403, 2.5403],
            [2.5403, 2.5403, 1.3464, 2.5403],
            [2.5403, 2.5403, 2.5403, 2.5403]])
    
    In [20]: A
    Out[20]:
    tensor([[2.5403, 2.5403, 2.5403, 2.5403],
            [2.5403, 2.5403, 1.3464, 2.5403],
            [2.5403, 2.5403, 2.5403, 2.5403]])
  6. 使用cuda

    # 如果支持gpu,则使用gpu
    Device = t.device("cuda" if.cuda.is_available() else      "cpu")
    # 将tensor转移到指定设备中
    x = x.to(device)
    y = y.to(device)
  7. 升维和降维(unsqueeze/squeeze)

    # 1. 在指定位置增加新的维度 -> unsqueeze
    In [22]: A.shape
    Out[22]: torch.Size([2, 1, 4])
    
    # 在A的第1个维度之前前插入新的维度
    In [23]: B = A.unsqueeze(0)
    
    In [24]: B.shape
    Out[24]: torch.Size([1, 2, 1, 4])
    
    # 在A的第3个维度之前插入新的维度
    In [25]: B = A.unsqueeze(2)
    
    In [26]: B.shape
    Out[26]: torch.Size([2, 1, 1, 4])
    
    
    # 2. 去掉指定位置的维度 -> unsqueeze
    # Note: 一个维度只包含一个元素的才可以被去掉
    # 去掉B的第2个维度
    In [27]: C = B.squeeze(1)
    
    In [28]: C.shape
    Out[28]: torch.Size([2, 1, 4])
    # 不指定参数,则会去掉B所有只有一个元素的维度
    In [29]: C = B.squeeze()
    
    In [30]: C.shape
    Out[30]: torch.Size([2, 4])
  8. 交换维度/改变维度顺序(transpose/permute)

    # 1. transpose一次只能改变2个维度的位置
    In [33]: B.shape
    Out[33]: torch.Size([2, 1, 1, 4])
    #交换B的第1个维度和第2个维度,B和C共享内存
    In [34]: C = B.transpose(0, 1)
    
    In [35]: C.shape
    Out[35]: torch.Size([1, 2, 1, 4])
    
    # 2. permute可以同时改变多个维度的位置
    # 重新调整B的维度顺序
    In [36]: B.shape
    Out[36]: torch.Size([2, 1, 1, 4])
    
    In [37]: C = B.permute(1, 2, 0, 3)
    
    In [38]: C.shape
    Out[38]: torch.Size([1, 1, 2, 4])
  9. 获取最大/小值(max/min)

    In [42]: A = t.rand(7, 4)
    
    # max函数返回指定维度的最大值以及还最大值的位置
    In [43]: t.max(A, 0)
    Out[43]:
    torch.return_types.max(
    values=tensor([0.7347, 0.9382, 0.8176, 0.9182]),
    indices=tensor([4, 6, 3, 0]))
    
    # min函数类似
    # ...
  10. 逻辑函数 t.any和t.all

    # pytorch中,all和any只支持uint8和bool类型的tensor
    # numpy中,所有数值类型以及bool类型的数组都支持逻辑运算
    In [52]: A = t.randint(0, 5, (5, 4)).type(t.uint8)
    
    In [53]: A
    Out[53]:
    tensor([[0, 4, 1, 3],
           [0, 0, 4, 1],
           [3, 0, 2, 1],
           [0, 0, 1, 1],
           [2, 0, 1, 4]], dtype=torch.uint8)
    
    # 1. all 沿着指定维度,只要有一个False(0),即为False(0)
    In [54]: A.all(0)
    Out[54]: tensor([0, 0, 1, 1], dtype=torch.uint8)
    
    # 2. any 沿着指定维度,只要有一个True(1),即为True(1)
    In [55]: A.any(0)
    Out[55]: tensor([1, 1, 1, 1], dtype=torch.uint8)
  11. 创建网格(meshgrid)

    # t.meshgrid的第一个参数表示列, 第二个参数表示行
    # 跟numpy刚好相反
    >>> a, b = t.meshgrid(t.arange(5), t.arange(5))
    >>> a
    tensor([[0, 0, 0, 0, 0],
           [1, 1, 1, 1, 1],
           [2, 2, 2, 2, 2],
           [3, 3, 3, 3, 3],
           [4, 4, 4, 4, 4]])
    >>> b
    tensor([[0, 1, 2, 3, 4],
           [0, 1, 2, 3, 4],
           [0, 1, 2, 3, 4],
           [0, 1, 2, 3, 4],
           [0, 1, 2, 3, 4]])
  12. 重复(repeat)

    repeat操作对数据进行了复制

    # 
    In [63]: A = t.rand(3, 2)
    
    # 指定A的第1个维度重复2次,第2个维度重复2次
    In [64]: A.repeat(2, 2)
    Out[64]:
    tensor([[0.4932, 0.4790, 0.4932, 0.4790],
           [0.2069, 0.9966, 0.2069, 0.9966],
           [0.8775, 0.1757, 0.8775, 0.1757],
           [0.4932, 0.4790, 0.4932, 0.4790],
           [0.2069, 0.9966, 0.2069, 0.9966],
           [0.8775, 0.1757, 0.8775, 0.1757]])
  13. 扩展维度的尺寸(expand)
    和repeat类似,都可以实现维度尺寸的扩展。但需要注意的是
    Note:expand并没有复制新的数据,而是在原有数据的基础上创建了视图。所以在修改源张量时,现有张量会同时被修改

    In [20]: a
    Out[20]: tensor([[0.2521, 0.1678, 0.4995, 0.5533]])
    # 将第一个维度扩展为2,第二个维度扩展为4
    In [21]: b = a.expand(2, 4)
    
    In [22]: b
    Out[22]:
    tensor([[0.2521, 0.1678, 0.4995, 0.5533],
            [0.2521, 0.1678, 0.4995, 0.5533]])
    
    # 修改b会同时修改a
    In [23]: b[1, 3] = 3
    
    In [24]: a
    Out[24]: tensor([[0.2521, 0.1678, 0.4995, 3.0000]])
    
    In [25]: b
    Out[25]:
    tensor([[0.2521, 0.1678, 0.4995, 3.0000],
            [0.2521, 0.1678, 0.4995, 3.0000]])
    
  14. 条件查找(where)

    # 1. 按条件修改值
    In [63]: A = t.rand(3, 2)
    
    # where(condition, x, y)
    # 满足条件,则返回x,不满足返回y
    # torch.where与numpy.where 的区别是,
    # torch.where中的参数x, y均要求为tensor
    In [72]: B = t.where(A > 5, t.tensor([10]), t.tensor([0]))
    
    In [73]: B
    Out[73]:
    tensor([[10,  0,  0,  0],
           [ 0,  0, 10,  0],
           [ 0,  0, 10, 10],
           [10, 10, 10,  0],
           [10,  0, 10, 10]])
           
    # 2. 获取满足条件的索引
    
    In [81]: t.where(A>4)
    Out[81]:
    (tensor([0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4]),
    tensor([0, 2, 2, 3, 0, 1, 2, 0, 1, 2, 3]))
    
    In [82]: A
    Out[82]:
    tensor([[8, 2, 3, 2],
           [1, 4, 8, 0],
           [4, 0, 9, 9],
           [8, 9, 7, 4],
           [9, 5, 8, 7]])
  15. 截断(clamp)

    # 和torch.where 功能类似,但功能没有where丰富
    # torch.clamp(input, min, max, out=None)
    # 对于input的所有值,从min和max两个位置截断
    # 小于min的值,则设为min;大于max的值,则设为max
    
    In [82]: A
    Out[82]:
    tensor([[8, 2, 3, 2],
           [1, 4, 8, 0],
           [4, 0, 9, 9],
           [8, 9, 7, 4],
           [9, 5, 8, 7]])
    # 将A中小于5的值设为5, 大于8的值设为8
    In [83]: t.clamp(A, 5, 8)
    Out[83]:
    tensor([[8, 5, 5, 5],
           [5, 5, 8, 5],
           [5, 5, 8, 8],
           [8, 8, 7, 5],
           [8, 5, 8, 7]])
  16. 组合(stack/cat)

    # 1. stack在新的维度上进行拼接,张量对应维度尺寸需相同
    
    In [97]: B = t.rand(3, 4)
    
    In [98]: C = t.rand(3, 4)
    
    # 在第1个维度之前新增一个维度,在新的维度上拼接
    In [99]: t.stack([B, C], 1).shape
    Out[99]: torch.Size([3, 2, 4])
    
    # 2. cat在现有维度上进行拼接
    # 在第一个维度上进行拼接
    In [107]: t.cat([B, C], 0).shape
    Out[107]: torch.Size([6, 4])
    
  17. gather
    按维度索引取值。 在one-hot编码的处理中, 经常使用。

    In [2]: a = t.rand(3, 4)
    
    In [3]: a
    Out[3]:
    tensor([[0.6875, 0.7594, 0.4874, 0.0156],
            [0.6033, 0.8766, 0.3650, 0.7240],
            [0.3139, 0.4568, 0.8455, 0.9149]])
    
    # 在第二个维度上, 取出索引为(1, 2, 0)的值, 
    # Note: 除了第dim个维度, index的其它维度必须和a一致. 比如dim=1, 那除了第1个维度, 其它维度必须一致
    
    # 输出的维度和index的维度一致
    
    # index -> [3, 1], a -> [3, 4]
    In [4]: a.gather(dim=1, index=t.tensor([[1],[2], [0]]))
    Out[4]:
    tensor([[0.7594],
            [0.3650],
            
    # index -> [1, 4], a -> [3, 4]
    In [10]: a.gather(dim=0, index=t.tensor([[1,2, 0, 0]]))
    Out[10]: tensor([[0.6033, 0.4568, 0.4874, 0.0156]])
  18. scatter
    按维度索引设定值

    >>> a
    tensor([[1, 2, 6, 5],
            [6, 7, 9, 0],
            [7, 8, 3, 1],
            [2, 8, 0, 6]])
            
    # 指定在张量的那个维度上进行操作        
    >>> dim = 1
    
    # 需要被填充的值
    >>> val = 0
    
    # index 在dim之外的维度需要保持一致
    >>> index = t.tensor([0, 1, 2, 1]).unsqueeze(1)
    
    # 可以看到,a[0, 0], a[1, 1], a[2, 2]和a[3, 1]被修改成val
    >>> a.scatter(dim, index, val)
    tensor([[0, 2, 6, 5],
            [6, 0, 9, 0],
            [7, 8, 0, 1],
            [2, 0, 0, 6]])
            
    # 既然可以设置指定值,那么是否可以设置指定的张量呢,答案是可以的
    
    # 比如也可以这样,val和index的维度一致
    >>> val = t.randint(10, 100, (4,))
    >>> val
    tensor([59, 39, 76, 99])
    
    >>> a.scatter(dim, index, val)
    tensor([[59,  2,  6,  5],
            [ 6, 39,  9,  0],
            [ 7,  8, 76,  1],
            [ 2, 99,  0,  6]])

    scatter在labelsmooth以及标签转onehot矩阵时经常用到,功能很强大。


mhxin
84 声望15 粉丝