天天看点

tensor 增加维度_tensor 维度变换

operation

view/reshape

squeeze/unsqueeze

transpose/ t / permute

expand/ repeat

1.view/reshape

import torch

a = torch.rand(4, 1, 28, 28)

# 使用rand随机均匀初始化一个4维的tensor

# 在minist中可以理解为load进了4张灰度图片,长宽各为28

a.shape

output:

torch.Size([4, 1, 28, 28])

下面进行view操作:

a.view(4, 28 * 28)

# 4 1 * 28 * 28

output:

tensor([[0.1915, 0.9915, 0.4148, ..., 0.3582, 0.4939, 0.7734],

[0.7373, 0.5476, 0.0908, ..., 0.2784, 0.0220, 0.3247],

[0.6855, 0.1770, 0.6714, ..., 0.3116, 0.5055, 0.1866],

[0.0151, 0.9768, 0.4203, ..., 0.7694, 0.7458, 0.2084]])

(view必须满足物理意义,否则会导致数据的”污染“)

打印shape

a.view(4, 28 * 28).shape

output

torch.Size([4, 784])

b = a.view(4, 784)

# 这个时造成了数据的污染,b.view(4, 28, 28, 1)这样子也等于上面的数值,但是数据的理解不一样了。

数据的存储/维度顺序非常重要

下面这样view会出错:

a.view(4, 783)

ouput:

>RuntimeError: shape '[4, 783]' is invalid for input of size 3136

这是由于前后的size不一致导致的。

2.squeeze v.s squeeze

减少维度(挤压)v.s 增加维度

下面来看一些维度增加的举例:

a = torch.rand(4, 1, 28, 28)

在0维度前增加一个维度:

a.unsqueeze(0).shape

output:

torch.Size([1, 4, 1, 28, 28])

(增加了一个额外的维度,这里多出来的“1”可以理解为1个组)

这里并没有增加数据,而是增加了一个额外的概念 组

a.unsqueeze(-1).shape

# -1是指最后一个维度,这里是在-1之后插入,一般不用负数,正数已经可以覆盖所有的位置

output:

torch.Size([4, 1, 28, 28, 1])

下面这个表格展示了index的位置:

Pos.IDX

1

2

3

4

3

28

28

Neg.IDX

-4

-3

-2

-1

# 使用List来初始化一个维度为0,shape为[2]的tensor

a = torch.tensor([1.2, 2.3])

print(a.shape)

print(a.unsqueeze(1))

print(a.unsqueeze(1).shape)

output:

torch.Size([2])

tensor([[1.2000],

[2.3000]])

torch.Size([2, 1])

print(a.unsqueeze(0))

print(a.unsqueeze(0).shape)

output:

tensor([[1.2000, 2.3000]])

torch.Size([1, 2])

下面来看一个实际的案例,而不是简单的数学的计算

b = torch.rand(32)

# bias

b.shape

f = torch.rand(4, 32, 14, 14)

# 32 是channel

# 现在想累加 f + b,首先把 b 的dim=4,size与 f 相等

b = b.unsqueeze(1).unsqueeze(2).unsqueeze(0)

b.shape

output:

torch.Size([32])

torch.Size([1, 32, 1, 1])

下面再来看看维度删减操作

squeeze

b.shape

现在b的shape:

torch.Size([1, 32, 1, 1])

下面来挤压:

b.squeeze().shape

# squeeze不给参数即能挤压的都挤压,包括dim的size是1的

output:

torch.Size([32])

参数为0时:

b.squeeze(0).shape

output:

torch.Size([32, 1, 1])

这里本来应该挤压掉32的,但是32是不能被挤压得,所以这里按照原来得size输出:

b.squeeze(1).shape

output:

torch.Size([1, 32, 1, 1])

3.expand(改变理解方式,没有增加数据)(推荐用)/ repeat(增加了数据)

(维度扩展,改变shape)

e.p [1, 32, 1, 1] →[4, 32, 4, 32]

expand/expand_as

a = torch.rand(4, 32, 14, 14)

# b的shape是:torch.Size([1, 32, 1, 1])

b.expand(4, 32, 14, 14).shape

output:

torch.Size([4, 32, 14, 14])

调用expand的前提是,①dim一致,②对于原来是1的是可以扩张的,但是原来不为1时会报错

repeat(memory touched)

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

output:

torch.Size([4, 32, 1, 1])

这里的4表示在这个维度上重复拷贝的次数

3. .t(矩阵的转置操作)

a = torch.randn(3, 4)

print(a)

a.t()

output:

tensor([[ 0.5026, 0.2715, -0.0155, 0.9671],

[-0.0519, -0.2210, 1.0061, 0.0739],

[-0.9153, 0.2358, 1.4426, 0.2461]])

tensor([[ 0.5026, -0.0519, -0.9153],

[ 0.2715, -0.2210, 0.2358],

[-0.0155, 1.0061, 1.4426],

[ 0.9671, 0.0739, 0.2461]])

转置操作只适用于2d的tensor

transport

(矩阵的维度交换操作)

a = torch.rand(4, 3, 32, 32)

a2 = a.transpose(1, 3).contiguous().view(4, 3*32*32).view(4,32,32,3).transpose(1, 3)

print(a2.shape)

torch.all(torch.eq(a, a2))

output:

torch.Size([4, 3, 32, 32])

tensor(True)

view会导致维度顺序关系变复杂,所以需要人为跟踪。

permute

b = torch.rand(4, 3, 28, 32)

# [b, c, h, w]

b.transpose(1, 3).shape

# [b, w, h, c]

# 这时列在前了,需要再交换一次

b.transpose(1, 3).transpose(1, 2).shape

# [b, h, w, c]

# 而使用permute就会简单很多

b.permute(0, 2, 3, 1).shape

output:

torch.Size([4, 28, 32, 3])