Ошибка в рекурсивной функции с Numba в режиме nopython

Я хочу запустить рекурсивную функцию в 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 все еще находится в активной разработке, а набор поддерживаемых функций меняется быстрыми темпами.

MSeifert 08.04.2019 20:28
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
1 522
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Согласно этот список предложений в текущих выпусках:

Recursion support in numba is currently limited to self-recursion with explicit type annotation for the function. This limitation comes from the inability to determine the return type of a recursive call.

Итак, вместо этого попробуйте:

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. Какая у тебя нумба версия?

MSeifert 08.04.2019 20:30

@MSeifert, я только что зашел на веб-сайт numba и на их страницу jupyter «попробуйте онлайн». У меня там работало с аннотациями, но не без. Все я знаю.

cdlane 08.04.2019 21:05

Это интересно спасибо за объяснение. Но это также не работает в режиме nopython.

MSeifert 08.04.2019 22:02
Ответ принят как подходящий

Есть несколько причин, почему этого делать не следует:

  • Как правило, это своего рода подход, который, вероятно, будет быстрее в чистом Python, чем в функции, украшенной numba.
  • Итерация будет проще и, вероятно, быстрее, однако имейте в виду, что объединение кортежей обычно является операцией O(n), даже в numba. Таким образом, общая производительность функции будет O(n**2). Это можно улучшить, используя структуру данных, которая поддерживает добавление O(1), или структуру данных, которая поддерживает предварительное выделение размера. Или просто не используя «циклический» или «рекурсивный» подход.
  • Вы пробовали, что произойдет, если вы пропустите декоратор njit и передадите кортеж, содержащий 6 элементов? (подсказка: он достигнет предела рекурсии, потому что он никогда не выполняет конечное условие рекурсии).

Numba на момент написания 0.43.1 поддерживает только простые рекурсии, когда тип аргументов не меняется между рекурсиями. В вашем случае тип изменяется, вы передаете 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)

большое спасибо за ответ. На самом деле этот код не совсем то, что я хочу запустить, это просто проблемная часть того, что я пытаюсь сделать. исходная проблема состоит в том, чтобы запустить произвольный вложенный цикл по элементам многомерного массива. Поскольку количество циклов может варьироваться, я делал рекурсивные вызовы, каждый из которых входил в следующий цикл и соответственно строил (мульти)индекс.

Integral 09.04.2019 00:08

Все было бы проще, если бы я просто передал кортеж с его окончательным размером, который я могу узнать до запуска цикла, проблема в том, что кортежи неизменяемы, поэтому я не могу присвоить им значения индексов. Вместо кортежей я мог бы использовать массивы, и можно присваивать новые значения, но я не могу использовать массив индексов, скажем, [1,2,0,0,1] для доступа к значению M[1,2, 0,0,1] многомерного M. Также numba не позволяет мне преобразовать массив в кортеж... Я тоже не могу найти решение со списками... кажется, у каждого пути есть небольшая деталь, мешающая мне делать то, что я хочу делать.

Integral 09.04.2019 00:16

Во всяком случае, я уже видел, что чистый python на самом деле быстрее, чем numba для рекурсии, как вы сказали. Это немного разочаровывает, я ожидаю повышения производительности, поскольку numba лучше работает с циклами.

Integral 09.04.2019 00:28

@Integral Не каждый цикл можно оптимизировать с помощью numba, это действительно зависит от операций, которые вы выполняете внутри цикла.

MSeifert 09.04.2019 11:54

@Integral Проблема с преобразованием массива в кортеж в numba заключается в том, что кортежи должны иметь фиксированный размер времени компиляции. Массивы не имеют такого размера (как и списки), поэтому вы не можете создать кортеж из массива. Я также обнаружил, что работа с многомерными массивами и пользовательскими индексами в numba довольно сложна.

MSeifert 09.04.2019 11:57

Я просто пытаюсь создать все возможные кортежи с помощью модуля itertools, а затем могу запустить все в одном цикле. По какой-то причине это было намного хуже, чем рекурсивный подход, даже с numba в режиме nopython. Вы знаете, почему это происходит?

Integral 10.04.2019 01:03

@Integral Это может лучше подходить для новый вопрос, потому что слишком сложно обсуждать это в комментариях, и редактирование этого вопроса (вероятно) сделает ответы недействительными.

MSeifert 10.04.2019 07:57

Другие вопросы по теме