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

1. tensor的数据结构

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

大部分情况下一个tensor有独立的头信息区和storage,但pytorch中也可以多个不同的tensor共享一个storage,这么做是为了节省内存
也正因如此,从一个已有的tensor创建一个新的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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容