A python implementation for the MLP¶
MLP code based on Marsland (2014)
Contains:
- a perceptron class called pcn
- a Multi-layer perceptron class called mlp
- a test-case of the pcn
- a test-case of mlp classification
- an analytical testcase for mlp regression
- classification with the Iris data set
- classification with the MNIST data set
1. Perceptron class (PCN)¶
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¶
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¶
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¶
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.
# 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
6. Iris data set¶
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¶
# 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