diff --git a/.gitignore b/.gitignore index 1dbc687..3a18ad8 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,5 @@ target/ #Ipython Notebook .ipynb_checkpoints + +.*.swp diff --git a/ch3/or.py b/ch3/or.py new file mode 100755 index 0000000..8afd7a0 --- /dev/null +++ b/ch3/or.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +import numpy as np +import pcn_logic_eg as pcn + +def main(): + #or_training = np.array( [ [0,0,0], [1,0,1], [0,1,1], [1,1,1] ]) + or_inputs = np.array( [[0,0], [0,1], [1,0], [1,1]]) + or_targets = np.array([[0],[1],[1],[1]]) + + #p = pcn.pcn(a[:,0:2], a[:,2:]) + p = pcn.pcn(or_inputs, or_targets) + #p.pcntrain(a[:,0:2], a[:, 2:], 0.25, 10) + p.pcntrain(or_inputs, or_targets, 0.25, 10) + print "confusion matrix" + p.confmat(or_inputs, or_targets) + + print "doing" + print " for " + print or_inputs + inputs_bias = np.concatenate((or_inputs,-np.ones((np.shape(or_inputs)[0],1))), axis=1) + print " results" + print p.pcnfwd(inputs_bias) + + +main() diff --git a/ch3/pcn.py b/ch3/pcn.py new file mode 100644 index 0000000..7022752 --- /dev/null +++ b/ch3/pcn.py @@ -0,0 +1,85 @@ +# Code from Chapter 3 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 + +class pcn: + """ A basic Perceptron""" + + def __init__(self,inputs,targets): + """ Constructor """ + # Set up network size + if np.ndim(inputs)>1: + self.nIn = np.shape(inputs)[1] + else: + self.nIn = 1 + + if np.ndim(targets)>1: + self.nOut = np.shape(targets)[1] + else: + self.nOut = 1 + + self.nData = np.shape(inputs)[0] + + # Initialise network + self.weights = np.random.rand(self.nIn+1,self.nOut)*0.1-0.05 + + def pcntrain(self,inputs,targets,eta,nIterations): + """ Train the thing """ + # Add the inputs that match the bias node + inputs = np.concatenate((inputs,-np.ones((self.nData,1))),axis=1) + # Training + change = range(self.nData) + + for n in range(nIterations): + + self.activations = self.pcnfwd(inputs); + self.weights -= eta*np.dot(np.transpose(inputs),self.activations-targets) + + # Randomise order of inputs + #np.random.shuffle(change) + #inputs = inputs[change,:] + #targets = targets[change,:] + + #return self.weights + + def pcnfwd(self,inputs): + """ Run the network forward """ + # Compute activations + activations = np.dot(inputs,self.weights) + + # Threshold the activations + return np.where(activations>0,1,0) + + + def confmat(self,inputs,targets): + """Confusion matrix""" + + # Add the inputs that match the bias node + inputs = np.concatenate((inputs,-np.ones((self.nData,1))),axis=1) + + outputs = np.dot(inputs,self.weights) + + 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) diff --git a/ch3/pcn_logic_eg.py b/ch3/pcn_logic_eg.py new file mode 100644 index 0000000..36b931f --- /dev/null +++ b/ch3/pcn_logic_eg.py @@ -0,0 +1,86 @@ +# Code from Chapter 3 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 + +class pcn: + """ A basic Perceptron (the same pcn.py except with the weights printed + and it does not reorder the inputs)""" + + def __init__(self,inputs,targets): + """ Constructor """ + # Set up network size + if np.ndim(inputs)>1: + self.nIn = np.shape(inputs)[1] + else: + self.nIn = 1 + + if np.ndim(targets)>1: + self.nOut = np.shape(targets)[1] + else: + self.nOut = 1 + + self.nData = np.shape(inputs)[0] + + # Initialise network + self.weights = np.random.rand(self.nIn+1,self.nOut)*0.1-0.05 + + def pcntrain(self,inputs,targets,eta,nIterations): + """ Train the thing """ + # Add the inputs that match the bias node + inputs = np.concatenate((inputs,-np.ones((self.nData,1))),axis=1) + + # Training + change = range(self.nData) + + for n in range(nIterations): + + self.activations = self.pcnfwd(inputs); + self.weights -= eta*np.dot(np.transpose(inputs),self.activations-targets) + print "Iteration: ", n + print self.weights + + activations = self.pcnfwd(inputs) + print "Final outputs are:" + print activations + #return self.weights + + def pcnfwd(self,inputs): + """ Run the network forward """ + + # Compute activations + activations = np.dot(inputs,self.weights) + + # Threshold the activations + return np.where(activations>0,1,0) + + def confmat(self,inputs,targets): + """Confusion matrix""" + + # Add the inputs that match the bias node + inputs = np.concatenate((inputs,-np.ones((self.nData,1))),axis=1) + outputs = np.dot(inputs,self.weights) + + 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) diff --git a/ch3/xor.py b/ch3/xor.py new file mode 100755 index 0000000..70986e1 --- /dev/null +++ b/ch3/xor.py @@ -0,0 +1,23 @@ +#!/usr/bin/python + +import numpy as np +import pcn_logic_eg as pcn + +def main(): + or_inputs = np.array( [[0,0], [0,1], [1,0], [1,1]]) + or_targets = np.array([[0],[1],[1],[0]]) + + p = pcn.pcn(or_inputs, or_targets) + p.pcntrain(or_inputs, or_targets, 0.25, 10) + print "confusion matrix" + p.confmat(or_inputs, or_targets) + + print "doing" + print " for " + print or_inputs + inputs_bias = np.concatenate((or_inputs,-np.ones((np.shape(or_inputs)[0],1))), axis=1) + print " results" + print p.pcnfwd(inputs_bias) + + +main()