A python implementation for the MLP¶

MLP code based on Marsland (2014)

Contains:

    1. a perceptron class called pcn
    1. a Multi-layer perceptron class called mlp
    1. a test-case of the pcn
    1. a test-case of mlp classification
    1. an analytical testcase for mlp regression
    1. classification with the Iris data set
    1. classification with the MNIST data set

1. Perceptron class (PCN)¶

In [1]:
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))

def logic():
    import pcn
    """ Run AND and XOR logic functions"""

    a = np.array([[0,0,0],[0,1,0],[1,0,0],[1,1,1]])
    b = np.array([[0,0,0],[0,1,1],[1,0,1],[1,1,0]])

    p = pcn.pcn(a[:,0:2],a[:,2:])
    p.pcntrain(a[:,0:2],a[:,2:],0.25,10)
    p.confmat(a[:,0:2],a[:,2:])

    q = pcn.pcn(b[:,0:2],b[:,2:])
    q.pcntrain(b[:,0:2],b[:,2:],0.25,10)
    q.confmat(b[:,0:2],b[:,2:])

2. Multi-layer Perceptron class¶

In [2]:
class mlp:
    """ A Multi-Layer Perceptron"""
    
    def __init__(self,inputs,targets,nhidden,beta=1,momentum=0.9,outtype='logistic'):
        """ Constructor """
        # Set up network size
        self.nin = np.shape(inputs)[1]
        self.nout = np.shape(targets)[1]
        self.ndata = np.shape(inputs)[0]
        self.nhidden = nhidden

        self.beta = beta
        self.momentum = momentum
        self.outtype = outtype
    
        # Initialise network
        self.weights1 = (np.random.rand(self.nin+1,self.nhidden)-0.5)*2/np.sqrt(self.nin)
        self.weights2 = (np.random.rand(self.nhidden+1,self.nout)-0.5)*2/np.sqrt(self.nhidden)

    def earlystopping(self,inputs,targets,valid,validtargets,eta,niterations=100):
    
        valid = np.concatenate((valid,-np.ones((np.shape(valid)[0],1))),axis=1)
        
        old_val_error1 = 100002
        old_val_error2 = 100001
        new_val_error = 100000
        
        count = 0
        while (((old_val_error1 - new_val_error) > 0.001) or ((old_val_error2 - old_val_error1)>0.001)):
            count+=1
            print(count)
            self.mlptrain(inputs,targets,eta,niterations)
            old_val_error2 = old_val_error1
            old_val_error1 = new_val_error
            validout = self.mlpfwd(valid)
            new_val_error = 0.5*np.sum((validtargets-validout)**2)
            
        print("Stopped", new_val_error,old_val_error1, old_val_error2)
        return new_val_error
    
    def mlptrain(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)
        change = range(self.ndata)
    
        updatew1 = np.zeros((np.shape(self.weights1)))
        updatew2 = np.zeros((np.shape(self.weights2)))
            
        for n in range(niterations):
    
            self.outputs = self.mlpfwd(inputs)

            error = 0.5*np.sum((self.outputs-targets)**2)
            if (np.mod(n,100)==0):
                print("Iteration: ",n, " Error: ",error)    

            # Different types of output neurons
            if self.outtype == 'linear':
            	deltao = (self.outputs-targets)/self.ndata
            elif self.outtype == 'logistic':
            	deltao = self.beta*(self.outputs-targets)*self.outputs*(1.0-self.outputs)
            elif self.outtype == 'softmax':
                deltao = (self.outputs-targets)*(self.outputs*(-self.outputs)+self.outputs)/self.ndata 
            else:
            	print("error")
            
            deltah = self.hidden*self.beta*(1.0-self.hidden)*(np.dot(deltao,np.transpose(self.weights2)))
                      
            updatew1 = eta*(np.dot(np.transpose(inputs),deltah[:,:-1])) + self.momentum*updatew1
            updatew2 = eta*(np.dot(np.transpose(self.hidden),deltao)) + self.momentum*updatew2
            self.weights1 -= updatew1
            self.weights2 -= updatew2
                
            # Randomise order of inputs (not necessary for matrix-based calculation)
            #np.random.shuffle(change)
            #inputs = inputs[change,:]
            #targets = targets[change,:]
            
    def mlpfwd(self,inputs):
        """ Run the network forward """

        self.hidden = np.dot(inputs,self.weights1);
        self.hidden = 1.0/(1.0+np.exp(-self.beta*self.hidden))
        self.hidden = np.concatenate((self.hidden,-np.ones((np.shape(inputs)[0],1))),axis=1)

        outputs = np.dot(self.hidden,self.weights2);

        # Different types of output neurons
        if self.outtype == 'linear':
        	return outputs
        elif self.outtype == 'logistic':
            return 1.0/(1.0+np.exp(-self.beta*outputs))
        elif self.outtype == 'softmax':
            normalisers = np.sum(np.exp(outputs),axis=1)*np.ones((1,np.shape(outputs)[0]))
            return np.transpose(np.transpose(np.exp(outputs))/normalisers)
        else:
            print("error")

    def confmat(self,inputs,targets):
        """Confusion matrix"""

        # Add the inputs that match the bias node
        inputs = np.concatenate((inputs,-np.ones((np.shape(inputs)[0],1))),axis=1)
        outputs = self.mlpfwd(inputs)
        
        nclasses = np.shape(targets)[1]

        if nclasses==1:
            nclasses = 2
            outputs = np.where(outputs>0.5,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("Confusion matrix is:")
        print(cm)
        print("Percentage Correct: ",np.trace(cm)/np.sum(cm)*100)

3. Test the perceptron with the simple OR data-set¶

In [3]:
import pcn

inputs = np.array([[0,0],[0,1],[1,0],[1,1]])
targets = np.array([[0],[1],[1],[1]])
p = pcn.pcn(inputs,targets)
p.pcntrain(inputs,targets,0.25,6)
p.confmat(inputs,targets)
[[1. 0.]
 [0. 3.]]
1.0

4. Test the MLP with logical functions¶

In [4]:
import mlp

anddata = np.array([[0,0,0],[0,1,0],[1,0,0],[1,1,1]])
xordata = np.array([[0,0,0],[0,1,1],[1,0,1],[1,1,0]])

p = mlp.mlp(anddata[:,0:2],anddata[:,2:3],2)
p.mlptrain(anddata[:,0:2],anddata[:,2:3],0.25,1001)
p.confmat(anddata[:,0:2],anddata[:,2:3])

q = mlp.mlp(xordata[:,0:2],xordata[:,2:3],2,outtype='logistic')
q.mlptrain(xordata[:,0:2],xordata[:,2:3],0.25,5001)
q.confmat(xordata[:,0:2],xordata[:,2:3])
Iteration:  0  Error:  0.6618159664923471
Iteration:  100  Error:  0.036086772698034134
Iteration:  200  Error:  0.005904418340716359
Iteration:  300  Error:  0.003101659310278744
Iteration:  400  Error:  0.002073041089272464
Iteration:  500  Error:  0.0015455039974929217
Iteration:  600  Error:  0.0012267480155394254
Iteration:  700  Error:  0.0010141724128340756
Iteration:  800  Error:  0.000862709842149745
Iteration:  900  Error:  0.000749537186384387
Iteration:  1000  Error:  0.0006618900743824764
Confusion matrix is:
[[3. 0.]
 [0. 1.]]
Percentage Correct:  100.0
Iteration:  0  Error:  0.5284622827244535
Iteration:  100  Error:  0.4999815109186363
Iteration:  200  Error:  0.4998525988276532
Iteration:  300  Error:  0.49885050871017284
Iteration:  400  Error:  0.4333613423669407
Iteration:  500  Error:  0.02261114482925698
Iteration:  600  Error:  0.007540990729356722
Iteration:  700  Error:  0.004480061021622528
Iteration:  800  Error:  0.0031656638185134896
Iteration:  900  Error:  0.002438936930390839
Iteration:  1000  Error:  0.001979339655473407
Iteration:  1100  Error:  0.001663146645153137
Iteration:  1200  Error:  0.0014326451523058257
Iteration:  1300  Error:  0.0012573477228123805
Iteration:  1400  Error:  0.0011196557253057794
Iteration:  1500  Error:  0.0010087104660327299
Iteration:  1600  Error:  0.0009174541588458499
Iteration:  1700  Error:  0.0008411037168741077
Iteration:  1800  Error:  0.000776304399156597
Iteration:  1900  Error:  0.0007206347029906714
Iteration:  2000  Error:  0.0006723035849408142
Iteration:  2100  Error:  0.000629958224984818
Iteration:  2200  Error:  0.0005925579927014601
Iteration:  2300  Error:  0.000559289485973899
Iteration:  2400  Error:  0.0005295078459250057
Iteration:  2500  Error:  0.0005026953411109931
Iteration:  2600  Error:  0.0004784315751990495
Iteration:  2700  Error:  0.0004563716861133806
Iteration:  2800  Error:  0.0004362301452788212
Iteration:  2900  Error:  0.000417768549272445
Iteration:  3000  Error:  0.00040078630248749825
Iteration:  3100  Error:  0.00038511342323450655
Iteration:  3200  Error:  0.00037060492992246603
Iteration:  3300  Error:  0.0003571364171369403
Iteration:  3400  Error:  0.0003446005377107875
Iteration:  3500  Error:  0.00033290418168676776
Iteration:  3600  Error:  0.00032196619642243276
Iteration:  3700  Error:  0.00031171553060754337
Iteration:  3800  Error:  0.0003020897130942973
Iteration:  3900  Error:  0.00029303359820304206
Iteration:  4000  Error:  0.0002844983246425753
Iteration:  4100  Error:  0.00027644044682890436
Iteration:  4200  Error:  0.00026882120622393103
Iteration:  4300  Error:  0.00026160591707840696
Iteration:  4400  Error:  0.00025476344617866755
Iteration:  4500  Error:  0.000248265770247643
Iteration:  4600  Error:  0.0002420875978191728
Iteration:  4700  Error:  0.00023620604489903372
Iteration:  4800  Error:  0.00023060035570222017
Iteration:  4900  Error:  0.00022525166133032372
Iteration:  5000  Error:  0.00022014277051455973
Confusion matrix is:
[[2. 0.]
 [0. 2.]]
Percentage Correct:  100.0
  • The first thing that we can do is check that this MLP can indeed learn the logic functions, especially the XOR.

  • There are a few things to notice about this.

  • One is that it does work, producing the correct answers, but the other is that even for the AND we need significantly more iterations than we did for the Perceptron.

  • So the benefits of a more complex network come at a cost, because it takes substantially more computational time to fit those weights to solve the problem, even for linear examples.

  • Sometimes, even 5000 iterations are not enough for the XOR function, and more have to be added.

5. A simple regression problem¶

  • The regression problem we will look at is a very simple one.

  • We will take a set of samples generated by a simple mathematical function, and try to learn the generating function (that describes how the data was made) so that we can find the values of any inputs, not just the ones we have training data for.

  • The function that we will use is a very simple one, just a bit of a sine wave.

  • Before getting started, we need to normalize the data separate the data into training, testing, validation sets.

  • For this example there are only 40 data points

  • We use half of them as the training set, although that isn’t very many and might not be enough for the algorithm to learn effectively.

  • We can split the data in the ratio 50:25:25 by using the odd-numbered elements as training data, the even-numbered ones that do not divide by 4 for testing, and the rest for validation.

In [8]:
# Set up the data
import pylab as pl
%matplotlib inline


x = np.linspace(0,1,40).reshape((40,1))
t = np.sin(2*np.pi*x) + np.cos(4*np.pi*x) + np.random.randn(40).reshape((40,1))*0.2
x = (x-0.5)*2

# Split into training, testing, and validation sets
train = x[0::2,:]
test = x[1::4,:]
valid = x[3::4,:]
traintarget = t[0::2,:]
testtarget = t[1::4,:]
validtarget = t[3::4,:]

# Plot the data
pl.plot(x,t,'o')
pl.xlabel('x')
pl.ylabel('t')

# Perform basic training with a small MLP
import mlp
net = mlp.mlp(train,traintarget,3,outtype='linear')
net.mlptrain(train,traintarget,0.25,101)

# Use early stopping
net.earlystopping(train,traintarget,valid,validtarget,0.25)

pl.show()
Iteration:  0  Error:  14.437878302676902
Iteration:  100  Error:  6.8148976595570465
1
Iteration:  0  Error:  6.813421632448891
2
Iteration:  0  Error:  6.541211827213872
3
Iteration:  0  Error:  5.34358329205848
4
Iteration:  0  Error:  2.0209104443773884
5
Iteration:  0  Error:  1.550299557646615
6
Iteration:  0  Error:  1.5055229676770758
7
Iteration:  0  Error:  1.4910363523943921
8
Iteration:  0  Error:  1.4790768345734988
9
Iteration:  0  Error:  1.4654764135339695
10
Iteration:  0  Error:  1.4483080422671784
11
Iteration:  0  Error:  1.4250046462781791
12
Iteration:  0  Error:  1.3908198927490065
13
Iteration:  0  Error:  1.3360807256621505
14
Iteration:  0  Error:  1.2440869405074193
15
Iteration:  0  Error:  1.1060517114813613
16
Iteration:  0  Error:  0.9542063743880459
17
Iteration:  0  Error:  0.8365044272608969
18
Iteration:  0  Error:  0.760240623515487
19
Iteration:  0  Error:  0.7101517395434356
20
Iteration:  0  Error:  0.6746984674655385
21
Iteration:  0  Error:  0.647711598198839
22
Iteration:  0  Error:  0.6257111565766248
23
Iteration:  0  Error:  0.6065633585813781
24
Iteration:  0  Error:  0.5889451060366812
25
Iteration:  0  Error:  0.5721879440097721
26
Iteration:  0  Error:  0.5562271155580282
27
Iteration:  0  Error:  0.5413008115991439
28
Iteration:  0  Error:  0.5275249673308112
29
Iteration:  0  Error:  0.514855855710624
30
Iteration:  0  Error:  0.5032225804382612
31
Iteration:  0  Error:  0.4925578538161721
32
Iteration:  0  Error:  0.4827944372963597
33
Iteration:  0  Error:  0.473865031353268
34
Iteration:  0  Error:  0.4657036295203718
35
Iteration:  0  Error:  0.4582466322044212
36
Iteration:  0  Error:  0.45143358632755254
37
Iteration:  0  Error:  0.4452076401184612
38
Iteration:  0  Error:  0.4395157887411533
39
Iteration:  0  Error:  0.4343089641373241
40
Iteration:  0  Error:  0.4295420090745633
41
Iteration:  0  Error:  0.42517356704960546
42
Iteration:  0  Error:  0.42116591356632016
43
Iteration:  0  Error:  0.417484749231345
44
Iteration:  0  Error:  0.4140989707219112
45
Iteration:  0  Error:  0.4109804319002091
46
Iteration:  0  Error:  0.40810370416486896
47
Iteration:  0  Error:  0.4054458425207621
Stopped 0.18173513997598373 0.18258568482277177 0.183516175697587
No description has been provided for this image

6. Iris data set¶

  • Iris Data set
In [6]:
def preprocessIris(infile,outfile):

    stext1 = 'Iris-setosa'
    stext2 = 'Iris-versicolor'
    stext3 = 'Iris-virginica'
    rtext1 = '0'
    rtext2 = '1'
    rtext3 = '2'

    fid = open(infile,"r")
    oid = open(outfile,"w")

    for s in fid:
        if s.find(stext1)>-1:
            oid.write(s.replace(stext1, rtext1))
        elif s.find(stext2)>-1:
            oid.write(s.replace(stext2, rtext2))
        elif s.find(stext3)>-1:
            oid.write(s.replace(stext3, rtext3))
    fid.close()
    oid.close()

iris = np.loadtxt('iris_proc.data',delimiter=',')
iris[:,:4] = iris[:,:4]-iris[:,:4].mean(axis=0)
imax = np.concatenate((iris.max(axis=0)*np.ones((1,5)),np.abs(iris.min(axis=0)*np.ones((1,5)))),axis=0).max(axis=0)
iris[:,:4] = iris[:,:4]/imax[:4]
print(iris[0:5,:])

# Split into training, validation, and test sets
target = np.zeros((np.shape(iris)[0],3));
indices = np.where(iris[:,4]==0) 
target[indices,0] = 1
indices = np.where(iris[:,4]==1)
target[indices,1] = 1
indices = np.where(iris[:,4]==2)
target[indices,2] = 1

# Randomly order the data
order = list(range(np.shape(iris)[0])) ## python 3

np.random.shuffle(order)
iris = iris[order,:]
target = target[order,:]

train = iris[::2,0:4]
traint = target[::2]
valid = iris[1::4,0:4]
validt = target[1::4]
test = iris[3::4,0:4]
testt = target[3::4]

#print train.max(axis=0), train.min(axis=0)

# Train the network
import mlp
net = mlp.mlp(train,traint,5,outtype='logistic')
net.earlystopping(train,traint,valid,validt,0.1)
net.confmat(test,testt)
[[-0.36142626  0.33135215 -0.7508489  -0.76741803  0.        ]
 [-0.45867099 -0.04011887 -0.7508489  -0.76741803  0.        ]
 [-0.55591572  0.10846954 -0.78268251 -0.76741803  0.        ]
 [-0.60453809  0.03417533 -0.71901528 -0.76741803  0.        ]
 [-0.41004862  0.40564636 -0.7508489  -0.76741803  0.        ]]
1
Iteration:  0  Error:  27.85876371042035
2
Iteration:  0  Error:  0.8588027183203476
3
Iteration:  0  Error:  0.8087335777800588
4
Iteration:  0  Error:  0.7804345320771774
5
Iteration:  0  Error:  0.7565409228767828
6
Iteration:  0  Error:  0.7332850016967905
Stopped 0.5200484099764903 0.48591244121928984 0.47552591774260605
Confusion matrix is:
[[12.  0.  0.]
 [ 0. 12.  1.]
 [ 0.  0. 12.]]
Percentage Correct:  97.2972972972973

7. MNIST Data Set¶

In [7]:
# Read the dataset in 
import pickle, gzip

f = gzip.open('mnist.pkl.gz','rb')
tset, vset, teset = pickle.load(f, encoding='iso-8859-1')
f.close()

nread = 200
# Just use the first few images
train_in = tset[0][:nread,:]

# This is a little bit of work -- 1 of N encoding
# Make sure you understand how it does it
train_tgt = np.zeros((nread,10))
for i in range(nread):
    train_tgt[i,tset[1][i]] = 1

test_in = teset[0][:nread,:]
test_tgt = np.zeros((nread,10))
for i in range(nread):
    test_tgt[i,teset[1][i]] = 1

# We will need the validation set
valid_in = vset[0][:nread,:]
valid_tgt = np.zeros((nread,10))
for i in range(nread):
    valid_tgt[i,vset[1][i]] = 1

for i in [1,2,5,10,20]:  
    print("----- "+str(i))  
    net = mlp.mlp(train_in,train_tgt,i,outtype='softmax')
    net.earlystopping(train_in,train_tgt,valid_in,valid_tgt,0.1)
    net.confmat(test_in,test_tgt)
----- 1
1
Iteration:  0  Error:  93.50345094775088
2
Iteration:  0  Error:  87.72037197671762
3
Iteration:  0  Error:  84.3637449121243
4
Iteration:  0  Error:  81.99595899635365
5
Iteration:  0  Error:  80.90650512770571
6
Iteration:  0  Error:  80.36903547074485
7
Iteration:  0  Error:  80.05671426365132
8
Iteration:  0  Error:  79.84834145706871
9
Iteration:  0  Error:  79.69563323834407
10
Iteration:  0  Error:  79.57441443848222
11
Iteration:  0  Error:  79.46993247427072
12
Iteration:  0  Error:  79.37303388543086
13
Iteration:  0  Error:  79.27721774784663
14
Iteration:  0  Error:  79.17703483201717
15
Iteration:  0  Error:  79.06690063433575
16
Iteration:  0  Error:  78.94068735356247
17
Iteration:  0  Error:  78.79410375103923
18
Iteration:  0  Error:  78.62379683281287
19
Iteration:  0  Error:  78.41349623046695
Stopped 82.79436172810469 82.62874597616613 82.60477340130558
Confusion matrix is:
[[15.  0.  2.  3.  0.  8.  0.  0.  0.  0.]
 [ 0. 27.  9.  4. 21.  3. 17. 22.  8. 19.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 2.  1.  5.  9.  7.  9.  3.  2.  2.  2.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]
Percentage Correct:  25.5
----- 2
1
Iteration:  0  Error:  91.31230716670908
2
Iteration:  0  Error:  86.82705006124746
3
Iteration:  0  Error:  82.58360146042332
4
Iteration:  0  Error:  78.28608818003069
5
Iteration:  0  Error:  74.67374734492375
6
Iteration:  0  Error:  71.42985027440125
7
Iteration:  0  Error:  68.53218265749801
8
Iteration:  0  Error:  65.70613485899916
9
Iteration:  0  Error:  63.34032233606375
10
Iteration:  0  Error:  61.53024680510222
11
Iteration:  0  Error:  60.04936169056043
12
Iteration:  0  Error:  58.75906352965477
13
Iteration:  0  Error:  57.59498696677018
14
Iteration:  0  Error:  56.523760035387276
15
Iteration:  0  Error:  55.49204191205198
16
Iteration:  0  Error:  54.46375192779306
17
Iteration:  0  Error:  53.43066217096275
18
Iteration:  0  Error:  52.42994447364381
19
Iteration:  0  Error:  51.5600862283865
20
Iteration:  0  Error:  50.83237207207675
21
Iteration:  0  Error:  50.17263054048831
Stopped 70.92805522531384 70.82440214418533 70.7583502165412
Confusion matrix is:
[[16.  0.  7.  2.  2.  5.  0.  0.  0.  1.]
 [ 0. 28.  0.  0.  0.  0.  0.  1.  2.  2.]
 [ 0.  0.  1.  0.  0.  0.  1.  0.  0.  0.]
 [ 0.  0.  3. 10.  0. 11.  0.  0.  0.  0.]
 [ 1.  0.  0.  1.  4.  2.  2.  1.  4.  1.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  2.  0. 11.  0. 16. 19.  0. 11.]
 [ 0.  0.  3.  2.  0.  2.  0.  1.  1.  0.]
 [ 0.  0.  0.  1. 11.  0.  1.  2.  3.  6.]]
Percentage Correct:  42.5
----- 5
1
Iteration:  0  Error:  91.90741132107524
2
Iteration:  0  Error:  84.52575344113112
3
Iteration:  0  Error:  71.97857012944569
4
Iteration:  0  Error:  56.30921190198384
5
Iteration:  0  Error:  45.34021489274716
6
Iteration:  0  Error:  37.3762447181638
7
Iteration:  0  Error:  31.803538184401752
8
Iteration:  0  Error:  27.86265964180926
9
Iteration:  0  Error:  24.44295027268778
10
Iteration:  0  Error:  21.53781221493294
11
Iteration:  0  Error:  19.558312633398472
12
Iteration:  0  Error:  17.76816178259464
13
Iteration:  0  Error:  15.867076495844987
14
Iteration:  0  Error:  14.349932974255383
15
Iteration:  0  Error:  13.594411274520773
16
Iteration:  0  Error:  13.217805935135864
Stopped 45.06513578966635 44.84691241941947 44.82092047063506
Confusion matrix is:
[[14.  0.  2.  1.  0.  3.  0.  0.  0.  0.]
 [ 0. 27.  3.  1.  0.  0.  0.  1.  1.  1.]
 [ 1.  0.  5.  5.  0.  3.  0.  0.  0.  0.]
 [ 0.  0.  2.  7.  0.  0.  0.  0.  0.  0.]
 [ 0.  1.  2.  0. 21.  3.  6.  0.  3.  6.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  1.  1. 12.  0.  2.  0.]
 [ 1.  0.  2.  2.  1.  1.  1. 20.  0.  5.]
 [ 0.  0.  0.  0.  0.  8.  0.  0.  4.  0.]
 [ 0.  0.  0.  0.  5.  1.  1.  3.  0.  9.]]
Percentage Correct:  59.5
----- 10
1
Iteration:  0  Error:  90.37954591797723
2
Iteration:  0  Error:  81.7998678618191
3
Iteration:  0  Error:  62.97120258699593
4
Iteration:  0  Error:  45.025031274502986
5
Iteration:  0  Error:  33.50456395760865
6
Iteration:  0  Error:  26.818332535300335
7
Iteration:  0  Error:  22.327297567861194
8
Iteration:  0  Error:  19.198277441417282
9
Iteration:  0  Error:  16.743092400915355
10
Iteration:  0  Error:  13.233340741833711
11
Iteration:  0  Error:  10.878871531542078
12
Iteration:  0  Error:  9.934592869721657
13
Iteration:  0  Error:  9.346293092632708
14
Iteration:  0  Error:  8.899692479130078
15
Iteration:  0  Error:  8.504943246928146
16
Iteration:  0  Error:  8.100279303463523
17
Iteration:  0  Error:  7.626982259460561
18
Iteration:  0  Error:  6.9609361912438406
19
Iteration:  0  Error:  5.885195399904973
20
Iteration:  0  Error:  4.328664481510707
21
Iteration:  0  Error:  3.0669389437438044
22
Iteration:  0  Error:  2.4382627887905466
23
Iteration:  0  Error:  2.07969527940988
24
Iteration:  0  Error:  1.835324971723452
25
Iteration:  0  Error:  1.6559173770199433
26
Iteration:  0  Error:  1.5156730349314973
27
Iteration:  0  Error:  1.4017927593068646
28
Iteration:  0  Error:  1.3097172697184971
29
Iteration:  0  Error:  1.235842151903839
Stopped 37.97445556555277 37.94713293165062 37.93937959887576
Confusion matrix is:
[[14.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0. 28.  0.  0.  0.  0.  0.  1.  1.  0.]
 [ 2.  0. 11.  3.  0.  0.  1.  0.  1.  0.]
 [ 0.  0.  2. 12.  0.  7.  0.  0.  0.  0.]
 [ 0.  0.  1.  1. 20.  5.  7.  3.  0.  6.]
 [ 0.  0.  0.  0.  0.  1.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.  2. 11.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.  1.  0. 15.  0.  0.]
 [ 0.  0.  1.  0.  0.  4.  0.  0.  7.  1.]
 [ 0.  0.  0.  0.  8.  0.  1.  5.  1. 14.]]
Percentage Correct:  66.5
----- 20
1
Iteration:  0  Error:  90.85549016597358
2
Iteration:  0  Error:  79.88779181604491
3
Iteration:  0  Error:  54.084256646387
4
Iteration:  0  Error:  35.541504571546085
5
Iteration:  0  Error:  26.627175790861422
6
Iteration:  0  Error:  21.80238903847482
7
Iteration:  0  Error:  18.68064714476875
8
Iteration:  0  Error:  15.195345396076963
9
Iteration:  0  Error:  11.107768948891128
10
Iteration:  0  Error:  9.728788605762254
11
Iteration:  0  Error:  8.977134453736515
12
Iteration:  0  Error:  8.437374665241805
13
Iteration:  0  Error:  7.938252950852255
14
Iteration:  0  Error:  7.342558504390125
15
Iteration:  0  Error:  6.394191116942074
16
Iteration:  0  Error:  4.401202914758112
17
Iteration:  0  Error:  2.7817190085197256
18
Iteration:  0  Error:  2.7524599548032636
Stopped 37.53671979117725 37.30682683669154 36.95346626067327
Confusion matrix is:
[[15.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0. 28.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 2.  0. 13.  1.  0.  1.  1.  0.  1.  0.]
 [ 0.  0.  0. 13.  0. 11.  0.  0.  0.  0.]
 [ 0.  0.  1.  0. 23.  5.  8.  0.  0.  6.]
 [ 0.  0.  0.  0.  0.  2.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0. 11.  0.  0.  0.]
 [ 0.  0.  2.  2.  0.  1.  0. 20.  0.  6.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  8.  0.]
 [ 0.  0.  0.  0.  5.  0.  0.  4.  1.  9.]]
Percentage Correct:  71.0
In [ ]: