【问题标题】:What functions or modules require contiguous input?哪些功能或模块需要连续输入?
【发布时间】:2021-12-18 17:59:52
【问题描述】:

据我了解,每当某些函数或模块需要连续张量时,您都需要显式调用 tensor.contiguous()。否则你会得到如下异常:

RuntimeError: invalid argument 1: input is not contiguous at .../src/torch/lib/TH/generic/THTensor.c:231

(例如via.)

哪些功能或模块需要连续输入?是否记录在案?

或者换个说法,什么情况下需要拨打contiguous

例如Conv1d,是否需要连续输入?文档没有提到这一点。当文档没有提到这一点时,这总是意味着它不需要连续输入?

(我记得在 Theano 中,任何获得一些非连续输入的操作,这需要它是连续的,都会自动转换它。)

【问题讨论】:

    标签: python pytorch


    【解决方案1】:

    在通过 source_code 进一步挖掘后,似乎 view 是唯一在传递非连续输入时显式导致异常的函数

    人们会期待any operation using Tensor Views 有可能因非连续输入而失败。实际上,这些功能中的大部分或全部似乎是:

    (a.) 实现支持非连续块(参见下面的示例),即张量迭代器可以处理指向内存中各种数据块的多个指针,可能以牺牲性能为代价,否则

    (b.) 对.contiguous() 的调用包装了操作(在here 中为torch.tensor.diagflat() 显示了一个这样的示例)。 reshape 本质上是 contiguous() 的包装形式 view

    通过扩展,viewreshape 相比的主要优势似乎是当张量意外不连续时显式异常,而代码以性能为代价默默地处理这种差异。

    这个结论基于:

    1. 使用非连续输入测试所有 Tensor View 操作。
    2. 其他感兴趣的非张量视图函数的源代码分析(例如Conv1D,其中包括在所有重要输入情况下都需要调用contiguous)。
    3. 从 pytorch 的设计理念推断为一种简单、有时缓慢、易于使用的语言。
    4. Pytorch Discuss 上交叉发帖。
    5. 对涉及非连续错误的网络报告错误进行了广泛审查,所有这些错误都围绕着对view 的有问题的调用。

    我没有全面测试所有 pytorch 函数,因为有数千个。

    (a.)示例:

    import torch
    import numpy
    import time
    
    # allocation 
    start = time.time()
    test = torch.rand([10000,1000,100])
    torch.cuda.synchronize()
    end = time.time()
    print("Allocation took {} sec. Data is at address {}. Contiguous: 
    {}".format(end - 
    start,test.storage().data_ptr(),test.is_contiguous()))
    
    # view of a contiguous tensor
    start = time.time()
    test.view(-1)
    torch.cuda.synchronize()
    end = time.time()
    print("view() took {} sec. Data is at address {}. Contiguous: 
    {}".format(end - 
    start,test.storage().data_ptr(),test.is_contiguous()))
    
    
    # diagonal() on a contiguous tensor
    start = time.time()
    test.diagonal()
    torch.cuda.synchronize()
    end = time.time()
    print("diagonal() took {} sec. Data is at address {}. Contiguous: 
    {}".format(end - 
    start,test.storage().data_ptr(),test.is_contiguous()))
    
    
    # Diagonal and a few tensor view ops on a non-contiguous tensor
    test = test[::2,::2,::2]    # indexing is a Tensor View op 
    resulting in a non-contiguous output
    print(test.is_contiguous()) # False
    start = time.time()
    test = test.unsqueeze(-1).expand([test.shape[0],test.shape[1],test.shape[2],100]).diagonal()
    torch.cuda.synchronize()
    end = time.time()
    print("non-contiguous tensor ops() took {} sec. Data is at 
    address {}. Contiguous: {}".format(end - 
    start,test.storage().data_ptr(),test.is_contiguous()))
    
    # reshape, which requires a tensor copy operation to new memory
    start = time.time()
    test = test.reshape(-1) + 1.0
    torch.cuda.synchronize()
    end = time.time()
    print("reshape() took {} sec. Data is at address {}. Contiguous: {}".format(end - start,test.storage().data_ptr(),test.is_contiguous()))
    

    以下是输出:

    Allocation took 4.269254922866821 sec. Data is at address 139863636672576. Contiguous: True
    view() took 0.0002810955047607422 sec. Data is at address 139863636672576. Contiguous: True
    diagonal() took 6.532669067382812e-05 sec. Data is at address 139863636672576. Contiguous: True
    False
    non-contiguous tensor ops() took 0.00011277198791503906 sec. Data is at address 139863636672576. Contiguous: False
    reshape() took 0.13828253746032715 sec. Data is at address 94781254337664. Contiguous: True
    

    块 4 中的一些张量视图操作是在非连续输入张量上执行的。该操作运行没有错误,将数据保持在相同的内存地址中,并且比需要复制到新内存地址的操作(例如块 5 中的reshape)运行速度相对更快。因此,这些操作似乎是以一种无需数据副本即可处理非连续输入的方式实现的。

    【讨论】:

    • 我在问我的问题中哪些操作不支持非连续输入。所以你给了viewreshape作为例子。还有什么?这是我的问题。我不是在问不支持多维输入的操作。这一切都有据可查。
    • 答案是任何使用张量视图的东西
    • 另外@Albert, reshape 明确地不需要连续输入,它是一个惰性复制操作,如果可能,它执行与view 相同的功能,否则将数据复制到内存中的新张量
    • 我不明白这个答案。我在询问需要连续输入的操作列表。之前您写道view 需要连续输入。那么这不是真的吗?现在你改变了答案。但它并没有真正回答这个问题。哪些操作、功能或模块需要连续输入?你能举一些例子吗?
    • Pytorch 明确提供了使用张量视图的操作列表,这些操作需要连续输入。完整的功能列表在答案开头的链接中给出。答案的其余部分试图为那些不熟悉 Pytorch 这些方面的人解释对连续张量/张量视图的需求
    【解决方案2】:

    我认为没有完整的列表。这取决于您如何实现张量处理功能。

    如果您查看编写 C++ and CUDA extensions 的教程,您会看到典型的 pytorch CUDA 操作如下所示:

    • 带有torch::Tensor 参数的C++ 接口。此类提供 API 来访问/操作张量数据。
    • 带有float* 参数的CUDA 内核。这些指针直接指向存储张量数据的内存。

    显然,使用指针处理张量中的数据可能比处理张量类的 API 更有效。但最好处理具有连续内存布局(或至少是常规布局)的指针。

    我相信原则上可以使用指针操作数据,即使没有连续的数据,只要给定足够的内存布局信息。但是您必须考虑各种布局,并且代码可能会更加繁琐。

    Facebook 可能有一些技巧可以让一些内置操作在非连续数据上工作(我对此知之甚少),但大多数自定义扩展模块要求输入是连续的。

    【讨论】:

    • 是的,当然,对于所有自定义用户实现,您永远不会知道(尽管如果您将正确的步幅传递给内核并且不直接访问索引,它仍然可以,但是教程不这样做)。但我想知道内置函数。例如。 Conv1d 和许多其他人。那么这只是通过反复试验吗?
    【解决方案3】:

    来自 pytorch 文档:contiguous() → Tensor.返回一个包含与 self 张量相同数据的连续张量。如果 self tensor 是连续的,则此函数返回 self tensor。

    【讨论】:

    • 这不是问题。
    • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 2014-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-22
    • 2020-02-28
    相关资源
    最近更新 更多