Można użyć scipy.optimize.minimize
z jac=True
. Jeśli nie jest to opcja dla jakiegoś powodu, to można spojrzeć na how it handles this situation:
class MemoizeJac(object):
""" Decorator that caches the value gradient of function each time it
is called. """
def __init__(self, fun):
self.fun = fun
self.jac = None
self.x = None
def __call__(self, x, *args):
self.x = numpy.asarray(x).copy()
fg = self.fun(x, *args)
self.jac = fg[1]
return fg[0]
def derivative(self, x, *args):
if self.jac is not None and numpy.alltrue(x == self.x):
return self.jac
else:
self(x, *args)
return self.jac
Ta klasa jest zawijany funkcję, która zwraca wartość funkcji i gradientu, zachowując pamięć jednego elementu i sprawdza, że aby sprawdzić, czy już wie jego wynik. Zastosowanie:
fmemo = MemoizeJac(f, fprime)
xopt = fmin_cg(fmemo, x0, fmemo.derivative)
Najdziwniejsze o tym kodzie jest to, że zakłada f
zawsze jest wywoływana przed fprime
(ale nie każdy f
wywołanie następuje przez fprime
rozmowy). Nie jestem pewien, czy rzeczywiście to gwarantuje scipy.optimize
, ale kod można łatwo zaadaptować, aby nie przyjąć takiego założenia. Wytrzymała wersja powyższego (niesprawdzone):
class MemoizeJac(object):
def __init__(self, fun):
self.fun = fun
self.value, self.jac = None, None
self.x = None
def _compute(self, x, *args):
self.x = numpy.asarray(x).copy()
self.value, self.jac = self.fun(x, *args)
def __call__(self, x, *args):
if self.value is not None and numpy.alltrue(x == self.x):
return self.value
else:
self._compute(x, *args)
return self.value
def derivative(self, x, *args):
if self.jac is not None and numpy.alltrue(x == self.x):
return self.jac
else:
self._compute(x, *args)
return self.jac
+1 miły sposób buforowania powrót ostatniego połączenia głównej! Nie byłoby zbyt trudno pokonać ostatnie potencjalne ograniczenie ("f" wywołane przed 'fprime'), prawda? – Jaime
@Jime: nie, po prostu powtórz lewę użytą w 'derivative'. Zobacz zaktualizowaną odpowiedź. –
Waw, to takie niesamowite rozwiązanie, właśnie przetestowałem mój kod z czymś takim jak 'minimize (fun = self._cost_grad, x0 = initial_theta, method = 'Newton-CG', options = {'maxiter': 20, 'disp ': True}, jac = True, args = (X, n_features, n_samples)) ', i mam niesamowite rezultaty. Parametr 'fun' oczekuje funkcji zwracającej (cost, grad) jako krotki, a' method' można po prostu zmienić, wykonując 'l_bfgs',' bfgs', 'cg' lub dowolny optymalizator w scipy. Stukrotne dzięki! Jestem zaskoczony, że ta odpowiedź nie jest powszechna. – Curious