tensor的数据结构、storage()、stride()、storage

您所在的位置:网站首页 stowage和storage tensor的数据结构、storage()、stride()、storage

tensor的数据结构、storage()、stride()、storage

#tensor的数据结构、storage()、stride()、storage| 来源: 网络整理| 查看: 265

1. tensor的数据结构

pytorch中一个tensor对象分为头信息区(Tensor)和存储区(Storage)两部分。 头信息区主要保存tensor的形状(size)、步长(stride)、数据类型(type)等信息;而真正的data(数据)则以连续一维数组的形式放在存储区,由torch.Storage实例管理着。 注意:storage永远是一维数组,任何维度的tensor的实际数据都存储在一维的storage中。

大部分情况下一个tensor有独立的头信息区和storage,但也可以多个不同的tensor共享一个storage,这么做是为了节省内存空间。也正因如此,当从一个已有的tensor创建一个新的tensor时总能很快,因为其在内存中只会创建一次。如下图所示:

tensor结构.png

2. storage() 2.1 获取tensor的storage >>>a = torch.tensor([[1.0, 4.0],[2.0, 1.0],[3.0, 5.0]]) >>>a.storage() 1.0 4.0 2.0 1.0 3.0 5.0 [torch.FloatStorage of size 6] 2.2 对storage进行索引取值 >>>a_storage = a.storage() >>>a_storage[2] #获取第三个值 2.0 2.3 更改storage的值

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

>>>a_storage[0]=100 #改变storage的第1个值 >>>print(a.storage()) >>>print(a) 100.0 4.0 2.0 1.0 3.0 5.0 [torch.FloatStorage of size 6] tensor([[100., 4.], [ 2., 1.], [ 3., 5.]]) 2.4 tensor的id()和tensor.storage的id()

注意:当一个tensor创建后,id(tensor)固定不变(这没毛病);但id(tensor.storage)每次执行都会变化(这就有点诡异)★★★★,原因还不清楚。

#只运行一次 >>>a = torch.tensor([1,2]) #多次运行 >>>print(id(a)) >>>print(id(a.storage())) 2638892189312 2638989250912 2638892189312 2638989251056 2638892189312 2638989153376 2.5 多个tensor共用storage(判断多个tensor是否共用一个storage) 2.5.1 创建三个tensor(注意,只运行一次)

新建三个tensor a、b、c,其中b和c是在a的基础上创建的,事实上这三者共用了一个storage。

>>>a = torch.tensor([[1,2,3],[4,5,6]]) >>>b = a.view(3,2) >>>c = a[:,1] >>>print(a) tensor([[1, 2, 3], [4, 5, 6]]) >>>print(b) tensor([[1, 2], [3, 4], [5, 6]]) >>>print(c) tensor([2, 5]) 2.5.2 利用id(tensor)获取tensor头信息区地址(不能判断是否共用storage)

id(tensor)得到的是tensor“头信息区”的地址,任何不同的tensor,其头信息区是不一样的,因此这里得到的三个不同的结果。 当tensor创建后,id(tensor)固定不变。

>>>print(id(a)) >>>print(id(b)) >>>print(id(c)) 2638851940160 2638874315168 2638982342992 2.5.3 查看三个tensor的storage(不能判断是否共用storage)

虽然结果是一样的(但这还不能说是共用同一个storage)。 这里也可以看出,张量c虽然只有2个元素,但其storage依然是完整的1、2、3、4、5、6。这说明并没有给张量c独立创建storage,而是共享了a的storage。 特别注意:tensor的元素和他的storage的元素是不一定相同的。

>>>print(a.storage()) >>>print(b.storage()) >>>print(c.storage()) 1 2 3 4 5 6 [torch.LongStorage of size 6] 1 2 3 4 5 6 [torch.LongStorage of size 6] 1 2 3 4 5 6 [torch.LongStorage of size 6] 2.5.4 利用tensor.data_ptr()查看tensor的首元素的地址(不能判断是否共用storage)

从前面可知a和b的首元素都是1,因此其首元素地址相同;而c的首元素是2,显然首元素地址与a和b是不一样。 多次运行代码,结果不变。

>>>print(a.data_ptr()) >>>print(b.data_ptr()) >>>print(c.data_ptr()) 2638924337600 2638924337600 2638924337608 2.5.5 利用tensor.storage.data_ptr()查看storage的首元素的地址(可以判断是否共用storage★★)

