不足之处:会丢失维度信息(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()
如果直接使用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()
维度增加其实就是认为的添加一个维度,为其赋予相应的意义
维度增加时维度范围的确定:【-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()
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()
维度扩展:把对应维度上面的shape改变掉
- expand :broadcasting
- repeat:memory copied
- 区别:expand是改变了理解方式,并没有改变数据;而repeat是实实在在的增加了数据
- expand不会主动的复制数据,只会在有需要的时候才去复制数据,会省略掉复制数据的过程,比较推荐使用
- 维度为1是可以复制的,不为1的话不能复制
- 扩张时,维度上写的是 -1 表示当前维度不扩张
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方式传递的参数代表维度需要拷贝的次数,其实就是原始维度值 * 倍数
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()
转置操作只针对矩阵(适用于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()
维度交换后,如果再使用view进行维度变换,view操作会丢掉维度信息,之后如果需要数据恢复是需要注意原本数据的维度顺序
- 交换维度后,改变了数据的存储方式,所以是不连续的,需要使用 contiguous 将数据变连续再调整维度信息 (view)
- expand:自动扩展
- without copying data 没有拷贝
- Insert 1 dim ahead:从最小的维度开始匹配,如果没有维度的话插入一个新的维度
- Expand dims with size 1 to same size
broadcasting减少了内存消耗,满足数学上的要求,且不需要手动去扩充的需求
Merge split:
- Cat([tensor_1, tensor_2],dim=xx) dim指定在哪个维度上合并
- Stack
- split
- chunk
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()
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()
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()
根据单元 的长度进行拆分:(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()
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()