Het kost weer even moeite om de data 'om te bouwen' voor gebruik in een neuraal netwerk. Ik besluit gebruik te maken van Lasagne omdat het tot zeer overzichtelijke code leidt. Dat kan een chaoot als ik wel gebruiken. :-)
Onderwater werkt Lasagne met Theano waardoor mijn grafische processor weer mee kan werken. Dat moet snelheidswinst opleveren. Wel moet ik het datatype daarvoor omzetten naar 'float32'. Gek genoeg werkt X = np.asarray(X, type=float32) niet. Gelukkig kom ik er snel achter dat X=X.astype(np.float32) wel werkt. Raar!
De 'fit' functie van Lasagna werkt al snel. Ik kan de 'predict' functie echter niet zo snel aan de praat krijgen. Het blijkt een oude, bekende fout. Om het juiste inputdatatype te gebruiken moet er een range van 1 groot worden opgegeven. Bijvoorbeeld :
pred = net1.predict(X[si+i:si+i+1]) . Die was ik, volgens mij bij het neuraal bewerken van de Titanic, ook al eens tegengekomen.
Een 2e uitdaging blijkt om de output(hier 'pred') verder te verwerken. Ik krijg bijvoorbeeld dit resultaat: pred = [[ 41.93833542 -87.64888 ]]. Daar ontbreekt een komma! Uiteindelijk vind ik de functie 'tolist()': Die plaatst er gelukkig weer kommas bij. Ik gebruik hem met een verwijzing naar de eerste rij in het array. pred = pred[0].tolist() Dat zorgt voor de verwerking van de dubbele haken. Met lpred, bpred = pred[0], pred[1] kan ik vervolgens de lengte en breedte graad uit elkaar halen. Draaien maar!
Het eerste wat opvalt is de snelheid! In slechts enkele seconden resultaat. En niet eens zo slecht:
NN:
count 1329.000000
mean 6.280502
std 3.284298
min 0.057225
25% 3.642903
50% 6.513905
75% 8.674468
max 12.038028
Al iets beter dan de Support Vector Machine en wel, denk ik, 100x zo snel!:
SVM:
count 443.000000
mean 6.405327
std 3.505544
min 0.067581
25% 3.960455
50% 6.419669
75% 8.952459
max 17.101152
Hoewel ik 400 'epochs' (Een soort minibatches om het NN te leren) heb gekozen omdat het voorbeeld dat aangaf blijkt hij er maar 7 nodig te hebben voor het eindresultaat. Lasagne geeft daar automatisch een mooi rapport over:
input (None, 8) produces 8 outputs
hidden (None, 100) produces 100 outputs
output (None, 2) produces 2 outputs
epoch train loss valid loss train/val dur
------- ------------------ ------------ ------------ -----
1 214542254080.00000 515777.40625 415959.00000 0.06s
2 1944574.12500 354.51895 5485.10645 0.07s
3 391.01468 0.13764 2840.84082 0.07s
4 0.07900 0.00129 61.01440 0.07s
5 0.00122 0.00125 0.98046 0.06s
6 0.00121 0.00125 0.96734 0.07s
7 0.00121 0.00125 0.96732 0.07s
8 0.00121 0.00125 0.96732 0.07s
Na 7 epochs leert 'hij' niets meer bij. Hmmmmm ... Nu maar eens lekker aan de parameters sleutelen. 100 hidden layers of 16 blijkt nu niets uit te maken. De grootste winst boek ik door de 'update_learning_rate' sterk te verkleinen van 0.01 naar 0.000001. Dat lijkt intuïtief ook wel logisch omdat de Lenkte- en Breedtegraad natuurlijk feitelijk heel grote getallen zijn in verhouding met de busverplaatsingen. Per leermoment moet er dus niet te grote stappen worden gemaakt. Nu lijkt hij wel lekker tot de laatste epoch door te leren. Door de snelheid is het leuk om allerlei variaties uit te proberen. Ik zet de hidden units weer op 100. Na 400 epochs is dit het resultaat:
count 1329.000000
mean 4.286737
std 2.489372
min 0.183120
25% 2.245341
50% 4.071879
75% 6.276527
max 14.031579
Kijk, daar kunnen we al mee thuiskomen :-) Even lekker verder testen.
Oh ja, de code weer:
#execfile('/Users/DWW/Documents/Follow1bus outlier neural.py')
import webbrowser
import time
import numpy as np
from sklearn.externals import joblib
from sklearn import svm
import pandas as pd
Data = joblib.load('/Users/DWW/Documents/Bus_outlier.pkl')
Data = np.array(sorted(Data, key = lambda x: (x[0], x[1])))
busses = sorted(list(set([Colm[0] for Colm in Data])))
def dist(est,real):
if real == 0:
perc = 0
else:
perc = np.absolute(100* (real-est)/real)
dis = np.absolute(real-est) * 1.852 * 60
return est, real, perc, dis
def tim(int):
if len(int) == 7:
int = '0' + int
hr = int[0:2]
mi = int[3:5]
ds = int[6:8]
if int[6:8] == 'PM':
ds = 12
else:
ds = 0
return float(ds) + float(hr) + (float(mi)/100)
X = np.array([0.,0.,0.,0.,0.,0.,0.,0.])
Y = np.array([0.,0.])
t = 0
for i in busses:
HData = Data[Data[:,0]==i]
if len(HData) > 5: # Alleen voor bussen waar meer dan 5 waarnemengen van zijn.
for j in range(len(HData)-4):
if tim(HData[j+4][1])-tim(HData[j][1]) < 14.: # Alleen de waarnemeningen die inderdaad in tijd bij elkaar liggen. Feitelijk maximaal 8 minuten : 14 genomen voor marge
X = np.vstack((X,[float(HData[j][2]), float(HData[j+1][2]), float(HData[j+2][2]), float(HData[j+3][2]), float(HData[j][3]), float(HData[j+1][3]), float(HData[j+2][3]), float(HData[j+3][3])]))
Y = np.vstack((Y,[float(HData[j+4][2]),float(HData[j+4][3])]))
else:
t += 1
si = -.1 * len(X)
print 'Aantal records in dataset (X) =', len(X), 'Aantal in testset (si) =', si
X = X.astype(np.float32)
Y = Y.astype(np.float32)
# Voor het neuraal nw maar eens Lasagne proberen.
from lasagne import layers
from lasagne.updates import nesterov_momentum
from nolearn.lasagne import NeuralNet
net1 = NeuralNet(
layers=[ # three layers: one hidden layer
('input', layers.InputLayer),
('hidden', layers.DenseLayer),
('output', layers.DenseLayer),
],
# layer parameters:
input_shape=(None, 8), # 8 input values per batch
hidden_num_units=100, # number of units in hidden layer
output_nonlinearity=None, # output layer uses identity function
output_num_units=2, # 2 target values - lengte , breedte
# optimization method:
update=nesterov_momentum,
update_learning_rate=0.000001,
update_momentum=0.9,
regression=True, # flag to indicate we're dealing with regression problem
max_epochs=400, # we want to train this many epochs
verbose=1,
)
net1.fit(X[1:si], Y[1:si])
Tdist = np.array([])
for i in range(len(X[si:])-1):
pred = net1.predict(X[si+i:si+i+1])
pred = pred[0].tolist()
lpred, bpred = pred[0], pred[1]
l_est, l_real, l_perc, l_dis = dist(lpred, Y[si+i][0])
b_est, b_real, b_perc, b_dis = dist(bpred, Y[si+i][1])
Tdist = np.append(Tdist, [l_dis + b_dis])
Td = pd.DataFrame(Tdist)
print(Td.describe())
Geen opmerkingen:
Een reactie posten