tensor.storage().data_ptr()返回的是storage的首元素地址,如果他们相同,则肯定是同一个storage。

>>>print(a.storage().data_ptr()) >>>print(b.storage().data_ptr()) >>>print(c.storage().data_ptr()) 2638924337600 2638924337600 2638924337600 2.5.6 利用id(tensor.storage())获取storage地址(不能判断是否共用storage)

这条最奇怪! 根据前面我们已经知道,a、b、c共用storage,因此理论上id(tensor.storage())的结果是一样的,但实际上三者结果不一样,更奇怪的是每次运行都变化(网上很多例子都说这里三者是相同的,不知道是pytorch后面的版本发生了变化,还是啥原因)。

>>>print(id(a.storage())) >>>print(id(b.storage())) >>>print(id(c.storage())) 第一次运行结果 2638986051440 2638986049856 2638986050432 第二次运行结果 2638986050912 2638986047696 2638986048944 2.5.7 共用storage时,一个变,全部变 >>>c[0]=100 #从tensor改变某个元素 >>>print(a) >>>print(b) >>>print(c) tensor([[ 1, 100, 3], [ 4, 5, 6]]) tensor([[ 1, 100], [ 3, 4], [ 5, 6]]) tensor([100, 5]) >>>b.storage()[3]=-100 #从storage改变某个元素 >>>print(a) >>>print(b) >>>print(c) tensor([[ 1, 100, 3], [-100, 5, 6]]) tensor([[ 1, 100], [ 3, -100], [ 5, 6]]) tensor([100, 5]) 3. stride()

stride是在指定维度(dim)中从一个元素跳到紧邻下一个元素所必需的步长。当没有参数传入时,stride()返回由每个维度步长组成的一个元组。如果有整数参数传入,则返回该整数指定的维度的步长。 注意:前面讲过,pytorch中tensor的实际数据在内存中是按照行优先连续存储的storage。stride的计算也是按照storage存储的位置进行计算。 tensor 连续情况: 如下例中,tensor a总共有0和1两个dim。 沿着dim0(即纵向),从一个元素跳到下一个元素(如从4到7)要经过2、5、7,三个元素; 沿着dim1(即横向),从一个元素跳到下一个元素(如从4到2)只经过2,一个元素。

stride1.jpg

>>>a = torch.tensor([[4,2,5],[7,6,9]]) >>>print(a) tensor([[4, 2, 5], [7, 6, 9]]) >>>print(a.storage()) 4 2 5 7 6 9 [torch.LongStorage of size 6] >>>print(a.stride()) (3, 1) >>>print(a.stride(0)) 3 >>>print(a.stride(1)) 1

tensor 不连续情况: 如下例中,b是a的转置,则b是不连续的。 沿着dim0(即纵向),从一个元素跳到下一个元素(如从4到2)要经过2,一个元素; 沿着dim1(即横向),从一个元素跳到下一个元素(如从4到7)只经过2、5、7,三个元素。

stride2.jpg >>>a = torch.tensor([[4,2,5],[7,6,9]]) >>>b = a.t() >>>print(b) >>>print(b.storage()) >>>print(b.stride()) tensor([[4, 7], [2, 6], [5, 9]]) 4 2 5 7 6 9 [torch.LongStorage of size 6] (1, 3) 4.storage_offset()

返回tensor的第一个元素与其storage的第一个元素的偏移量。 前面已经说过一个tensor的元素和他的storage的元素不一定完全相同(共享别人的storage)。 下例中a的第一个元素是3,a的storage的第一个元素也是3,因此其storage_offset是0; b的第一个元素是5,而b的storage的第一个元素还是3,从3到5的storage_offset是2。

>>>a = torch.tensor([[3,2,5],[7,6,9]]) >>>print(a) tensor([[3, 2, 5], [7, 6, 9]]) >>>print(a.storage()) 3 2 5 7 6 9 [torch.LongStorage of size 6] >>>print(a.storage_offset()) 0 >>>b =a[:,2] #在a的基础上生成 >>>print(b) tensor([5, 9]) >>>print(b.storage()) 3 2 5 7 6 9 [torch.LongStorage of size 6] >>>print(b.storage_offset()) 2


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3