В моей проблеме минимизации все ограниченные методы минимизации, такие как 'L-BFGS-B', 'TN C', не сходятся, но 'Nelder-Mead' сходится очень хорошо. Поэтому я предпочитаю использовать «Nelder-Mead» с измененной функцией минимизации, например:
def outbound_penalty(x, bounds):
o1 = (bounds[:, 0]-x).max()
o2 = (x-bounds[:, 1]).max()
outbound = max(o1, o2, 0)
rez = 100500*outbound
def bounded_fun(x, bounds):
return fun(x) + outbound_penalty(x, bounds)
x - это numpy форма массива (4), границы имеют форму (2, 4), границы [ 0] - нижние границы, границы [1] - верхние границы. Это на удивление не так быстро, как я ожидал. При 4 * 10 ^ 6 вызовах это занимает 40 секунд собственного времени на процессоре. Конечно, я запомнил это. Но я должен спросить. Существуют ли некоторые очень оптимизированные функции в numpy / scipy, которые я могу использовать для создания исходящих штрафов?
sss = np.zeros((2, 1000))
sss[0] = np.random.uniform(-100, 300, 1000)
sss[1] = np.random.uniform(-100, 300, 1000)
smpls = sss.T
bnd = np.array([[0, 100+np.random.randint(100)], [0, 100+np.random.randint(100)]])
np_bounds = np.array(bnd)
def outbound_penalty(x, bs):
o1 = (bs[:, 0] - x).max()
o2 = (x - bs[:, 1]).max()
outbound = max(o1, o2, 0)
return 1000000 * outbound
def outbound_penalty_fast(x, bs):
o1 = (bs[:, 0, None] - x).max(axis=0)
o2 = (x - bs[:, 1, None]).max(axis=0)
outbound = np.clip(np.maximum(o1, o2), a_max=None, a_min=0)
return 1000000 * outbound
%timeit [outbound_penalty(x, np_bounds) for x in smpls]
22.6 ms ± 198 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [outbound_penalty_fast(x, np_bounds) for x in smpls]
68.6 ms ± 1.62 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit outbound_penalty(smpls[0], np_bounds)
22.5 µs ± 109 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit outbound_penalty_fast(smpls[0], np_bounds)
68.2 µs ± 1.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Эта версия outbound_penalty_fast возвращает одно число с плавающей точкой, как и ожидал вызывающий:
def outbound_penalty_fast(x, bs):
o1 = (bs[:, 0, None] - x).max(axis=0)
o2 = (x - bs[:, 1, None]).max(axis=0)
outbound = np.clip(np.maximum(o1, o2), a_max=None, a_min=0)
rez = 1000000 * outbound.max()
return rez