È possibile utilizzare scipy.optimize.minimize
con jac=True
. Se questo non è un'opzione per qualche motivo, allora si può guardare 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
Questa classe avvolge una funzione che restituisce valore della funzione e di pendenza, mantenendo una cache di un elemento e controlla che per vedere se si sa già il suo risultato. Uso:
fmemo = MemoizeJac(f, fprime)
xopt = fmin_cg(fmemo, x0, fmemo.derivative)
La cosa strana di questo codice è che esso presuppone f
viene sempre chiamato prima fprime
(ma non tutti i f
chiamata è seguito da un fprime
chiamata). Non sono sicuro che lo standard scipy.optimize
lo garantisca, ma il codice può essere facilmente adattato per non dare quell'assunzione, comunque. Versione robusta di quanto sopra (non testata ):
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 Bel modo di caching ritorno dell'ultima chiamata! Non sarebbe troppo difficile superare quell'ultima limitazione potenziale ('f' chiamato prima di' fprime'), giusto? – Jaime
@Jaime: no, basta ripetere il trucco usato in 'derivata'. Vedi risposta aggiornata. –
Waw, questa è una soluzione incredibile, ho appena testato il mio codice con qualcosa come 'minimizza (fun = self._cost_grad, x0 = initial_theta, method = 'Newton-CG', options = {'maxiter': 20, 'disp ': True}, jac = True, args = (X, n_features, n_samples)) ', e ho ottenuto risultati fantastici. Il parametro 'fun' si aspetta una funzione che ritorna (cost, grad) come tupla, e' method' può essere semplicemente cambiato per eseguire 'l_bfgs',' bfgs', 'cg' o qualsiasi ottimizzatore disponibile in scipy. Grazie mille! Sono sorpreso che questa risposta non sia prevalente. – Curious