[Deep Learning]——Tensor维度变换

1、view / reshape

不足之处:会丢失维度信息(Lost dim information)

import torch
import numpy as np

#创建Tensor
def test():
   a  = torch.rand(4, 1, 28, 28)
   print(a.shape)
   #[4, 1*28*28]
   print(a.view(4, 1*28*28))
   print(a.view(4, 1*28*28).shape)
   #把b,c,w合到一起组成一个很大的数,只关注列
   print(a.view(4*1*28, 28).shape)
   print(a.view(4*1, 28, 28).shape)

if __name__ == '__main__':
    test()

 (1)致命问题

如果直接使用a reshape后的tensor为另一个tensor赋值,这样会出现维度信息丢失

import torch
import numpy as np

#创建Tensor
def test():
   a  = torch.rand(4, 1, 28, 28)
   print(a.shape)
   #维度信息丢失,b中不会复现a,因为不知道a的具体信息
   #比如:a 【b, c, w, h】信息丢失
   b = a.view(4, 784)
   #代码上支持,但是逻辑上也正确,但是破坏了原来的数据,导致数据丢失
   # 【b, w, h, c】
   print(b.view(4, 28, 28, 1).shape)

   #view新的tensor的size与原来的不一致
   a.view(4, 783) #error

if __name__ == '__main__':
    test()

2、squeeze / unsqueeze

维度增加

维度增加其实就是认为的添加一个维度,为其赋予相应的意义

维度增加时维度范围的确定:【-a.dim()-1, a.dim()+1),本次演示当中的维度信息是[-5, 5) 

import torch
import numpy as np

#tensor的增加
def test():
    a = torch.rand(4, 3, 28, 28)
    print(a.shape)
    #unsqueeze(维度):在第几维度上插入一个维度
    print(a.unsqueeze(0).shape)
    print(a.unsqueeze(-1).shape)
    print(a.unsqueeze(4).shape)
    print(a.unsqueeze(-4).shape)
    print(a.unsqueeze(-5).shape)
    
    #跨纬度插入,a是一个4维的tensor, 索引最大是3,这里在第五维度上插入错误
    print(a.unsqueeze(5).shape) #error

if __name__ == '__main__':
    test()

<1> for example

import torch
import numpy as np

#tensor的增加
def test():
    b = torch.rand(32)
    print(b)
    f = torch.rand(4, 32, 14, 14)
    b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
    print(b.shape)

if __name__ == '__main__':
    test()

维度减少

  • squeeze函数,不指定参数时:代表减少所有dim = 1的维度
  • 也可以减少指定维度的,如果指定的维度不是1的话,减少无效
import torch
import numpy as np

#维度减少
def test():
    #unsqueeze
    b = torch.rand(32)
    b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
    print(b.shape)

    #squeeze
    #即 dim为1的
    print(b.squeeze().shape)
    print(b.squeeze(0).shape)
    print(b.squeeze(1).shape)
    print(b.squeeze(-1).shape)
    print(b.squeeze(-4).shape)

if __name__ == '__main__':
    test()

 3、expand / repeat

维度扩展:把对应维度上面的shape改变掉

  • expand :broadcasting
  • repeat:memory copied
  • 区别:expand是改变了理解方式,并没有改变数据;而repeat是实实在在的增加了数据
    • expand不会主动的复制数据,只会在有需要的时候才去复制数据,会省略掉复制数据的过程,比较推荐使用
  • 维度为1是可以复制的,不为1的话不能复制
  • 扩张时,维度上写的是 -1 表示当前维度不扩张

expand方式:

expand方式传递的参数代表需要扩展到的维度值

import torch
import numpy as np

#维度扩张
def test():
    #unsqueeze
    b = torch.rand(32)
    b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
    print(b.shape)

    print(b.expand(4, 32, 14, 14).shape)
    # -1 表示当前维度不修改
    print(b.expand(-1, 32, -1, -1).shape)

if __name__ == '__main__':
    test()

 repeat方式:

repeat方式传递的参数代表维度需要拷贝的次数,其实就是原始维度值 * 倍数

import torch
import numpy as np

#维度扩张
def test():
    #unsqueeze
    b = torch.rand(32)
    b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
    print(b.shape)

    print(b.repeat(4, 32, 1, 1).shape)
    print(b.repeat(4, 1, 1, 1).shape)
    print(b.repeat(4, 1, 32, 32).shape)

