#python #performance #numpy #vectorization #array-broadcasting
#python #Производительность #numpy #векторизация #массив-трансляция
Вопрос:
В конечном счете, я хочу удалить все явные циклы в приведенном ниже коде, чтобы воспользоваться векторизацией numpy и вызовами функций на C вместо python.
Ниже упрощено для использования numpy в python. У меня есть следующая квадратичная функция:
def quadratic_func(a,b,c,x):
return a*x*x b*x c
Я пытаюсь оптимизировать выбор a, b, c с учетом входных данных x и выходных данных y одинакового размера (конечно, это должно быть сделано с помощью линейной регрессии … но мне нравится). Скажем, len(x)=100. Легко векторизировать с помощью скаляров a, b, c, чтобы получить результат длиной 100.
Допустим, мы знаем, что a, b, c должны находиться внутри [-10,10], и я оптимизирую, создавая сетку и выбирая точку с минимальной ошибкой квадрата суммы.
a=np.arange(-10.0, 10.01, 2.0)
nodes=np.array(np.meshgrid(a,a,a)).T.reshape(-1,3) #3-d cartesian product with array of nodes
Для каждого из 1331 узла я хотел бы вычислить все 1331 возвращаемых значений длиной 100.
res=[]
x=np.random.uniform(-5.0,5.0, 100)
for node in nodes:
res.append(quadratic_func(*node, x=x))
Как я могу воспользоваться широковещательной передачей, чтобы получить мой список из 1331 элемента, каждый из которых содержит 100 значений, которые являются результатами вызова quadratic_func для x ? Ответ должен использовать векторизацию, широковещательную передачу и т.д., Чтобы получить улучшения скорости на порядки, которые я ищу. Кроме того, в ответе должны использоваться вызовы quadratic_func — или, в более общем смысле, my_func(*узел, x=x).
В реальной жизни я оптимизирую нелинейную функцию, которая даже близко не является выпуклой и имеет много локальных минимумов. Это отличная функциональная форма для использования, если я могу добраться до «правильного» локального минимума — я уже знаю, как это сделать, но хотел бы добраться туда быстрее!
Ответ №1:
Один подход, использующий комбинацию broadcasting
и np.einsum
—
np.einsum('ij,jk->ik',nodes,x**np.array([2,1,0])[:,None])
Другой, использующий умножение матрицы на np.dot
—
nodes.dot(x**np.array([2,1,0])[:,None])
Комментарии:
1. Я вижу, что вы делаете, но ищу что-то более общее, чем это — я не хочу знать, что такое функция априори. Я хочу иметь возможность передавать целевую функцию, для которой я в конечном итоге собираюсь оптимизировать параметры, в свой оптимизатор, и я не могу предположить, что функциональная форма будет представлять собой некоторую комбинацию полиномов, sqrts, журналов и т.д. Можете ли вы сделать это с помощью вызова quadratic_func?
2. @FinanceGuyThatCantCode Да, в этом суть векторизации NumPy, нет способа, который использовал бы какую-либо общую функцию и ускорил бы ее. Вы можете заглянуть в cython или numba, если работаете с какой-то конкретной функциональностью, которая не может быть переведена в NumPy funcs или ufuncs.
3. Я думаю, именно поэтому я не мог понять это сам! Было бы хорошей функцией, хотя …. и подумать только, я мог бы спросить ребят из Continuum, которые были сегодня в моем офисе!