# Code from Chapter 5 of Machine Learning: An Algorithmic Perspective (2nd Edition) # by Stephen Marsland (http://stephenmonika.net) # You are free to use, change, or redistribute the code in any way you wish for # non-commercial purposes, but please maintain the name of the original author. # This code comes with no warranty of any kind. # Stephen Marsland, 2008, 2014 import numpy as np import pcn import kmeans class rbf: """ The Radial Basis Function network Parameters are number of RBFs, and their width, how to train the network (pseudo-inverse or kmeans) and whether the RBFs are normalised""" def __init__(self,inputs,targets,nRBF,sigma=0,usekmeans=0,normalise=0): self.nin = np.shape(inputs)[1] self.nout = np.shape(targets)[1] self.ndata = np.shape(inputs)[0] self.nRBF = nRBF self.usekmeans = usekmeans self.normalise = normalise if usekmeans: self.kmeansnet = kmeans.kmeans(self.nRBF,inputs) self.hidden = np.zeros((self.ndata,self.nRBF+1)) if sigma==0: # Set width of Gaussians d = (inputs.max(axis=0)-inputs.min(axis=0)).max() self.sigma = d/np.sqrt(2*nRBF) else: self.sigma = sigma self.perceptron = pcn.pcn(self.hidden[:,:-1],targets) # Initialise network self.weights1 = np.zeros((self.nin,self.nRBF)) def rbftrain(self,inputs,targets,eta=0.25,niterations=100): if self.usekmeans==0: # Version 1: set RBFs to be datapoints indices = range(self.ndata) np.random.shuffle(indices) for i in range(self.nRBF): self.weights1[:,i] = inputs[indices[i],:] else: # Version 2: use k-means self.weights1 = np.transpose(self.kmeansnet.kmeanstrain(inputs)) for i in range(self.nRBF): self.hidden[:,i] = np.exp(-np.sum((inputs - np.ones((1,self.nin))*self.weights1[:,i])**2,axis=1)/(2*self.sigma**2)) if self.normalise: self.hidden[:,:-1] /= np.transpose(np.ones((1,np.shape(self.hidden)[0]))*self.hidden[:,:-1].sum(axis=1)) # Call Perceptron without bias node (since it adds its own) self.perceptron.pcntrain(self.hidden[:,:-1],targets,eta,niterations) def rbffwd(self,inputs): hidden = np.zeros((np.shape(inputs)[0],self.nRBF+1)) for i in range(self.nRBF): hidden[:,i] = np.exp(-np.sum((inputs - np.ones((1,self.nin))*self.weights1[:,i])**2,axis=1)/(2*self.sigma**2)) if self.normalise: hidden[:,:-1] /= np.transpose(ones((1,np.shape(hidden)[0]))*hidden[:,:-1].sum(axis=1)) # Add the bias hidden[:,-1] = -1 outputs = self.perceptron.pcnfwd(hidden) return outputs def confmat(self,inputs,targets): """Confusion matrix""" outputs = self.rbffwd(inputs) nClasses = np.shape(targets)[1] if nClasses==1: nClasses = 2 outputs = np.where(outputs>0,1,0) else: # 1-of-N encoding outputs = np.argmax(outputs,1) targets = np.argmax(targets,1) cm = np.zeros((nClasses,nClasses)) for i in range(nClasses): for j in range(nClasses): cm[i,j] = np.sum(np.where(outputs==i,1,0)*np.where(targets==j,1,0)) print cm print np.trace(cm)/np.sum(cm)