Pytorch中张量的构造与组织

前言:《神经网络与PyTorch实战》读书笔记之PyTorch中的张量操作

1. PyTorch中的张量

  • torch.Tensor类的常用成员:
    • size() 返回张量大小
    • dim() 返回张量维度
    • numel() 返回张量中元素个数
>>> import torch
>>> tmp = torch.tensor([[1,2,3],[4,5,6]])
>>> tmp
tensor([[1, 2, 3],
        [4, 5, 6]])
>>> tmp.reshape(3,2)
tensor([[1, 2],
        [3, 4],
        [5, 6]])
>>> tmp
tensor([[1, 2, 3],
        [4, 5, 6]])
>>> tmp.size()
torch.Size([2, 3])
>>> tmp.dim()
2
>>> tmp.numel()
6
>>> tmp.dtype
torch.int64

2. 构造Tensor实例方法

  • torch.zeros(), torch.zeros_like()

    •   >>> torch.zeros(3,4)
        tensor([[0., 0., 0., 0.],
                [0., 0., 0., 0.],
                [0., 0., 0., 0.]])
        >>> a=torch.tensor([1,2,3])
        >>> torch.zeros_like(a)
        tensor([0, 0, 0])
        >>>
      
  • torch.ones(), torch.ones_like()

    •   >>> torch.ones(4,5)
        tensor([[1., 1., 1., 1., 1.],
                [1., 1., 1., 1., 1.],
                [1., 1., 1., 1., 1.],
                [1., 1., 1., 1., 1.]])
        >>> torch.ones_like(torch.zeros(3,4))
        tensor([[1., 1., 1., 1.],
                [1., 1., 1., 1.],
                [1., 1., 1., 1.]])
        >>>
      
  • torch.full(), torch.full_like()

    • 两个参数,张量的大小和要填充的值

      >>> torch.full((3,3),3)
      tensor([[3., 3., 3.],
              [3., 3., 3.],
              [3., 3., 3.]])
      >>> torch.full_like(torch.zeros(3,4),3)
      tensor([[3., 3., 3., 3.],
              [3., 3., 3., 3.],
              [3., 3., 3., 3.]])
      >>>
      
  • torch.empty(), torch.empty_like()

    • 不指定具体的值

      >>> torch.empty(2,2)
      tensor([[ 0.0000e+00,  0.0000e+00],
              [-3.7177e-36,  4.5912e-41]])
      >>> torch.empty_like(torch.zeros(3,3))
      tensor([[1.0561e-38, 1.0286e-38, 1.0653e-38],
              [1.0469e-38, 9.5510e-39, 6.2449e-39],
              [6.9796e-39, 8.4490e-39, 1.0561e-38]])
      >>>
      
  • torch.eye()

    •   >>> torch.eye(5,5)
        tensor([[1., 0., 0., 0., 0.],
                [0., 1., 0., 0., 0.],
                [0., 0., 1., 0., 0.],
                [0., 0., 0., 1., 0.],
                [0., 0., 0., 0., 1.]])
        >>>
      
  • torch.arange(), torch.range(), torch.linspace(), torch.logspace()

    •   >>> torch.arange(2,10)
        tensor([2, 3, 4, 5, 6, 7, 8, 9])
        >>> torch.arange(2,10,2)
        tensor([2, 4, 6, 8])
        >>> torch.range(2,10,2)
        __main__:1: UserWarning: torch.range is deprecated in favor of torch.arange and will be removed in 0.5. Note that arange generates values in [start; end), not [start; end].
        tensor([ 2.,  4.,  6.,  8., 10.])
        >>> torch.linespace(2,10,2)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        AttributeError: module 'torch' has no attribute 'linespace'
        >>> torch.linspace(2,10,2)
        tensor([ 2., 10.])
        >>> torch.linspace(2,10,6)
        tensor([ 2.0000,  3.6000,  5.2000,  6.8000,  8.4000, 10.0000])
        >>> torch.logspace(2,10,6)
        tensor([1.0000e+02, 3.9811e+03, 1.5849e+05, 6.3096e+06, 2.5119e+08, 1.0000e+10])
        >>>
      
    • arange() 中第三个参数代表每隔几个进行一次取样

    • linspace(), logspace()中第三个参数代表一共取多少个样本

  • torch.bernoulli(), torch.multinomial(), torch.randperm(), torch.randint(), torch.randint_like() 随机向量

    •   >>> probs = torch.full((3,4), 0.5) # 概率张量,有一定的概率取1
        >>> torch.bernoulli(probs)
        tensor([[0., 1., 1., 1.],
                [0., 0., 1., 1.],
                [1., 1., 0., 0.]])
        >>> torch.bernoulli(probs)
        tensor([[0., 0., 0., 0.],
                [1., 1., 0., 0.],
                [1., 0., 1., 0.]])
        >>>
      
    •   >>> import torch
        >>> weights=torch.tensor([[1,100],[100,1],[1,1]], dtype=torch.float32)
        >>> weights
        tensor([[  1., 100.],
                [100.,   1.],
                [  1.,   1.]])
        >>> torch.multinomial(weights,1)
        tensor([[1],
                [0],
                [1]])
        ps: 不知道有啥用
      
    •   >>> torch.randperm(5, dtype=torch.float32)
        tensor([2., 0., 3., 1., 4.])
        >>>
        功能就是随机生成一个排列,参数只有一个n, 得到{0,1,2..., n-1}一个排列
      
    •   >>> torch.randint(low=0,high=4,size=(3,4))
        tensor([[0, 2, 0, 1],
                [3, 2, 3, 1],
                [0, 1, 0, 0]])
        >>> torch.randint_like(torch.ones(3,4), low=0, high=4)
        tensor([[0., 0., 0., 0.],
                [3., 3., 1., 3.],
                [2., 3., 0., 2.]])
        功能:[low,high)范围的数,生成独立同分布的离散均匀分布的张量
      
    •   >>> torch.rand(2,3)
        tensor([[0.0408, 0.8364, 0.2955],
                [0.5750, 0.9387, 0.0326]])
        >>> torch.rand_like(torch.ones(3,3))
        tensor([[0.1841, 0.9014, 0.6892],
                [0.6298, 0.9209, 0.4046],
                [0.1707, 0.2002, 0.3489]])
        >>> mean=torch.tensor([0.,1.])
        >>> std=torch.tensor([3.,2.])
        >>> torch.normal(mean,std)
        tensor([-1.4714, -0.3917])
        >>>
      

