zoukankan      html  css  js  c++  java
  • Pytorch03_张量变化

    Tensor变化

    导入库

    import numpy as np # 导入Numpy
    import torch  # 导入Torch

    1. 创建张量

     1)通过numpy的array创建

    # 创建(3,3)的全1矩阵
    arr = np.ones((3, 3))  
    # 创建张量,默认存放在CPU
    t1 = torch.tensor(arr)
    # 创建张量,存放在GPU
    t2 = torch.tensor(arr, device='cuda') 

     2)torch.from_numpy

    # 创建矩阵
    arr = np.array([[1, 2, 3], [4, 5, 6]])  
    # 转化为torch的张量形式
    t = torch.from_numpy(arr) 
    
    # 修改arr[0,0] 张量会同时变化,即共用内存
    arr[0, 0] = 0
    print(t) 
    >>> tensor([[0, 2, 3],[4, 5, 6]], dtype=torch.int32)

     3)torch.zeros 、torch.ones 、torch.full

    # torch.zeros
    t = torch.zeros(3,3)  
    # input:矩阵尺寸3,3
    print(t)
    >>> tensor([[0., 0., 0.],[0., 0., 0.],[0., 0., 0.]])
    
    # torch.ones
    t = torch.ones(3,3)  
    # input:矩阵尺寸3,3
    print(t)
    >>> tensor([[1., 1., 1.],[1., 1., 1.],[1., 1., 1.]])
    
    # torch.full
    t = torch.full((3,3),2)   
    # input:(矩阵尺寸3,3), 填充数值2
    print(t)
    >>> tensor([[2., 2., 2.],[2., 2., 2.],[2., 2., 2.]])

     4) 数列类 torch.arange 、torch.linspace

    # torch.arange
    t = torch.arange(2, 10, 2)   
    # input:数值区间[2,10),间隔2
    # 注意:是闭区间到开区间[2,10)
    print(t)
    >>> tensor([2, 4, 6, 8])
    
    # torch.linspace
    t = torch.linspace(2, 10, 6) 
    #input:数值区间[2,10],创建元素个数6
    # 注意是闭区间[2,10]
    print(t)
    >>> tensor([ 2.0000,  3.6000,  5.2000,  6.8000,  8.4000, 10.0000])

     5)分布类(正态分布)torch.normal

    t_normal = torch.normal(0, 1, size=(4,))  
    # input:均值,标准差,张量尺寸
    print(t_normal)
    >>> tensor([-0.7996,  0.5916,  0.8975,  0.6617])
    
    # 均值:tensor([1., 2., 3., 4.])
    mean = torch.arange(1, 5, dtype=torch.float)  
    # 标准差:tensor([1., 2., 3., 4.])
    std = torch.arange(1, 5, dtype=torch.float)   
    t_normal = torch.normal(mean, std)
    print(t_normal)
    
    >>> tensor([0.7053, 2.7317, 1.1439, 2.1598])  
    # 分别满足(1,1),(2,2),(3,3),(4,4)正态分布

    2. 张量信息

     1)tensor.size() 与 tensor.shape 的区别

    # 创建一定维度的张量
    a1 = torch.zeros(1)
    a2 = torch.zeros(2, 3)
    a3 = torch.zeros(2, 3, 5)
    
    # 输出维度信息 结果相同
    print('a1.size() = ', a1.size())
    print('a2.size() = ', a2.size())
    print('a3.size() = ', a3.size())
    
    print('a1.shape() = ', a1.shape)
    print('a2.shape() = ', a2.shape)
    print('a3.shape() = ', a3.shape)
    
    >>> a1.size() =  torch.Size([1])
    >>> a2.size() =  torch.Size([2, 3])
    >>> a3.size() =  torch.Size([2, 3, 5])
    
    >>> a1.shape() =  torch.Size([1])
    >>> a2.shape() =  torch.Size([2, 3])
    >>> a3.shape() =  torch.Size([2, 3, 5])

    区别,size(index) 可以通过指定参数,获取某维度的具体信息,shape不可以,但是 shape 可以使用 shape[index],达到同样的效果.

    print('a1.size(0) = ', a1.size(0))  # a1.size(0) =  1
    print('a2.size(1) = ', a2.size(1))  # a2.size(1) =  3
    print('a3.size(2) = ', a3.size(2))  # a3.size(2) =  5
    
    print('a1.shape(0) = ', a1.shape[0])  # a1.shape(0) =  1
    print('a2.shape(1) = ', a2.shape[1])  # a2.shape(1) =  3
    print('a3.shape(2) = ', a3.shape[2])  # a3.shape(2) =  5

     2) 其他信息

     数据类型、晚晚继续

    3. 维度变化

     1)改变 shape

    torch.reshape()、torch.view() 可以调整 Tensor 的 shape,返回一个新 shape 的 Tensor,torch.view() 是老版本的实现,torch.reshape() 是最新的实现,两者在功能上是一样的。

    import torch
    # 随机生成维度为4,1,28,28的矩阵
    a = torch.rand(4, 1, 28, 28)
    print(a.shape)  # torch.Size([4, 1, 28, 28])
    print(a.view(4 * 1, 28, 28).shape)  # torch.Size([4, 28, 28])
    print(a.reshape(4 * 1, 28, 28).shape) # torch.Size([4, 28, 28])
    print(a.reshape(4, 1 * 28 * 28).shape) # torch.Size([4, 784])

    注意:维度变换的时候要注意实际意义。

     2)删减维度

     torch.unsqueeze(index) 可以为 Tensor 增加一个维度,增加的这一个维度的位置由我们自己定义,新增加的这一个维度不会改变数据本身,只是为数据新增加了一个组别,这个组别是什么由我们自己定义。

     index的范围不能超过数据本身已有的维度范围,可以为负数,同负索引。

    a = torch.randn(4, 1, 28, 28)
    print(a.shape)  # torch.Size([4, 1, 28, 28])
    print(a.unsqueeze(0).shape)  # torch.Size([1, 4, 1, 28, 28])
    print(a.unsqueeze(-1).shape)  # torch.Size([4, 1, 28, 28, 1])
    print(a.unsqueeze(3).shape)  # torch.Size([4, 1, 28, 1, 28])
    print(a.unsqueeze(4).shape)  # torch.Size([4, 1, 28, 28, 1])
    print(a.unsqueeze(-4).shape)  # torch.Size([4, 1, 1, 28, 28])
    print(a.unsqueeze(-5).shape)  # torch.Size([1, 4, 1, 28, 28])
    print(a.unsqueeze(5).shape)  # 报错,超出范围了,原始数据只有四个维度(最大索引为3),因此最多只能在第五个维度上增加(索引为4)
    
    Traceback (most recent call last):
      File "/home/lhy/workspace/mmdetection/my_code/pytorch_ws/tensotr_0.py", line 218, in <module>
        print(a.unsqueeze(5).shape)
    IndexError: Dimension out of range (expected to be in range of [-5, 4], but got 5)

    删减维度实际上是一个维度挤压的过程,直观地看是把那些多余的[]给去掉,也就是只是去删除那些size=1的维度。

    import torch
     
    a = torch.Tensor(1, 4, 1, 9)
    print(a.shape)  # 
    print(a.squeeze().shape) # 删除所有的size=1的维度
    print(a.squeeze(0).shape) # 删除0号维度,ok
    print(a.squeeze(2).shape) # 删除2号维度,ok
    print(a.squeeze(3).shape) # 删除3号维度,但是3号维度是9不是1,删除失败
    
    >>> torch.Size([1, 4, 1, 9])
    >>> torch.Size([4, 9])
    >>> torch.Size([4, 1, 9])
    >>> torch.Size([1, 4, 9])
    >>> torch.Size([1, 4, 1, 9])

     3)维度扩展

    expand 就是在某个 size=1 的维度上改变 size,改成更大的一个大小,实际就是在每个 size=1 的维度上的标量的广播操作。
    import torch
    # 想要把bias加到data上面去
    bias = torch.rand(32)
    data = torch.rand(4, 32, 14, 14)
    
    # 先进行维度增加
    bias = bias.unsqueeze(1).unsqueeze(2).unsqueeze(0)
    print(bias.shape)  # torch.Size([1, 32, 1, 1])
     
    # 再进行维度扩展
    bias = bias.expand(4, -1, 14, 14)  # -1表示这个维度保持不变,这里写32也可以
    print(bias.shape)  # torch.Size([4, 32, 14, 14])
    
    # 可以看出,效果就是把维度为1的地方复制了很多份,以完成扩展的目的
    data + bias

    repeat 就是将每个位置的维度都重复至指定的次数,以形成新的 Tensor,功能与维度扩展一样,但是 repeat 会重新申请内存空间,repeat() 参数表示各个维度指定的重复次数。

    import torch
    
    b = torch.Tensor(1, 32, 1, 1)
    print(b.shape)  # torch.Size([1, 32, 1, 1])
    # 维度重复,32这里不想进行重复,所以就相当于"重复至1次"
    b = b.repeat(4, 1, 14, 14)
    print(b.shape)  # torch.Size([4, 32, 14, 14])

     4)转置操作

     Pytorch的转置操作只适用于dim=2的Tensor,也就是矩阵。

    c = torch.Tensor(2, 4)  # shape=(2,4)
    print(c.t().shape)  # torch.Size([4, 2])

     5)维度交换

    transpose

    # transpose 交换维度
    d = torch.Tensor(6, 3, 1, 2)
    # 1号维度和3号维度交换
    # 注意这种交换使得存储不再连续,再执行一些reshape的操作会报错,所以要调用一下contiguous()使其变成连续的维度。
    print(d.transpose(1, 3).contiguous().shape)  
    
    >>> torch.Size([6, 2, 1, 3])

     举个例子验证一下

    下面这个例子比较一下每个位置上的元素都是一致的,来验证一下这个交换->压缩shape->展开shape->交换回去是没有问题的。

    e = torch.rand(4, 3, 6, 7)
    e2 = e.transpose(1, 3).contiguous().reshape(4, 7 * 6 * 3).reshape(4, 7, 6, 3).transpose(1, 3)
    print(e2.shape)  # torch.Size([4, 3, 6, 7])
    # 比较下两个Tensor所有位置上的元素是否都相等,返回1表示相等。
    print(torch.all(torch.eq(e, e2)))  # tensor(1, dtype=torch.uint8)

    permute

    如果四个维度表示上节的 [batch,channel,h,w] ,如果想把 channel 放到最后去,形成 [batch,h,w,channel],那么如果使用前面的维度交换,至少要交换两次(先13交换再12交换)。而使用 permute 可以直接指定维度新的所处位置,更加方便。

    a = torch.rand(4, 3, 6, 7)
    print(a.permute(0, 2, 3, 1).shape)  # torch.Size([4, 6, 7, 3])

    逻辑是:原有维度顺序为,0、1、2、3...  参数表示的含义为原有维度的索引。如上面例子表示,现在的第一个位置是原来的 0 维度(索引),现在的第二个位置是原来的2维度(索引)...



















    我喜欢一致,可是世界并不一致
  • 相关阅读:
    手机浏览器跳转APP
    js识别用户设备是移动端手机时跳转到手机网站
    input文字颜色、光标颜色
    vue和微信小程序的区别、比较
    vue-router query和params传参(接收参数),$router、$route的区别
    vue父子组件、兄弟组件之间的通信和访问
    利用Everything开启http服务测试移动端浏览器环境
    Vue基础知识简介
    关于Vue的一些小技巧
    Flume环境安装
  • 原文地址:https://www.cnblogs.com/Haozi-D17/p/14866477.html
Copyright © 2011-2022 走看看