Pytorch tensor在内存中的存储/存储空间的连续性(contiguous&channel last memory format&tensor.stride&storage&offset

判断tensor的内存是否连续

x.is_contiguous()

转置操作会改变tensor的内存连续性. 还有permute(), transpose(), expand(), narrow()等

       我们也许都知道,Python 为了节省内存,很多操作都是不会重新分配地址的,而是在原地址上进行,这一特性在我使用 numpy 的时候就深刻的感受到了,如果想确保分配一个新的地址,需要使用 copy 或者 clone 等操作。而 Pytorch 与 numpy 一脉相承 (这里需要说一下, Pytorch 的很多操作我们都可以在 numpy 里面找到对应,就像王者荣耀和英雄联盟的关系),很多操作都是在原地址上进行的。执行 transpose 操作的时候系统就不会另外分配内存,所以示例中的 a 和 a.t() 是共用一块内存的,只不过读取内存的顺序有所不同。因此,对 a 来说,数据是按维度存储在内存里的,但对 a_t 来说,它的维度改变了,数据存的方式却并没有改变,这就解释了为什么 a 是 contiguous,而 a_t 不是 contiguous。再解释对 a_t 使用 tensor.contiguous(),它的作用是为 a_t 申请一块新的内存,并让数据按照 a_t 的维度进行存储。它们之间的差别可以通过读取 tensor 的 stride 来区分.
 

也即有些tensor并不是占用一整块内存,而是由不同的数据块组成

tensor在内存中的存储

      我们输入一个格式为 (N, C, H, W) 的 tensor,一般来说,系统会先沿着 W 存储,然后再沿着 H 存储,依次进行,这时候的 tensor 是具有 contiguous 特性的。但是我们也可以让这个 tensor 以 channels_last 的方式进行存储,先沿着 C 存储,然后再沿着 W, H, N 依次存储,但以这种方式存储的 tensor 不是 contiguous 的
 

一个[2,3,4,4]的tensor

默认的contiguous的存储方式在内存中是这么存的

 而channels last memory format是这么存的(channels last memory format只用于4D的tensor)

channels last memory format有时性能会比contiguous好,可参考(beta) Channels Last Memory Format in PyTorch — PyTorch Tutorials 1.11.0+cu102 documentation

将tensor从contiguous到channel last memory foramt

x1 = x.contiguous(memory_format=torch.channels_last)

Storage

tensor中的值是存储在连续的内存块中的,由torch.Storage实例管理着。一个storage即是一个一维的向量。

多个不同的tensor可以存储在同一个storage中,只是对数据的索引不同,如下图,一个2行3列的tensor和3行2列的tensor的值都存储在同一个storage中,其中storage中索引为0位置存储着两个tensor的第一行第一列的值4。正因如此,当从一个已有的Tensor创建一个新的tensor时总能很快,因为其在内存中只会创建一次。

获取tensor的storage

import torch
# 3*2的tensor
points = torch.tensor([[1.0, 4.0],[2.0, 1.0],[3.0, 5.0]])
points.storage()


对storage进行索引

points_storage = points.storage()
points_storage[0]


注意:storage永远是一维的数组,任何维度的tensor都存储在一维的storage中。

更改storage的值

tensor的值存储在storage中,若改变了storage的值,势必会改变tensor的值。

points_storage = points.storage()
points_storage[0] = 2.0
print(points)

可见,改变了points的storage中索引为0的值,同时也改变了points中第一行第一列的值。

现在,你知道了tensor的值时存储在storage中,但你肯定会疑惑,我们如何知道在tensor中的某个值,存储在storage的什么位置,也就是说如何知道storage时如何存储tensor的。Pytorch中提供了3个信息来连接tensor与storage: size, storage offset, strides。

storage offset

storage offset是指tensor的第一个元素在storage中的位置,再来看之前的例子

取出points中的一维,生成一个新的tensor points_second, 注意新的tensor与points仍然是同一个storage.

points_second的offset为2表示 它的第一个元素在storage中位置为索引为2的地方。
 

 x.stride()

stride是在指定维度dim中从一个元素跳到下一个元素所必需的步长。当没有参数传入时,返回所有步长的元组。否则,将返回一个整数值作为特定维度dim中的步长。

 x.stride(0)是5表示红色跳到黄色要5个

 x.stride(1)是1表示红色跳到黄色要1个

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值