Source code for optimatic.optimisers.grad_desc

"""
Gradient descent optimisation

Implements gradient descent to optimise a function
:math:`f:\mathbb{R}^n \\rightarrow \mathbb{R}`.

Uses the reccurence relation:

.. math::

    \mathbf{x}_n = \mathbf{x}_{n-1} - \gamma_n \\nabla f(\mathbf{x}_{n-1})

Where

.. math::

    \gamma_n = \\frac{(\mathbf{x}_n - \mathbf{x}_{n-1}) \cdot \
        (\mathbf{\\nabla}f(\mathbf{x}_n) - \mathbf{\\nabla}\
        f(\mathbf{x}_{n-1}))}{||\mathbf{\\nabla}f(\mathbf{x}_n) - \
        \mathbf{\\nabla}f(\mathbf{x}_{n-1})||^2}
"""
import numpy as np
from optimatic.optimisers.optimiser_base import Optimiser as OptimiserBase
from optimatic.utils.differentiate import central_diff

[docs]class Optimiser(OptimiserBase): """ :param f: The function to optimise :param x0: The starting position for the algorithm :param df: The derivative of the function to optimise. If this isn't provided, it will be estimated from :math:`f` using :func:`~optimatic.utils.differentiate.central_diff` :param precision: The precision to calculate the minimum to :param gamma: The starting value for :math:`\gamma` :param steps: The max number of iterations of the algorithm to run """ def __init__(self, f, x0, df=None, gamma=0.1, precision=1e-7, steps=10000): super(Optimiser, self).__init__(f, x0, precision=precision, steps=steps) if df is None: self.df = lambda *x: central_diff(f, np.array(x[0])) else: self.df = df self.gamma = gamma
[docs] def step(self): self.xn_1 = self.xn self.xn = self.xn_1 - self.gamma * self.df(self.xn_1) grad_diff = self.df(self.xn) - self.df(self.xn_1) if grad_diff == 0.0: # Algorithm has converged return xs_diff = self.xn - self.xn_1 self.gamma = np.dot(xs_diff, grad_diff) self.gamma /= np.linalg.norm(grad_diff) ** 2