3. 组织张量元素(重点)

张量的组织在深度学习中tensor的处理中非常常见,所以也是重中之重。

3.1 重排张量

  • reshape(), squeeze(), unsqueeze(),不会改变元素的实际位置
  • permute(), transpose(), t(), 可能会改变元素的实际位置
  1. reshape() 方法

    张量元素个数相同的情况下,改变张量的维度

    >>> import torch
    >>> ts = torch.arange(12)
    >>> ts.reshape(3,4)
    tensor([[ 0,  1,  2,  3],
            [ 4,  5,  6,  7],
            [ 8,  9, 10, 11]])
    >>> ts.reshape(3,4).size()
    torch.Size([3, 4])
    >>> ts.reshape(-1,4).size()
    torch.Size([3, 4])
    >>> ts.reshape(-1,2).size() # -1 代表可以通过其他维度进行计算
    torch.Size([6, 2])
    >>>
    
  2. squeeze()方法

    >>> t = torch.arange(24).reshape(2,1,3,4,1)
    >>> t.size()
    torch.Size([2, 1, 3, 4, 1])
    >>> t.squeeze()
    tensor([[[ 0,  1,  2,  3],
             [ 4,  5,  6,  7],
             [ 8,  9, 10, 11]],
    
            [[12, 13, 14, 15],
             [16, 17, 18, 19],
             [20, 21, 22, 23]]])
    >>> t.squeeze().size() # 将 1 维度的挤压掉
    torch.Size([2, 3, 4])
    >>>
    
  3. unsqueeze()方法

    >>> t = torch.arange(24).reshape(2,3,4)
    >>> t.unsqueeze(dim=1).size() # 在第1维度进行
    torch.Size([2, 1, 3, 4])
    
    ### 举个例子 两张图片
    >>> img = torch.ones([512,512,3])
    >>> img.size()
    torch.Size([512, 512, 3])
    >>> img = img.unsqueeze(dim=0)
    >>> img.size()
    torch.Size([1, 512, 512, 3])
    >>> img2 = torch.ones([512,512,3])
    >>> img2 = img2.unsqueeze(dim=0)
    >>> img2.size()
    torch.Size([1, 512, 512, 3])
    
  4. permuate()方法:英文意思是排列,重新排列,进行张量的交换

    >>> t = torch.arange(24).reshape(1,2,3,4)
    >>> t.permute(dims=[0,2,1,3])
    tensor([[[[ 0,  1,  2,  3],
              [12, 13, 14, 15]],
    
             [[ 4,  5,  6,  7],
              [16, 17, 18, 19]],
    
             [[ 8,  9, 10, 11],
              [20, 21, 22, 23]]]])
    >>> t.permute(dims=[0,2,1,3]).size() # 根据dims进行重排
    torch.Size([1, 3, 2, 4])
    >>>
    
  5. transpose(),张量的交换可以用转置实现

    >>> t.size()
    torch.Size([1, 2, 3, 4])
    >>> t.transpose(0,3).size()
    torch.Size([4, 2, 3, 1]) # 互换0和3维度
    >>>
    

