Source code for pymlp.mlp.FFNetwork

"""
Multilayer Perceptron implementation.
"""

import numpy as np
from functools import partial


[docs]class FFNetwork: """Simple feed forward Multilayer Perceptron (MLP) implementation.""" def __init__(self, shape, transferFunctions, alpha): """ Initializes the network with values from a uniform distribution between [-0.3,0.3]. Parameters: shape -- the shape of the network, e.g. (2, 3, 1) for 2 input nodes, 3 hidden nodes and 1 output node. transferFunctions -- the transfer functions between the layers of nodes. alpha -- the learning rate of this network """ assert len(shape) == len(transferFunctions) + 1 self.shape = shape # Make sure, it does use its own random number seed randomState = np.random.RandomState() # b = math.sqrt(shape[0]) b = 0.1 self.weights = [randomState.uniform(- b, b, (shape[i] + 1, shape[i + 1])) for i in xrange(len(shape) - 1)] self.transferFunctions = transferFunctions self.alpha = alpha # used to cache the activation of every forward step self.O = list()
[docs] def feedForward(self, x): """ Runs forward through the network and caches the A of each layer in the list A. Parameters: x -- the input value to run through the network returns -- the networks outputs """ assert x.ndim == 2, "%s == 2" % x.ndim # I want activations to be a row vector activations = x transposed = activations.T if len(self.O) > 0 and (self.O[0] == transposed).all(): return self.O[-1].T else: self.O = list() self.O.append(transposed) for i in xrange(len(self.weights)): w = self.weights[i] transferFunction = self.transferFunctions[i] assert activations.ndim == 2, "%s: %s == %s" % (i, activations.ndim, 2) # include bias activations = np.concatenate((activations, [[-1]]), axis=1) assert activations.shape[1] == w.shape[0], "%s: %s == %s" % \ (i, activations.shape[1], w.shape[0]) activations = np.dot(activations, w) activations = transferFunction.f(activations) self.O.append(activations.T) return activations
[docs] def propagateBack(self, error): """ Implementation according to (Rojas, 1996, p. 170 ff.). Parameters: error -- the error to propagate back. """ assert error.ndim == 2, "%s == 2" % error.ndim self.propagateBackBatch(error, self.O) self.O = list()
[docs] def propagateBackBatch(self, error, O): """ Implements batch learning. However, it must be called for every data-point separately. Based on (Rojas, 1996, p. 170 ff.).: Parameters: error -- the error to propagate back O -- the outputs of every layer of the MLP. """ assert error.ndim == 2, "%s == 2" % error.ndim e = error.T # use column vectors to stay close to the book for i in xrange(len(self.weights) - 1, - 1, - 1): transferFunction = self.transferFunctions[i] D = (np.identity(O[i + 1].shape[0]) * transferFunction.df(O[i + 1])) delta = np.dot(D, e) e = np.dot(self.weights[i], delta) # add bias, because it was an input ohat = np.concatenate((O[i], [[-1]]), axis=0) deltaW = self.alpha * np.dot(delta, ohat.T).T self.weights[i] += deltaW # remove the result, based on the bias, because it is part of the # previous output e = e[:-1]
[docs] def clone(self): """Returns a clone of this network.""" clone = FFNetwork(self.shape, np.copy(self.transferFunctions), self.alpha) clone.weights = map(np.copy, self.weights) return clone
[docs] def save(self, filetemplate): """ Saves the weights into files based on the filetemplate. Parameters: filetemplate -- to add the layer number to save in. """ for i, weights in enumerate(self.weights): np.savetxt(filetemplate.format(i), weights)
[docs] def load(self, files): """ Loads the weights of the given files. Parameters: files -- a list of files to read the weights """ # np.loadtxt of column vector returns a row vector self.weights = map(partial(np.loadtxt, ndmin=2), files)