Deep-Learning-with-PyTorch-3.8.1 其他张量存储的视图

3.8.1 其他张量存储的视图

我们可以通过提供相应的索引来获得张量中的第二个点:

# In[21]:
points = torch.tensor([[4.0, 1.0], [5.0, 3.0], [2.0, 1.0]])
second_point = points[1]
second_point.storage_offset()

# Out[21]:
2

# In[22]:
second_point.size()

# Out[22]:
torch.Size([2])

结果张量在存储中的偏移量为2(因为我们需要跳过第一个点,该点有两个项目),并且由于张量是一维的,因此size是包含一个元素的Size类的实例。 请务必注意,这与张量对象的shape属性中包含的信息相同:

# In[23]:
second_point.shape

# Out[23]:
torch.Size([2])

步幅是一个元组,指示当索引在每个维度上增加1时必须跳过的存储中元素的数量。 例如,我们的点张量的步幅为(2,1):

# In[24]:
points.stride()

# Out[24]:
(2, 1)

在2D张量中访问元素i,j导致访问存储器中的storage_offset + stride [0] * i + stride [1] * j元素。 偏移量通常为零; 如果此张量是为容纳更大张量而创建的存储的视图,则偏移量可能为正值。

张量和存储之间的这种间接性使某些操作变得不昂贵,例如转置张量或提取子张量,因为它们不会导致内存重新分配。 相反,它们包括分配一个新的Tensor对象,该对象的大小,存储偏移或跨度的值不同。

当我们索引特定点并看到存储偏移量增加时,我们已经提取了一个张量。 让我们来看看尺寸和跨度如何变化:

# In[25]:
second_point = points[1]
second_point.size()

# Out[25]:
torch.Size([2])

# In[26]:
second_point.storage_offset()

# Out[26]:
2

# In[27]:
second_point.stride()

# Out[27]:
(1,)

底线是,正如我们所期望的那样,次张量具有较小的维数,同时仍索引与原始点张量相同的存储。 这也意味着更改次张量将对原始张量产生副作用:

# In[28]:
points = torch.tensor([[4.0, 1.0], [5.0, 3.0], [2.0, 1.0]])
second_point = points[1]
second_point[0] = 10.0
points

# Out[28]:
tensor([[ 4.,  1.],
        [10.,  3.],
        [ 2.,  1.]])

这可能并不总是理想的,因此我们最终可以将次张量克隆为新的张量:

# In[29]:
points = torch.tensor([[4.0, 1.0], [5.0, 3.0], [2.0, 1.0]])
second_point = points[1].clone()
second_point[0] = 10.0
points

# Out[29]:
tensor([[4., 1.],
        [5., 3.],
        [2., 1.]])

你可能感兴趣的