Отправка numba по типу

Я хотел бы отправить тип второго аргумента в функции в numba, но мне это не удалось.

Если это целое число, то должен быть возвращен вектор, если он сам является массивом целых чисел, то должна быть возвращена матрица.

Первый код не работает

@njit
def test_dispatch(X, indices):
    if isinstance(indices, nb.int64):
        ref_pos = np.empty(3, np.float64)
        ref_pos[:] = X[:, indices]
        return ref_pos
    elif isinstance(indices, nb.int64[:]):
        ref_pos = np.empty((3, len(indices)), np.float64)
        ref_pos[:, :] = X[:, indices]
        return ref_pos

а второй, с else, так и есть.

@njit
def test_dispatch(X, indices):
    if isinstance(indices, nb.int64):
        ref_pos = np.empty(3, np.float64)
        ref_pos[:] = X[:, indices]
        return ref_pos
    else:
        ref_pos = np.empty((3, len(indices)), np.float64)
        ref_pos[:, :] = X[:, indices]
        return ref_pos

Я предполагаю, что проблема в объявлении типа через nb.int64[:], но по-другому я не могу заставить его работать. У вас есть идея?

Обратите внимание, что этот вопрос относится к numba>=0.59. generated_jit устарел в более ранних версиях и фактически удален из версии 0.59 и далее.

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам не следует использовать isinstance в такой функции JIT, а вместо этого используйте @overload ( @generated_jit был старым устаревшим способом сделать это), который специально создан для этой цели. Это позволяет Numba генерировать код быстрее, поскольку для каждого случая компилируется только часть функции, а не весь случай для каждой специализации. Более того, isinstance является экспериментальным, как указано Numba в предупреждении при выполнении вашего первого кода (предупреждения выдаются, чтобы пользователи могли их прочитать ;)).


Используя новый метод @overload

Начиная с Numba 0.59, вместо него необходимо использовать перегрузку:

import numba as nb
import numpy as np

def test_dispatch_scalar(X, indices):
    ref_pos = np.empty(3, np.float64)
    ref_pos[:] = X[:, indices]
    return ref_pos

def test_dispatch_vector(X, indices):
    ref_pos = np.empty((3, len(indices)), np.float64)
    ref_pos[:, :] = X[:, indices]
    return ref_pos

# Pure-python fallback implementation
def test_dispatch_impl(X, indices):
    if isinstance(indices, (int, np.integer)):
        return test_dispatch_scalar(X, indices)
    elif isinstance(indices, np.ndarray) and indices.ndim == 1 and np.issubdtype(indices.dtype, np.integer):
        return test_dispatch_vector(X, indices)
    else:
        assert False # Unsupported

# Numba-specific overload
@nb.extending.overload(test_dispatch_impl)
def test_dispatch_impl_overload(X, indices):
    if isinstance(indices, nb.types.Integer):
        return test_dispatch_scalar
    elif isinstance(indices, nb.types.Array) and indices.ndim == 1 and isinstance(indices.dtype, nb.types.Integer):
        return test_dispatch_vector
    else:
        assert False # Unsupported

@nb.njit
def test_dispatch(X, indices):
    return test_dispatch_impl(X, indices)

Старое устаревшее решение

Вот пример рассуждений об универсальных типах:

import numba as nb
import numpy as np

@nb.generated_jit(nopython=True)
def test_dispatch(X, indices):
    if isinstance(indices, nb.types.Integer):
        def test_dispatch_scalar(X, indices):
            ref_pos = np.empty(3, np.float64)
            ref_pos[:] = X[:, indices]
            return ref_pos
        return test_dispatch_scalar
    elif isinstance(indices, nb.types.Array) and indices.ndim == 1 and isinstance(indices.dtype, nb.types.Integer):
        def test_dispatch_vector(X, indices):
            ref_pos = np.empty((3, len(indices)), np.float64)
            ref_pos[:, :] = X[:, indices]
            return ref_pos
        return test_dispatch_vector
    else:
        assert False # Unsupported

Вот пример рассуждений о конкретных типах:

import numba as nb
import numpy as np

