【Deep Learning with PyTorch 中文手册】(八)Tensors and storages
Tensors and storages
在本节中,我们将开始探讨张量存储的内部实现。张量的值被分配在连续的内存块中,由torch.Storage管理。一块存储指的是存储数据的一维数组,例如包含给定类型(可能是float或int32)数值的连续内存块。PyTorch张量就是使用这种存储方式,可以通过使用偏移量和维度的单位步长将其索引到该存储中。
多个张量可以索引到同一存储,即使它们索引到数据的方式不同。下图中的例子可以很好地对其说明。实际上,当在最后一行访问points[0]时,得到的是另一个张量,该张量指向的存储与points张量的部分存储相同,但不是二者的存储完全相同,并且二者的维度也不一样(前者是1D,points是2D)。底层的内存仅分配一次,因此无论实例化的Storage对象管理的数据维度尺寸如何,都可以快速地创建指向该数据的其他张量。(绕来绕去的,就是想表达内存可以共用)
接下来,我们将在实际中使用2D点来演示如何索引到内存存储。使用.storage属性可以访问给定张量的内存存储。
>>> import torch
>>> points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
>>> points.storage()
1.0
4.0
2.0
1.0
3.0
5.0
[torch.FloatStorage of size 6]
即使定义张量时指明维度是三行两列,但底层的存储却是大小为6的连续数组。从这个意义上讲,张量知道如何将一对索引转换为内存存储中的某个位置。
我们可以手动索引到某个内存存储:
>>> points_storage = points.storage()
>>> points_storage[0]
1.0
>>> points.storage()[1]
4.0
我们无法使用两个索引值来索引2D张量的存储,这是因为存储器的布局始终是一维的,而与指向该内存存储的张量的维度无关。
现在读者应该能够理解,如果改变了内存存储中的值,那么相应的所有索引到该存储的张量的值都会改变。
>>> points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
>>> points_storage = points.storage()
>>> points_storage[0] = 2.0
>>> points
tensor([[2., 4.],
[2., 1.],
[3., 5.]])
我们不会经常直接访问某个具体的底层存储,但是理解张量和底层存储之间的关系对于以后理解张量的某些操作会很有帮助。如果读者想要编写出高效的PyTorch代码的话,请务必牢记这一点。