if __name__ == '__main__':
    test()

 4、矩阵转置

(1)t()矩阵转换

转置操作只针对矩阵(适用于2D的tensor),多维的情况不适用

import torch
import numpy as np

#矩阵的转置
def test():
    #unsqueeze
    b = torch.rand(32)
    b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)
    print(b.shape)

    #矩阵转置
    a = torch.randn(3, 4)
    print(a.t())

    #转置操作只适用于2D情况
    print(b.t())

if __name__ == '__main__':
    test()

 (2)维度交换(Transpose)

维度交换后,如果再使用view进行维度变换,view操作会丢掉维度信息,之后如果需要数据恢复是需要注意原本数据的维度顺序

  • 交换维度后,改变了数据的存储方式,所以是不连续的,需要使用 contiguous 将数据变连续再调整维度信息 (view)

5、Broadcast自动扩展

  • expand:自动扩展
  • without copying data 没有拷贝

(1)具体实施

  1. Insert 1 dim ahead:从最小的维度开始匹配,如果没有维度的话插入一个新的维度
  2. Expand dims with size 1 to same size

 (2)Why broadcastig

broadcasting减少了内存消耗,满足数学上的要求,且不需要手动去扩充的需求

6、拼接和拆分

Merge split:

  • Cat([tensor_1, tensor_2],dim=xx) dim指定在哪个维度上合并
  • Stack
  • split
  • chunk

cat(拼接)

import torch
import numpy as np

#统计学生的分数,最终将不同班级的成绩单合并
#[class 1-4, student, scores]
#[class 5-9, student, scores]
def test():
    a = torch.rand(4, 32, 8)
    b = torch.rand(5, 32, 8)
    print("a.shape = {0}, b.shape = {1}".format(a.shape, b.shape))
    print(torch.cat([a, b], dim=0).shape)

if __name__ == '__main__':
    test()

(1)Along distinct dim/ axis

import torch
import numpy as np

def test():
    a = torch.rand(4, 3, 32, 32)
    b = torch.rand(5, 3, 32, 32)
    print("a.shape = {0}, b.shape = {1}".format(a.shape, b.shape))
    print(torch.cat([a, b], dim=0).shape)

    b = torch.rand(4, 1, 32, 32)
    print(torch.cat([a, b], dim=1).shape)

    a = torch.rand(4, 3, 16, 32)
    b = torch.rand(4, 3, 16, 32)
    print(torch.cat([a, b], dim=2).shape)
if __name__ == '__main__':
    test()

 stack(拼接)

create new dim——> stack([tensor_1, tensor_2], dim=xxx) 在xxx维度上增加一个维度

  • 对于stack而言,在某个维度上创建维度时,两个tensor对应在原来位置上的维度值时一样的
import torch
import numpy as np

def test():
    a = torch.rand(4, 3, 16, 32)
    b = torch.rand(4, 3, 16, 32)
    print(torch.cat([a, b], dim=2).shape)
    print(torch.stack([a, b], dim=2).shape)

    a = torch.rand(32, 8)
    b = torch.rand(32, 8)
    print(torch.stack([a, b], dim=0).shape)


if __name__ == '__main__':
    test()

 split(拆分)

根据单元 的长度进行拆分:(1)直接指定长度,(2)指定长度分配列表的方式

import torch
import numpy as np

def test():
    a = torch.rand(32, 8)
    b = torch.rand(32, 8)
    c = torch.stack([a, b], dim=0)
    print(c.shape)

    #通过列表方式:按照列表中指定的分配方式分配
    aa, bb = c.split([2, 0], dim=0)
    print("aa.shape: {0}, bb.shape: {1}".format(aa.shape, bb.shape))

    #直接指定长度分割
    aa, bb = c.split(1, dim=0)
    print("aa.shape: {0}, bb.shape: {1}".format(aa.shape, bb.shape))

if __name__ == '__main__':
    test()

chunk:按照数量拆分

import torch
import numpy as np

def test():
    a = torch.rand(32, 8)
    b = torch.rand(32, 8)
    c = torch.stack([a, b], dim=0)
    print(c.shape)

    #通过数量拆分
    #也就是将大的分为几块
    aa, bb = c.chunk(2, dim=0)
    print("aa.shape: {0}, bb.shape: {1}".format(aa.shape, bb.shape))

if __name__ == '__main__':
    test()

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Star星屹程序设计

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值