一.前言
在深度学习中,张量的的形状操作是十分重要的,主要是掌握reshape, transpose, permute, view, contigous, squeeze, unsqueeze等函数使⽤。
在我们后⾯搭建⽹络模型时,数据都是基于张量形式的表示,⽹络层与层之间很多都是以不同的 shape 的 ⽅式进⾏表现和运算,我们需要掌握对张量形状的操作,以便能够更好处理⽹络各层之间的数据连接。
二.reshape函数的用法
reshape 函数可以在保证张量数据不变的前提下改变数据的维度,将其转换成指定的形状,在后⾯的神经⽹络学习时,会经常使⽤该函数来调节数据的形状,以适配不同⽹络层之间的数据传递。
import torch
import numpy as np
def test():
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
# 1. 使⽤ shape 属性或者 size ⽅法都可以获得张量的形状
print(data.shape, data.shape[0], data.shape[1])
print(data.size(), data.size(0), data.size(1))
# 2. 使⽤ reshape 函数修改张量形状
new_data = data.reshape(1, 6)
print(new_data.shape)
if __name__ == '__main__':
test()
结果展示:
torch.Size([2, 3]) 2 3
torch.Size([2, 3]) 2 3
torch.Size([1, 6])
三.transpose和permute函数的使用
transpose 函数可以实现交换张量形状的指定维度, 例如: ⼀个张量的形状为 (2, 3, 4) 可以通过 transpose 函 数把 3 和 4 进⾏交换, 将张量的形状变为 (2, 4, 3)
permute 函数可以⼀次交换更多的维度。
import torch
import numpy as np
def test():
data = torch.tensor(np.random.randint(0, 10, [3, 4, 5]))
print('data shape:', data.size())
# 1. 交换1和2维度
new_data = torch.transpose(data, 1, 2)
print('data shape:', new_data.size())
# 2. 将 data 的形状修改为 (4, 5, 3)
new_data = torch.transpose(data, 0, 1)
new_data = torch.transpose(new_data, 1, 2)
print('new_data shape:', new_data.size())
# 3. 使⽤ permute 函数将形状修改为 (4, 5, 3)
new_data = torch.permute(data, [1, 2, 0])
print('new_data shape:', new_data.size())
if __name__ == '__main__':
test()
结果展示:
data shape: torch.Size([3, 4, 5])
data shape: torch.Size([3, 5, 4])
new_data shape: torch.Size([4, 5, 3])
new_data shape: torch.Size([4, 5, 3])
四.view 和 contigous 函数的用法
view 函数也可以⽤于修改张量的形状,但是其⽤法⽐较局限,只能⽤于存储在整块内存中的张量。在 PyTorch 中,有些张量是由不同的数据块组成的,它们并没有存储在整块的内存中,view 函数⽆法对这样 的张量进⾏变形处理,例如: ⼀个张量经过了 transpose 或者 permute 函数的处理之后,就⽆法使⽤ view 函数进⾏形状操作。
import torch
import numpy as np
def test():
data = torch.tensor([[10, 20, 30], [40, 50, 60]])
print('data shape:', data.size())
# 1. 使⽤ view 函数修改形状
new_data = data.view(3, 2)
print('new_data shape:', new_data.shape)
# 2. 判断张量是否使⽤整块内存
print('data:', data.is_contiguous()) # True
# 3. 使⽤ transpose 函数修改形状
new_data = torch.transpose(data, 0, 1)
print('new_data:', new_data.is_contiguous()) # False
# new_data = new_data.view(2, 3) # RuntimeError
# 需要先使⽤ contiguous 函数转换为整块内存的张量,再使⽤ view 函数
print(new_data.contiguous().is_contiguous())
new_data = new_data.contiguous().view(2, 3)
print('new_data shape:', new_data.shape)
if __name__ == '__main__':
test()
data shape: torch.Size([2, 3])
new_data shape: torch.Size([3, 2])
data: True
new_data: False
True
new_data shape: torch.Size([2, 3])
五.squeeze和unsqueeze函数的用法
squeeze 函数⽤删除 shape 为 1 的维度,unsqueeze 在每个维度添加 1, 以增加数据的形状。
import torch
import numpy as np
def test():
data = torch.tensor(np.random.randint(0, 10, [1, 3, 1, 5]))
print('data shape:', data.size())
# 1. 去掉值为1的维度
new_data = data.squeeze()
print('new_data shape:', new_data.size()) # torch.Size([3, 5])
# 2. 去掉指定位置为1的维度,注意: 如果指定位置不是1则不删除
new_data = data.squeeze(2)
print('new_data shape:', new_data.size()) # torch.Size([3, 5])
# 3. 在2维度增加⼀个维度
new_data = data.unsqueeze(-1)
print('new_data shape:', new_data.size()) # torch.Size([3, 1, 5, 1])
if __name__ == '__main__':
test()
data shape: torch.Size([1, 3, 1, 5])
new_data shape: torch.Size([3, 5])
new_data shape: torch.Size([1, 3, 5])
new_data shape: torch.Size([1, 3, 1, 5, 1])
六.总结
本节学习了经常使⽤的关于张量形状的操作,我们⽤到的主要函数有:
1. reshape 函数可以在保证张量数据不变的前提下改变数据的维度.
2. transpose 函数可以实现交换张量形状的指定维度, permute 可以⼀次交换更多的维度.
3. view 函数也可以⽤于修改张量的形状, 但是它要求被转换的张量内存必须连续,所以⼀般配合 contiguous 函数使⽤.
4. squeeze 和 unsqueeze 函数可以⽤来增加或者减少维度.