3.2 选取部分张量

选取一个张量中部分元素,涉及index_select(), masked_select(), take()三个方法。

  1. index_select() 方法有两个参数,dim 表示对哪个维度进行处理, index表示选取该维度哪些指标

    >>> t = torch.arange(24).reshape(2,3,4)
    >>> index = torch.tensor([1,2])
    >>> t.index_select(dim=1, index=index)
    tensor([[[ 4,  5,  6,  7],
             [ 8,  9, 10, 11]],
    
            [[16, 17, 18, 19],
             [20, 21, 22, 23]]])
    >>> t.index_select(dim=1, index=index).size()
    torch.Size([2, 2, 4])
    >>>
    
  2. masked_select() 只接受一个张量参数mask, 这个mask大小必须要跟作用对象相同,且类型必须为torch.uint8,且其中元素必须是0或者1,对应为1的部分就会被选择。

    >>> t = torch.arange(12).reshape(3,4)
    >>> mask = torch.tensor([[1,0,0,1],[0,1,0,0],[0,0,0,0]])
    >>> mask = torch.tensor([[1,0,0,1],[0,1,0,0],[0,0,0,0]], dtype=torch.uint8)
    >>> t.masked_select(mask)
    tensor([0, 3, 5])
    >>> t
    tensor([[ 0,  1,  2,  3],
            [ 4,  5,  6,  7],
            [ 8,  9, 10, 11]])
    >>>
    
  3. take() 不考虑张量大小,只考虑总个数,相当于对tensor进行reshape(-1)以后进行索引的结果。

    >>> t = torch.arange(12).reshape(3,4)
    >>> t
    tensor([[ 0,  1,  2,  3],
            [ 4,  5,  6,  7],
            [ 8,  9, 10, 11]])
    >>> indices = torch.tensor([3,4,5])
    >>> t.take(indices)
    tensor([3, 4, 5])
    >>> indices = torch.tensor([1,4,2])
    >>> t.take(indices)
    tensor([1, 4, 2])
    >>>
    # ps: 用的不多
    

    3.3 张量扩展和拼接

    这部分也很重要,讲解了各个方法操作以后会介绍一个简单的但很实用的例子。

    主要涉及到三个方法:repeat(), cat(), stack()

    1. repeat() 方法可以对张量内容进行复制,复制方法具体看例子:

      >>> import torch
      >>> img = torch.ones(224,224) # 假如读入了单通道图片想要将其处理成三通道,就会用到repeat
      >>> img.size()
      torch.Size([224, 224])
      >>> img = img.unsqueeze(2)
      >>> img.size()
      torch.Size([224, 224, 1])
      >>> img = img.repeat(1,1,3)
      >>> img.size()
      torch.Size([224, 224, 3])
      >>>
      
    2. cat() 方法可以对张量内容进行拼接,有两个参数,第一个参数是一个张量列表,第二个参数就是指定根据哪个维度进行拼接。依然延续上一个例子,拼接多张图片。

      >>> img1 = torch.ones(224)
      >>> img1 = torch.ones(224,224)
      >>> img2 =torch.ones(224,224)
      >>> img_list = torch.cat([img1,img2],2)
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      IndexError: Dimension out of range (expected to be in range of [-2, 1], but got 2)
      >>> img1 = img1.unsqueeze(2)
      >>> img2 = img2.unsqueeze(2)
      >>> img_list = torch.cat([img1,img2],2)
      >>> img_list.size()
      torch.Size([224, 224, 2])
      >>>
      
    3. stack()方法与cat()方法不同之处在于stack()要求输入张量大小完全相同, 也可以看出来有其他地方不太一样。

      >>> img_list2 = torch.stack([img1,img2],2)
      >>> img_list2.size()
      torch.Size([224, 224, 2, 1])
      >>> img1.size()
      torch.Size([224, 224, 1])
      >>> img2.size()
      torch.Size([224, 224, 1])
      >>> img_list2 = torch.stack([img1,img2, img1, img2],2)
      >>> img_list2.size()
      torch.Size([224, 224, 4, 1])
      >>> tp = torch.arange(12).reshape(3,4)
      >>> tp.size()
      torch.Size([3, 4])
      >>> tn=-tp
      >>> tn.size()
      torch.Size([3, 4])
      >>> ts0 = torch.stack([tn,tp], 0)
      >>> ts0.size()
      torch.Size([2, 3, 4])
      >>> ts1 = torch.stack([tn,tn, tp, tp],1)
      >>> ts1.size()
      torch.Size([3, 4, 4])
      >>>
      

