Source code for biolearn.model.hopfield

import numpy as np

from biolearn.model._base import Base
from biolearn.utils.weights import Normal
from biolearn.utils.activations import Linear
from biolearn.utils.optimizer import SGD

__author__  = ['Nico Curti', 'SimoneGasperini']
__email__ = ['nico.curit2@unibo.it', 'simone.gasperini2@studio.unibo.it']


[docs]class Hopfield (Base): ''' Parameters ---------- inputs : int (default=None) Number of input units outputs : int (default=100) Number of hidden units num_epochs : int (default=100) Maximum number of epochs for model convergency batch_size : int (default=10) Size of the minibatch weights_init : BaseWeights (default=Normal) Weights initialization strategy object optimizer : Optimizer (default=SGD) Optimizer object delta : float (default=0.4) Strength of the anti-hebbian learning p : float (default=2.) Lebesgue norm of the weights k : int (default=2) Ranking parameter, must be an integer greater or equal to 1 precision : float (default=1e-30) Parameter that controls numerical precision of the weight updates epochs_for_convergency : int (default=None) Number of stable epochs requested for the convergency. If None the training proceeds up to the maximum number of epochs (num_epochs) convergency_atol : float (default=0.01) Absolute tolerance requested for the convergency random_state : int (default=None) Random seed for weights generation verbose : bool (default=True) Turn on/off the verbosity ''' def __init__(self, inputs=None, outputs=100, num_epochs=100, batch_size=100, weights_init=Normal(), optimizer=SGD(), delta=.4, p=2., k=2, precision=1e-30, epochs_for_convergency=None, convergency_atol=0.01, random_state=None, verbose=True): self.delta = delta self.p = p if k > outputs: raise ValueError('Incorrect value of the ranking parameter k. ' 'It must be less or equal to the number of outputs') self.k = k super (Hopfield, self).__init__(inputs=inputs, outputs=outputs, num_epochs=num_epochs, batch_size=batch_size, weights_init=weights_init, activation=Linear(), optimizer=optimizer, precision=precision, epochs_for_convergency=epochs_for_convergency, convergency_atol=convergency_atol, random_state=random_state, verbose=verbose) def _weights_update (self, X, output): ''' This is the core function of the Hopfield model since it implements the Hopfield learning rule using the approximation introduced by Krotov: instead of solving the dynamical equations, the currents are used as a proxy for ranking the outputs activities and then computing the weights update. Parameters ---------- X : array-like (2D) Input array of data output : array-like (2D) Output of the model estimated by the predict function Returns ------- weight_update : array-like (2D) Weight updates matrix to apply theta : array-like (1D) Array of learning progress ''' order = np.argsort(output, axis=0) yl = np.zeros_like(output, dtype=float) yl[order[-1, :], range(self.batch_size)] = 1. yl[order[-self.k, :], range(self.batch_size)] = - self.delta xx = np.sum(yl * output, axis=1, keepdims=True) #ds = yl @ X - xx * self.weights ds = np.einsum('ij, jk -> ik', yl, X, optimize=True) - xx * self.weights nc = np.max(np.abs(ds)) nc = 1. / max(nc, self.precision) return ds * nc, xx def _fit (self, X): ''' Core function for the fit member ''' return super(Hopfield, self)._fit(X=X, norm=True) def _predict (self, X): ''' Core function for the predict member ''' # return self.weights @ X return np.einsum('ij, kj -> ik', self.weights, X, optimize=True)