Векторизация поэлементно

Можно ли векторизовать (или иным образом ускорить) поэлементную оптимизацию с помощью NumPy (и SciPy)?

В самом абстрактном смысле у меня есть функция y, которая имеет параболическую форму и может быть выражена в основном как y=x^2+b*x+z, где x — массив известных значений, и я хочу найти z, при котором минимальное значение y равно нулю ( Другими словами, я хочу найти значение z, при котором моя парабола будет иметь только один ноль). Для этого я решил реализовать простой метод, похожий на деление пополам. Код для этого ниже:

import numpy as np

def find_single_root():
    x = np.arange(-5, 6,0.1) # domain
    z = 1 # initial guess
    delta = 1 # initial step size
    tol = 0.001 # tolerance
    while True:
        y = x**2-5*x+z
        minimum = np.nanmin(y)
        # update z
        print(delta)
        print(z)
        if minimum > 0:
            if delta > 0:
                delta = -1*delta/2
            z += delta
        else:
            if delta < 0:
                delta = -1*delta/2
            z += delta
        # check if step is smaller than tolerance
        if np.abs(delta) < tol:
            return z

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

def find_single_root(v, w):
    x = np.arange(-5*v/w, 6*w,0.1) # domain
    ... # rest of the function

vs = np.arange(1,5)
ws = np.arange(1,5)
zs = np.zeros((len(vs),len(ws)))
for i, v in enumerate(vs):
    for j, w in enumerate(ws):
        zs[i][j] = find_single_root(v,w)

Прямо сейчас у меня есть эти простые вложенные циклы for, но есть ли способ, которым я могу подойти к этому по-другому или ускорить его с помощью векторизации NumPy?


person Brandon Bocklund    schedule 22.01.2017    source источник


Ответы (1)


Векторизация может быть применима, когда вычисления, которые должны быть выполнены, точно известны заранее. Например, «возьмите два массива чисел и перемножьте их попарно».

Векторизация неприменима, когда вычисления адаптируются к заданным данным. Любой алгоритм оптимизации является адаптивным, потому что то, где вы ищете минимум, зависит от того, что возвращает функция. Если у вас есть куча функций и вам нужно найти минимум каждой из них, вам придется минимизировать их по одной в цикле. Если этот процесс идет медленно, то это потому, что для минимизации набора функций требуется много времени, а не потому, что в программе есть цикл for.

Что касается вашей программы, я бы попробовал использовать некоторые методы SciPy как для минимизации, так и для поиска корня. Создайте функцию min_of_f(z), которая находит минимум для заданного значения параметра z, возможно, используя minimize_scalar. Затем передайте min_of_f процедуре поиска корня< /а>. Сколько времени это займет, можно контролировать с помощью их параметров допуска (xtol и другие).


Редактирование OP: я хотел отметить это как правильный ответ, но все же предоставить больше информации.

В итоге я использовал numpy.vectorize для векторизации без реструктуризации проблема. Хотя numpy.vectorize не предназначено для повышения производительности, производительность в моем конкретном случае была скромно в два раза выше. Применение того же подхода к исходной проблеме в вопросе практически не привело к ускорению с векторами 100x100, поэтому YMMV.

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

person Community    schedule 22.01.2017
comment
Спасибо за ответ. Численная сложность вычисления y в моей реальной задаче достаточно значительна, поэтому ее векторизация позволила всей функции оптимизации ускориться в 60 раз. Я понимаю, что вы имеете в виду в отношении адаптивного подхода, поэтому я и спросил, существует ли другой (аналитический) подход к этой проблеме, который можно было бы векторизовать. В конце концов, я мог бы просто переписать этот фрагмент на Cython, но эти усилия не стоили бы увеличения производительности. - person Brandon Bocklund; 22.01.2017