Source code for neurodynex.ojas_rule.oja

"""
This file implements Oja's hebbian learning rule.

Relevant book chapters:
    - http://neuronaldynamics.epfl.ch/online/Ch19.S2.html#SS1.p6
"""

# This file is part of the exercise code repository accompanying
# the book: Neuronal Dynamics (see http://neuronaldynamics.epfl.ch)
# located at http://github.com/EPFL-LCN/neuronaldynamics-exercises.

# This free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License 2.0 as published by the
# Free Software Foundation. You should have received a copy of the
# GNU General Public License along with the repository. If not,
# see http://www.gnu.org/licenses/.

# Should you reuse and publish the code for your own purposes,
# please cite the book or point to the webpage http://neuronaldynamics.epfl.ch.

# Wulfram Gerstner, Werner M. Kistler, Richard Naud, and Liam Paninski.
# Neuronal Dynamics: From Single Neurons to Networks and Models of Cognition.
# Cambridge University Press, 2014.

import matplotlib.pyplot as plt
import numpy as np


[docs]def make_cloud(n=10000, ratio=1, angle=0): """Returns an oriented elliptic gaussian cloud of 2D points Args: n (int, optional): number of points in the cloud ratio (int, optional): (std along the short axis) / (std along the long axis) angle (int, optional): rotation angle [deg] Returns: numpy.ndarray: array of datapoints """ if ratio > 1.: ratio = 1. / ratio x = np.random.randn(n, 1) y = ratio * np.random.randn(n, 1) z = np.concatenate((x, y), 1) radangle = (180. - angle) * np.pi / 180. transfo = [ [np.cos(radangle), np.sin(radangle)], [-np.sin(radangle), np.cos(radangle)] ] return np.dot(transfo, z.T).T
[docs]def learn(cloud, initial_angle=None, eta=0.001): """Run one batch of Oja's learning over a cloud of datapoints Args: cloud (numpy.ndarray): array of datapoints initial_angle (float, optional): angle of initial set of weights [deg]. If None, this is random. eta (float, optional): learning rate Returns: numpy.ndarray: time course of the weight vector """ # get angle if not set if initial_angle is None: initial_angle = np.random.rand() * 360. radangle = initial_angle * np.pi / 180. w = np.array([np.cos(radangle), np.sin(radangle)]) wcourse = np.zeros((len(cloud), 2), float) for i in range(0, len(cloud)): wcourse[i] = w y = np.dot(w, cloud[i]) # output w = w + eta * y * (cloud[i] - y * w) # ojas rule return wcourse
[docs]def run_oja(n=10000, ratio=1., angle=0., do_plot=True): """Generates a point cloud and runs Oja's learning rule once. Optionally plots the result. Args: n (int, optional): number of points in the cloud ratio (float, optional): (std along the short axis) / (std along the long axis) angle (float, optional): rotation angle [deg] do_plot (bool, optional): plot the result """ cloud = make_cloud(n=n, ratio=ratio, angle=angle) wcourse = learn(cloud) if do_plot: # plot data cloud plt.scatter( cloud[:, 0], cloud[:, 1], marker='.', facecolor='none', edgecolor='#222222', alpha=.2 ) # color time and plot with colorbar time = np.arange(len(wcourse)) colors = plt.cm.cool(time/float(len(time))) sm = plt.cm.ScalarMappable( cmap=plt.cm.cool, norm=plt.Normalize(vmin=0, vmax=n) ) sm.set_array(time) cb = plt.colorbar(sm) cb.set_label("Datapoints") plt.scatter( wcourse[:, 0], wcourse[:, 1], facecolor=colors, edgecolor='none', lw=2 ) # ensure rectangular plot x_min = cloud[:, 0].min() x_max = cloud[:, 0].max() y_min = cloud[:, 1].min() y_max = cloud[:, 1].max() lims = [min(x_min, y_min), max(x_max, y_max)] plt.xlim(lims) plt.ylim(lims) plt.show()