【问题标题】:Error in recursive function with Numba in nopython mode在 nopython 模式下使用 Numba 的递归函数出错
【发布时间】:2019-08-29 20:47:42
【问题描述】:

我想在 Numba 中运行递归函数,使用 nopython 模式。直到现在我只得到错误。这是一个非常简单的代码,用户给出一个少于五个元素的元组,然后该函数创建另一个元组,并在元组中添加一个新值(在本例中为数字 3)。重复此操作,直到最终元组的长度为 5。由于某种原因,这不起作用,不知道为什么。

@njit
def tup(a):
    if len(a) == 5:
        return a
    else:
        b = a + (3,)
        b = tup(b)
        return b

例如,如果a = (0,1),我希望最终结果是元组(0,1,3,3,3)

编辑:我正在使用 Numba 0.41.0,我得到的错误是内核死了,'内核似乎已经死了。它将自动重启。'

【问题讨论】:

  • 请不要忘记显示您遇到的错误类型。包含 numba 版本也可能会有所帮助,因为 numba 仍在积极开发中,并且支持的功能集正在快速发展。

标签: python python-3.x recursion tuples numba


【解决方案1】:

根据当前版本中的this list of proposals

numba 中的递归支持目前仅限于自递归 函数的显式类型注释。这个限制来自 无法确定递归调用的返回类型。

所以,试试吧:

from numba import jit

@jit()
def tup(a:tuple) -> tuple:
    if len(a) == 5:
        return a

    return tup(a + (3,))

print(tup((0, 1)))

看看这是否更适合你。

【讨论】:

  • 运行时真的有效吗?我只是尝试运行代码,至少在我的机器上只产生 StackOverflow。你的 numba 版本是什么?
  • @MSeifert,我刚刚去了 numba 网站和他们的“在线试用”jupyter 页面。它在注释中对我有用,但并非没有。我所知道的。
  • 这很有趣,感谢您的解释。但它在 nopython 模式下也失败了。
【解决方案2】:

您不应该这样做的原因有几个:

  • 这通常是一种在纯 Python 中可能比在 numba 修饰函数中更快的方法。
  • 迭代会更简单并且可能更快,但是请注意连接元组通常是O(n) 操作,即使在 numba 中也是如此。所以函数的整体性能将是O(n**2)。这可以通过使用支持O(1) 附加的数据结构或支持预分配大小的数据结构来改进。或者干脆不使用“循环”或“递归”方法。
  • 您是否尝试过如果省略 njit 装饰器并传入包含 6 个元素的元组会发生什么情况? (提示:它将达到递归限制,因为它永远不会满足递归的结束条件)。

在编写 0.43.1 时,Numba 仅在参数类型在递归之间不发生变化时支持简单递归。在您的情况下,类型确实发生了变化,您传入tuple(int64 x 2),但递归调用尝试传入tuple(int64 x 3),这是一种不同的类型。奇怪的是,它在我的电脑上遇到了StackOverflow——这似乎是 numba 中的一个错误。

我的建议是使用这个(没有 numba,没有递归):

def tup(a):
    if len(a) < 5:
        a += (3, ) * (5 - len(a))
    return a

这也返回了预期的结果:

>>> tup((1,))
(1, 3, 3, 3, 3)
>>> tup((1, 2))
(1, 2, 3, 3, 3)

【讨论】:

  • 非常感谢您的回答。事实上,这段代码并不是我想要运行的,它只是我正在尝试做的有问题的部分。最初的问题是在多维数组的条目上运行任意嵌套循环。由于循环的数量可能会有所不同,因此我进行了递归调用,每个调用都进入下一个循环并相应地构造(多)索引。
  • 如果我只是传递具有最终大小的元组,一切都会更简单,我可以在开始循环之前知道,问题是元组是不可变的,所以我不能分配索引的值进入他们。我可以使用数组代替元组,并且可以分配新值,但我不能使用索引数组,例如 [1,2,0,0,1] 来访问值 M[1,2, 0,0,1] 的多维 M。此外 numba 不允许我将数组转换为元组......我也无法找到带有列表的解决方案......似乎每种方式都有一些细节阻止我做我想做的事。
  • 无论如何,正如你所说,我已经看到纯 python 在递归方面实际上比 numba 快。这有点令人失望,我希望能获得性能,因为 numba 的循环性能更好。
  • @Integral 并非每个循环都可以使用 numba 进行优化,这实际上取决于您在循环内执行的操作。
  • @Integral numba 中数组-元组转换的问题是因为元组需要具有固定的编译时间大小。数组没有那个大小(列表也没有),所以你不能从一个数组创建一个元组。我还发现在 numba 中使用多维数组和自定义索引非常复杂。
猜你喜欢
  • 1970-01-01
  • 2020-06-15
  • 1970-01-01
  • 2017-06-21
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 2017-08-08
  • 2020-09-15
相关资源
最近更新 更多