@nb.generated_jit(nopython=True)
def test_dispatch(X, indices):
    if indices == nb.types.int64:
        def test_dispatch_scalar(X, indices):
            ref_pos = np.empty(3, np.float64)
            ref_pos[:] = X[:, indices]
            return ref_pos
        return test_dispatch_scalar
    elif isinstance(indices, nb.types.Array) and indices.ndim == 1 and indices.dtype == nb.types.int64:
        def test_dispatch_vector(X, indices):
            ref_pos = np.empty((3, len(indices)), np.float64)
            ref_pos[:, :] = X[:, indices]
            return ref_pos
        return test_dispatch_vector
    else:
        assert False # Unsupported

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

Обратите внимание, что общие функции JIT предназначены для создания функций, которые компилируются отдельно относительно целевого типа входных данных (а не значений).

Раньше я использовал generated_jit. Мой вопрос поступил от пользователей моей библиотеки, которые жаловались на удаление generated jit из numba. github.com/mcocdawc/chemcoord/issues/76 Поэтому я хотел провести рефакторинг своего кода, используя isinstance numba.readthedocs.io/en/stable/reference/…

mcocdawc 15.04.2024 20:33

Фактический код, который в настоящее время работает нормально и его необходимо переписать без generated_jit, — это github.com/mcocdawc/chemcoord/blob/master/src/chemcoord/…

mcocdawc 15.04.2024 20:35

Обратите внимание, что в реальном коде я использую nb.types.Array и nb.types.Integer, но для целей вопроса я хотел упростить и запросил специально int64.

mcocdawc 15.04.2024 20:42

Вы можете использовать extending.overload вместо generated_jit, как обсуждалось в этом выпуске.

Nin17 15.04.2024 22:48

@mcocdawc Я не знал об устаревании. Я просто следую инструкциям в документе (об использовании overload) по вашей ссылке, и все сработало.

Jérôme Richard 15.04.2024 23:48

Большое спасибо за вашу помощь. Мне не нравится новый синтаксис перегрузки, потому что он очень многословен и повторяется. В той же ссылке они также привели гораздо более хороший пример, в котором напрямую использовался синтаксис моего вопроса. Они пишут об этом [...] Кроме того, пользователи, которые используют сгенерированный_jit для отправки некоторых более примитивных типов, могут обнаружить, что поддержки Numba для isinstance достаточно [...] Видимо, уже просто массив целых чисел не является «примитивным». "Хватит уже. Я оставлю вопрос открытым еще немного в надежде, что можно обойтись без повторяющегося синтаксиса.

mcocdawc 16.04.2024 16:30

Я согласен с вами. Я немного изменил реализацию, чтобы сделать ее менее повторяющейся, но она все еще немного многословна и громоздка. К сожалению, это по своей сути связано с тем, как overload работает. Жаль, что они приняли такое решение. Здесь решение isinstance может сработать, если Numba будет поддерживать np.issubdtype, но пока нет :/ . Возможно, этот можно заменить, чтобы было проще. Но имейте в виду, что один и тот же код реплицируется для нескольких реализаций, поэтому для этого кода это подходит, но не для более крупных.

Jérôme Richard 17.04.2024 22:08

Большое спасибо! Ваш рефакторинг кода — лучшее решение, которое я видел в отношении нового механизма overload. Могу ли я спросить, можете ли вы изменить первое предложение своего ответа, чтобы новые пользователи не были обмануты, заставляя их поверить, что generated_jit по-прежнему является каноническим решением, возможно, вы можете обратиться к обновлению внизу? Тогда я, конечно, приму ваш ответ.

mcocdawc 19.04.2024 16:38

Хорошая точка зрения. Я изменил ответ, чтобы продвигать новое решение @overload, и явно пометил исходное решение как устаревшее.

Jérôme Richard 20.04.2024 14:39

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

Попытайтесь получить значение ListBox из UserForm, но я получил следующую ошибку: Ошибка выполнения 13: несоответствие типов
Преобразование значения одного типа в значение другого типа в Котлине в целом
Как в этом случае получить возвращаемое значение безопасной для типа функции?
Шаблон класса C++: определение типа, используемого при параметризации суперкласса и определении value_type
Xcode показывает переменную как необязательную, если это не так
Назначение типа переменной на основе типа другой переменной в подпрограмме
Неопределенное поведение с объединениями
PyTorch Geometric SAGEConv — Ожидаемый скалярный тип Long, но найден Float?
Требуется разъяснение по выражениям VHDL, включающим std_logic_vector, беззнаковые и литералы, неуверенность в интерпретации компилятора
Тип B отображается как A, если используется тип B = A. Почему он отображается как «любой», когда «тип B = A | Вместо этого используется A`?