Hopfield Networks with Retina
As part of its machine learning module, Retina provides a full implementation of a general Hopfield Network along with classes for visualizing its training and action on data.
Historically speaking, the Hopfield Network was one of the first Recurrent Neural Networks and provided an early computational model of autoassociative memory. To learn more
about the network, we highly recommend this exposition, due to Rojas. Furthermore, you can find our walkthrough of
the Retina implementation in the source folder demos/mlearn/hopfield/Hopfield-Tutorial.ipynb
.
The Structure of Fovea's Machine Learning Utilities
The network implementation code is contained in retina/mlearn/hopfield_network.py
. The file defines a single class, HopfieldNetwork
, which is easily instantiated by a single call of the form myNet = HopfieldNetwork(num_neurons)
. Optionally, a custom activation function can be supplied. The num_neurons
argument specifies the number of neurons to be used internally by the network.
The file visuals.py
contains the front-end code that defines a VisualHopfield
network built on top of the HopfieldNetwork
backend. The VisualHopfield
network also relies on an internal VisualNeuron
class which creates drawings of neurons and the connections between them. In its default form, VisualHopfield
runs a detailed visual simulation of the Hopfield network training and learning on whatever data it's supplied. That said, each component of the visualization can easily be separated from the action of the others should your needs require a customized approach.
The HopfieldNetwork Class
This class defines the Hopfield Network sans a visual interface. The class provides methods for instantiating the network, returning its weight matrix, resetting the network, training the network, performing recall on given inputs, computing the value of the network's energy function for the given state, and more.
Class-Level Properties
None at this time.
Class-Level Functions
None at this time.
Instance-Level Properties
num_neurons
: The number of neurons contained in the network.
_weights
: The network's weight matrix.
_trainers
: A dictionary containing the available network training algorithms. At the time of writing the network supports Hebbian and Storkey training and the dictionary is
{"hebbian": self._hebbian, "storkey": self._storkey}
_recall_modes
: A dictionary containing the two different recall methods, _synchronous
and _asynchronous
.
{"synchronous": self._synchronous, "asynchronous": self._asynchronous}
_vec_activation
: A vectorized version of the network's activation function.
_train_act
: A vectorized version of the activation function used in network training.
Instance-Level Functions
weights()
: A getter method that return's the network's weight matrix.
reset()
: Resets the network to an untrained state by making the weight matrix identically zero.
train(patterns, method="hebbian", threshold=0, inject=lambda x, y: None)
: Trains the network.
patterns
: The input data on which the network is to be trained.
method
: Specifies the self._trainers
key for the training algorithm to be used.
threshold
: The threshold value for the network activation function.
inject
: A function to call after each iteration of the training algorithm. Primarily used by the VisualHopfield
class for updating the network drawing loop.
recall(patterns, steps=None, mode="asynchronous", inject=lambda x, y: None)
: This function should only be called after the network has been trained. Given an input
state the network attempts to "recall" the closest representative state seen during training. In other words, the network seeks to generalize the input state to one
from its internal "memory".
patterns
: The input states to be recalled.
steps
: The number of steps of the recall algorithm to be computed. This argument is unnecessary for asynchronous learning which is guaranteed to converge to some
final resting state, but is highly useful in avoiding infinite recursion in the case of synchronous learning.
mode
: The dictionary key for self._recall_modes
specifying the type of recall to be performed. Options are "synchronous"
and "asynchronous"
.
inject
: Has the same purpose as the corresponding argument of the training function.
energy(state)
: Returns the value of the network's energy function applied to the given state
.
The VisualNeuron
Class
Provides a visual interpretation of a constituent neuron of a Hopfield Network. All calls to VisualNeuron
are hidden internally within VisualHopfied
, and it is unlikely that you will need to alter this class. That said, if you do decide to adjust the visualization of individual neurons to your own specifications you will need to be familiar with the following class specifics.
Class-Level Properties
None at this time.
Class-Level Functions
None at this time.
Instance-Level Properties
theta
: The angular component of the polar representation of the neuron's position within the VisualHopfield
network diagram.
r
: The radial component of the polar representation of the neuron's position within the VisualHopfield
network diagram.
x
: The x component of the cartesian representation of the neuron's position within the VisualHopfield
network diagram.
y
: The y component of the cartesian representation of the neuron's position within the VisualHopfield
network diagram.
connections
: A dictionary which tracks the connections between this neuron and other neurons within the Hopfield Network. The keys are
VisualNeuron
objects and the values are the Line2D
artists of the VisualHopfield
network diagram.
Instance-Level Properties
draw(axes)
: Draws a neuron to the provided Matplotlib Axes instance.
draw_connection(neuron, connection_color, axes)
: Draws a connection between two neurons.
neuron
: The terminal VisualNeuron
of the connection.
connection_color
: The color of the connection line to be drawn.
axes
: The Matplotlib axes to which the connection should be drawn.
delete_connection(neuron)
: Deletes the connection between the calling VisualNeuron
and the VisualNeuron
specified by the neuron
argument.
The VisualHopfield Class
This class is a wrapper to the HopfieldNetwork
class which injects code for drawing and plotting various facets of the network dynamics
throughout the course of the network's operation. It subclasses HopfieldNetwork
.
Class-Level Properties
None at this time.
Class-Level Functions
None at this time.
Instance-Level Properties
d_theta
: A theta increment value calculated as 2pi multiplied by the number of neurons in the network. Used for positioning VisualNeuron
s in the
network diagram.
neurons
: A list of the VisualNeuron
objects associated with the network.
cs_plot
: None
training_data
: The user-provided training data.
recall_data
: The user-provided recall data.
cmap
: The Matplotlib colormap used in the weight matrix diagram.
mode
: The current mode of the visualization, either "training" or "recalling".
iteration
: A Matplotlib Text
instance displaying the current iteration of the network in either the training or recalling method.
network_fig
: The Matplotlib Figure
instance which holds the Axes associated with the visualization.
main_network
: The network diagram axes.
energy_diagram
: The energy diagram axes.
contour_diagram
: The energy contour diagram axes.
weight_diagram
: The weight diagram axes.
state_diagram
: The state diagram axes.
view_wfbutton
: A Matplotlib Button
used to toggle the wireframe view in the energy function diagram.
view_attractbutton
: A Matplotlib Button
used to toggle the plotting of attractors in the energy function diagram.
Instance-Level Functions
The _setup_display
Function
The task of the _setup_display
function is to construct the Matplotlib figure window and arrange its component axes. The figure is assigned to the instance attribute self.network_fig
and can be accessed as such. The component axes are the following:
self.main_network -- Axes to which VisualNeurons and their connections are drawn.
self.energy_diagram -- The 3D axes in which the network's energy function is plotted.
self.contour_diagram -- Axes to hold the contour plot of the network's energy function.
self.state_diagram -- Axes to which a checkerboard representation of the network's binary state is drawn.
self.weight_diagram -- Axes to hold a heatmap representation of the network's weight matrix.
The function also creates widgets to toggle layer visibility in the energy diagram and dynamic text labels that change based on the network's current mode (training or recalling) and iteration count within those methods.
The _draw_network
Function
This method uses a simple loop to draw the symmetric connections that occur between each of the network's neurons. Probably the most useful information that can be gleaned from the function is the significance of a connection's color. In our setup, connections having the weight 0 are colored green, the weight 1 colored blue, and the weight -1 colored red. You can change these colors to suit your preferences by altering the variable colors
.
The _plot_state
Function
This method handles all of the plotting necessary for creating the network's state diagram. The network's "state" at any given point in time is the output of its recall function in response to an input vector. Since all network vectors are bipolar, we split its output vector at even intervals and use these vectors as the rows of a matrix. This matrix is converted to a black-and-white patchwork diagram using Matplotlib's imshow
function.
IMPORTANT: Each state is a numpy array, and is converted to a matrix using the state.reshape()
function. You will need to alter this call should you seek to visualize a network not having exactly 25 neurons as is used for the OCR example.
The _plot_weights
Function
This one is similar to _plot_state
in its action and construction. The imshow
map is used to create a colormap representation of the network's weight matrix. You can modify this method to change the colormap used.
The _set_mode
Function
Updates the network's "mode" text label based on the network's current operation: either training or recalling.
The _train_inject
Function
This function contains visualization code that is injected into the HopfieldNetwork
base class' training method. Alter with care.
The _recall_inject
Function
Same as above, except for the network's recalling method. Alter with care, as well.
The _normalize_network
Function
This method serves one purpose: resetting the linewidth of those neuronal connections that were manipulated by the network during its training phase so as not to pollute with thickness the visual space.
The _plot_energy
Function
The _plot_energy
function is probably the most involved method of the entire visualization, as there is a great deal of legwork that goes into creating a 3-dimensional representation of the energy landscape. For networks having $\geq 3$ neurons, the plot of the energy function will reside in 4 or more dimensions. In order to reduce this $n$-dimensional information to a 3-dimensional representation, we perform a 2D PCA transformation on the network's training data. If we treat these PCA axes as our x and y axes and the energy value as the z-axis, we are able to plot the energy function accordingly.
This function, in fact, contains three plot artists in three different layers. The first layer contains the network's attractors, plotted in a scatter plot as green markers. The second layer contains a wireframe plot of the energy landscape onto which the attractor markers can be overlaid. The third layer contains the energy landscape plotted as a surface.