import time
import scipy.optimize
import tensorflow as tf
from garage.tf.misc import tensor_utils
from garage.tf.optimizers.utils import LazyDict
[docs]class LbfgsOptimizer:
"""
Performs unconstrained optimization via L-BFGS.
"""
def __init__(self, max_opt_itr=20, callback=None):
self._max_opt_itr = max_opt_itr
self._opt_fun = None
self._target = None
self._callback = callback
[docs] def update_opt(self,
loss,
target,
inputs,
extra_inputs=None,
name=None,
*args,
**kwargs):
"""
:param loss: Symbolic expression for the loss function.
:param target: A parameterized object to optimize over. It should
implement methods of the
:class:`garage.core.paramerized.Parameterized` class.
:param leq_constraint: A constraint provided as a tuple (f, epsilon),
of the form f(*inputs) <= epsilon.
:param inputs: A list of symbolic variables as inputs
:return: No return value.
"""
self._target = target
params = target.get_params(trainable=True)
with tf.name_scope(name, 'LbfgsOptimizer',
[loss, inputs, params, extra_inputs]):
def get_opt_output():
with tf.name_scope('get_opt_output', values=[loss, params]):
flat_grad = tensor_utils.flatten_tensor_variables(
tf.gradients(loss, params))
return [
tf.cast(loss, tf.float64),
tf.cast(flat_grad, tf.float64)
]
if extra_inputs is None:
extra_inputs = list()
self._opt_fun = LazyDict(
f_loss=lambda: tensor_utils.compile_function(
inputs + extra_inputs, loss),
f_opt=lambda: tensor_utils.compile_function(
inputs=inputs + extra_inputs,
outputs=get_opt_output(),
))
[docs] def loss(self, inputs, extra_inputs=None):
if self._opt_fun is None:
raise Exception(
'Use update_opt() to setup the loss function first.')
if extra_inputs is None:
extra_inputs = list()
return self._opt_fun['f_loss'](*(list(inputs) + list(extra_inputs)))
[docs] def optimize(self, inputs, extra_inputs=None, name=None):
if self._opt_fun is None:
raise Exception(
'Use update_opt() to setup the loss function first.')
with tf.name_scope(name, 'optimize', values=[inputs, extra_inputs]):
f_opt = self._opt_fun['f_opt']
if extra_inputs is None:
extra_inputs = list()
def f_opt_wrapper(flat_params):
self._target.set_param_values(flat_params, trainable=True)
ret = f_opt(*inputs)
return ret
itr = [0]
start_time = time.time()
if self._callback:
def opt_callback(params):
loss = self._opt_fun['f_loss'](*(inputs + extra_inputs))
elapsed = time.time() - start_time
self._callback(
dict(
loss=loss,
params=params,
itr=itr[0],
elapsed=elapsed,
))
itr[0] += 1
else:
opt_callback = None
scipy.optimize.fmin_l_bfgs_b(
func=f_opt_wrapper,
x0=self._target.get_param_values(trainable=True),
maxiter=self._max_opt_itr,
callback=opt_callback,
)
def __getstate__(self):
"""Object.__getstate__."""
new_dict = self.__dict__.copy()
del new_dict['_opt_fun']
return new_dict