【PyTorch】关于张量的连续性(contiguous)

文章目录

    • 引入:`view`和`reshape`有什么区别
    • 问题1:什么叫满足连续性的张量
    • 问题2:如何判断一个张量是否满足连续性条件
    • 问题3:为什么有些操作需要连续的张量
    • 方法1:不连续的张量转成连续张量
    • 问题4:为什么`reshape`可能会返回一个视图或者一个拷贝

引入:viewreshape有什么区别

view返回的是视图,而reshape一般返回拷贝(取决于原始张量的存储方式)

视图:共享底层数据

view只能用于满足连续性张量的视图

问题1:什么叫满足连续性的张量

连续性条件的含义是,张量底层一维数组元素的存储顺序与张量按行优先一维展开的元素顺序是否一致。

>>> x = torch.arange(12).reshape(3,4)
>>> x
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])

这个张量是连续的,因为它的底层数据的存储顺序是[0, 1, 2, … , 11],与它按行优先一维展开的顺序相同。

问题2:如何判断一个张量是否满足连续性条件

  1. y.is_contiguous()True说明连续

  2. y.stride(),如果stride与y的形状不匹配,说明不连续

    例如

    >>> x = torch.arange(6).reshape(2,3)
    >>> x
    tensor([[0, 1, 2],
            [3, 4, 5]])
    >>> x.stride()
    (3, 1)
    >>> y = x.transpose(0,1)  # 转置之后不再满足连续性
    >>> y
    tensor([[0, 3],
            [1, 4],
            [2, 5]])
    >>> y.is_contiguous()
    False
    >>> y.stride()
    (1, 3)
    

    y按行展开的stride应该是(2, 1),所以y不连续(不满足问题1)

问题3:为什么有些操作需要连续的张量

因为有些操作在底层实现的时候,需要按照一定的顺序访问或修改张量的元素,而不连续的张量会导致这些操作变得复杂或低效。

回到引入,为什么view只能用于满足连续性张量的视图?

因为它的作用是在不改变底层数据的情况下,使用新的形状查看张量。如果张量不是连续的,那么它的底层数据的存储顺序与它按行优先一维展开的顺序不同,这样就无法用一个新的步长来实现形状的变化

方法1:不连续的张量转成连续张量

接着上一个代码段,调用contiguous()函数即可

>>> z = y.contiguous()  # 将不连续张量y转成连续张量
>>> z
tensor([[0, 3],
        [1, 4],
        [2, 5]])
>>> z.is_contiguous()  # z连续
True
>>> z.stride()
(2, 1)

问题4:为什么reshape可能会返回一个视图或者一个拷贝

reshape 会根据原始张量的内存布局来决定是否可以通过修改步长来实现形状的变化,如果可以,返回视图,否则返回拷贝

仍以上面的y为例,下面是返回拷贝的情况

>>> y
tensor([[0, 3],
        [1, 4],
        [2, 5]])
>>> y.is_contiguous()  # y不连续
False
>>> z = y.reshape(2, 3)  # 返回拷贝
>>> z
tensor([[0, 3, 1],
        [4, 2, 5]])
>>> z.is_contiguous()  # z连续
True
>>> y.stride()  # y不连续
(1, 3)
>>> z.stride()  # z连续
(3, 1)

你可能感兴趣的:(Python,pytorch,python,机器学习,深度学习,人工智能)