view和reshape的区别
view
view操作主要是返回一个新的shape的视图,主要是改变原存储数据的索引方式,原地改变原存储区而不申请新的空间,前提是数据是连续的。否则要先使用contiguous()方法开辟新的存储区将其转化为连续的。
reshape
view可以做的,其实reshape都可以做。reshape对于如果是连续的数据那么就创建一个新的视图,否则就申请新的空间使其数据满足新的shape。
那么如何区分是否连续呢?
首先,明确一点,无论是python还是C or C++ or Java,其申请的数组数据在内存中都是线性分布的。
tensor中的size
你可以理解为tensor中每个维度的长度
tensor中的stride
对于pytorch中的tensor来说,其在信息区存储了stride变量,这个变量记录的是跳转至下一个维度需要跨多少步,与卷积操作的stride不同,注意区分。
连续条件:
满足以下条件则说明tensor是连续的,可以进行view操作,不必开辟新的空间。
\[stride[i]=stride[i+1] \times size[i+1]
\]
比如说二维的一个5行4列的一个向量,那么stride=[4,1],也就是说从第某行到下一行需要跨4步才能到下一行的同一列的位置,而从某一列到下一列只需要跨越一步即可。
举个例子:
辅助理解tensor里的stride
import torch
a = torch.arange(9).reshape(3, 3) # 初始化张量a
b = a.permute(1, 0) # 对a进行转置
print('struct of a:\n', a)
print('size of a:', a.size()) # 查看b的shape
print('stride of a:', a.stride()) # 查看b的stride
print('struct of b:\n', b)
print('size of b:', b.size()) # 查看b的shape
print('stride of b:', b.stride()) # 查看b的stride
########### 运行结果 ###########
struct of a:
tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
size of a: torch.Size([3, 3])
stride of a: (3, 1) # 注:满足连续性条件
struct of b:
tensor([[0, 3, 6],
[1, 4, 7],
[2, 5, 8]])
size of b: torch.Size([3, 3])
stride of b: (1, 3) # 注:此时不满足连续性条件!!!
如上图所示,对tensor进行转置或是其他改变shape的操作,若是使得stride和size与原tensor不兼容,即不满足连续条件。
不满足连续如何使用view呢?
答案在第一节已经说了,使用contiguous()即可
such as:
a.contiguous().view(...)