#python #random #signature #optional-parameters #numba
#python #Случайный #подпись #необязательно-параметры #numba
Вопрос:
Допустим, у меня есть функция, которая может принимать как int
, так и None
тип в качестве входного аргумента
import numba as nb
import numpy as np
jitkw = {"nopython": True, "nogil": True, "error_model": "numpy", "fastmath": True}
@nb.jit("f8(i8)", **jitkw)
def get_random(seed=None):
np.random.seed(None)
out = np.random.normal()
return out
Я хочу, чтобы функция просто возвращала нормально распределенное случайное число. Если я хочу воспроизводимые результаты, начальным значением должно быть int
.
get_random(42)
>>> 0.4967141530112327
get_random(42)
>>> 0.4967141530112327
get_random(42)
>>> 0.4967141530112327
Если я хочу случайные числа, seed
их следует оставить как None
. Однако, если я не передаю аргумент (поэтому по умолчанию используется значение seed None
) или явно передаю seed=None
, то numba вызывает TypeError
get_random()
>>> TypeError: No matching definition for argument type(s) omitted(default=None)
get_random(None)
>>> TypeError: No matching definition for argument type(s) omitted(default=None)
Как я могу написать функцию, все еще объявляя подпись и используя nopython
режим для такого сценария?
Моя версия numba 0.43.1
Комментарии:
1. С numba это всегда полезно для дальнейшего использования и для тех, кто отвечает, если вы включаете свою версию numba. Это потому, что поддерживаемые функции могут сильно различаться в разных версиях.
Ответ №1:
Первая проблема заключается в том, что numba в режиме nopython принимает только (начиная с версии 0.43.1) np.random.seed
: только с целочисленным аргументом.
Итак, к сожалению, вы не можете передать None
.
Вторая проблема заключается в том, что (насколько я знаю) нет «единой» подписи, которая указывала бы numba, как обращаться с пропущенными значениями, однако вы можете использовать две подписи (да, это очень подробно):
import numba as nb
import numpy as np
jitkw = {"nopython": True, "nogil": True, "error_model": "numpy", "fastmath": True}
@nb.jit(
[nb.types.float64(nb.types.misc.Omitted(None)),
nb.types.float64(nb.types.int64)],
**jitkw)
def get_random(seed=None):
return np.random.normal()
Просто краткое объяснение двух частей подписи:
nb.types.float64(nb.types.misc.Omitted(None))
Сообщает numba использоватьNone
в качестве типа по умолчанию, если аргумент опущен- и
nb.types.float64(nb.types.int64)
это подпись, которая ожидает целое число.
Лично я бы не стал указывать подпись и просто позволил numba разобраться с этим. Явные подписи редко стоят того в numba, и чаще всего они приводят к более медленному и менее гибкому коду.
Комментарии:
1. Я испытал значительное ускорение при определении подписей массива numpy: т. Е. nb.float64[:] или nb.int64 [:,:] и т.д., Но не так много с обычными переменными.
2. @MottTheTuple Это интересно, потому что обычно вы не получаете ускорения с типами в numba — за исключением первого вызова, потому что, если вы не определяете типы, функция компилируется с заданными аргументами, в то время как с заданными типами функция компилируется, когда она определена. Цель подписи, по сути, «детализированный контроль над типами, выбранными компилятором» (из numba.pydata.org/numba-doc/latest/user /… ). Если у вас есть пример, где скорость функции действительно сильно отличается, мне было бы очень интересно привести пример (например, суть).
3. Где я видел это в моей функции линейной регрессии. Я отправляю некоторые экстремумы и вычисляю наклон, перехват и остатки с помощью незначительных числовых функций: сумма, среднее значение, макс и т.д. Я отбрасываю строки с наименьшими остатками. Все это выполняется в инструкции while, пока я не достигну минимального числа циклов в строке .1000 — время python: .0005, с nb.jit(nopython= True): .0019, nb.jit (nb.types.float64[:,:] (nb.types.float64[:,:], nb.int32), nopython=True) время: 1.5624e-05. Это одна из моих идей, может быть, не «массивная», но мне очень повезло с добавлением sigs в функции, где режим nopython сам по себе плохо работал.
4. @MottTheTuple В ваших таймингах вы исключили первый вызов (который включает стоимость компиляции)? Я немного знаю о внутренних компонентах numba, и есть несколько случаев, когда типизированные функции могут быть быстрее, в большинстве случаев они будут немного медленнее (за исключением случаев, когда вы также вводите, является ли массив непрерывным). Однако я был бы признателен, если бы вы могли создать gist (GitHub) или что-то еще, где я мог бы посмотреть.
5. Я вернулся к своим таймингам и обнаружил, что я НЕ исключил первый вызов. Я протестировал обе функции nopython, и обе работали примерно с одинаковой скоростью. Таким образом, ваша предпосылка, вероятно, верна, что подписи в большинстве случаев не нужны.. Возможно, у меня были специальные типы ввода в функции, которые я использовал раньше, что могло привести к ускорению, если я обнаружу, что я отправлю вам ссылку на суть. Спасибо за дружеское обсуждение.