3.4 torch内置统计函数

主要有mean(), sum(), std(), var(), prod(), max(), min(), median(), kthvalue(), norm()

举例:

>>> t = torch.arange(5)
>>> t
tensor([0, 1, 2, 3, 4])
>>> t.mean() # 这里报错是因为不支持Long类型,使用dtype进行类型转化即可。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Can only calculate the mean of floating types. Got Long instead.
>>> t = torch.arange(5, dtype=torch.float32)
>>> t.mean()# 平均值
tensor(2.)
>>> t.var()# 方差
tensor(2.5000)
>>> t.sum()# 求和
tensor(10.)
>>> t.std()# 标准差
tensor(1.5811)
>>> t.median()#中位数
tensor(2.)
>>> t.kthvalue(3)#第k大值
torch.return_types.kthvalue(
values=tensor(2.),
indices=tensor(2))
>>> t.max()# 最大值
tensor(4.)
>>> t.min()# 最小值
tensor(0.)
>>> t.norm()# 范数
tensor(5.4773)

针对某个维度进行处理:

>>> t = torch.arange(12, dtype=torch.float32).reshape(2,2,3)
>>> t.var(dim=1) # 求某维度的方差
tensor([[4.5000, 4.5000, 4.5000],
        [4.5000, 4.5000, 4.5000]])
>>> t.prod(dim=1) # 求某一维度积
tensor([[ 0.,  4., 10.],
        [54., 70., 88.]])
>>> t.max(dim=1) # 求某一维度最大值
torch.return_types.max(
values=tensor([[ 3.,  4.,  5.],
        [ 9., 10., 11.]]),
indices=tensor([[1, 1, 1],
        [1, 1, 1]]))
>>> t.median(dim=1) # 求中位数
torch.return_types.median(
values=tensor([[0., 1., 2.],
        [6., 7., 8.]]),
indices=tensor([[0, 0, 0],
        [0, 0, 0]]))
>>> t.cumsum(dim=1) # 累计求和
tensor([[[ 0.,  1.,  2.],
         [ 3.,  5.,  7.]],

        [[ 6.,  7.,  8.],
         [15., 17., 19.]]])
>>> t.cumprod(dim=1) #累乘
tensor([[[ 0.,  1.,  2.],
         [ 0.,  4., 10.]],

        [[ 6.,  7.,  8.],
         [54., 70., 88.]]])
>>>

后记:暂且先写这么多,主要的用法,都已经写上了,后期遇到更多内容也会添加进来,欢迎在评论区讨论。

发布了39 篇原创文章 · 获赞 27 · 访问量 7962

猜你喜欢

转载自blog.csdn.net/DD_PP_JJ/article/details/102821409