woensdag 27 april 2016

3D locatiebepaling

De wens om iets met computer vision en deep learning te doen leeft al wat langer bij mij. Ik ben opnieuw eens gaan kijken of ik met Python en opencv iets met een webcam kan doen. Dat lukt wonderwel voorspoedig dus al snel de volgende stap gezet: 'object tracking'. Nou ja, kleuren tracking zoals ook bij de pixy camera beschikbaar is. Na wat geworstel met het vastleggen van de juiste kleurcodes (RGB) en, uiteraard, weer het door elkaar halen van hoogte en breedte coördinaten (waarom kan ik dat niet onthouden ?) lukt het om een kleur van een object (ping pong bal / gele isolatietape) 'te leren' en vervolgens de positie terug te geven zodra deze weer in beeld verschijnt. Zelfs mijn hand weet hij al heel aardig te volgen.

Nu eens kijken of dat ook in 3D zou kunnen werken. Ik leen de twee webcams van mijn zoons en ... succes! Het lukt om beide cameras tegelijk aan te sturen. 3D, I am on my way! (oke, wat flauw ... maar toch leuk dat dat ook al binnen de mogelijkheden ligt.)

Color capture on the right square. After that 3D position tracking is possible

Even totaal iets anders ... Het robotarm project van Bram

Bram heeft een zogenaamde 'pixy camera' waarmee de locaties van objecten aan de hand van hun kleuren kunnen worden vastgesteld. Hij is met een leuk project bezig om een eigen computerarm van scratch af aan te maken. Eerst is er een ontwerp gemaakt in Solidworks.



De componenten zijn daarna geprint met een 3D printer en gebouwd. Nu is Bram bezig om de juiste aansturing te programmeren.


Dat valt niet mee. Het vertalen van een 'Goto(X,Y,Z) functie, waarbij X, Y en Z een punt in de ruimte voorstellen, naar de juiste motorbewegingen vraagt een herverdieping in de goniometrie. Na veel gesinus en ge-arctangesen lukt het het eindelijk aardig. Alleen werken de servo-tjes serieel. Eerst de horizontale draaiing en dan de uitslag van de arm. Tevens schokt die daarbij nogal. In een volgende stap lukt het om de taak (het bewegen naar een positie) te verdelen in kleine substapjes en de beweging daarmee synchroon te laten lopen.

Nu kunnen de 2 grijper motoren (pols en handgreep) toegevoegd gaan worden.

Een (voorlopig) einddoel is om de arm, hopelijk via re-enforced learning, met behulp van de pixy camera zelf de beste aansturing te laten leren om een object te verplaatsen.

En hier de allereerste poging om iets met de arm te verplaatsen:


zaterdag 23 april 2016

Toch nog even installatie issues ...

Het testen van een eerder gemaakt robotarm programma vraagt om de grafische library cv2 ofwel opencv. Blijkbaar is de link kwijtgeraakt bij de laatste herinstallatie. Ik heb daarvoor Anaconda gebruikt wat iig even de Theano problemen leek te hebben opgelost.  Het geeft echter een inconsistentie melding bij de installatie van opencv met python en numpy. Ik blijk nu op te hoge versies te zitten. Python is nu 3.5 ipv 2.7. Ik probeer met Anaconda een parallel versie van Python te installeren. Daar kom ik echter niet goed uit.

conda create -n python2 python=2.7 anaconda
source activate python2 

Ik besluit maar weer met Homebrew te gaan werken. Daar lijk ik een goede opencv installatie instructie bij te kunnen vinden. Ik moet wel de terminal even opnieuw opstarten om de juiste Python te benaderen. 'Which python' wijst nu iig naar de juiste directory.

mac-pro-van-dirk-willem-wonnink:~ DWW$ which python

/usr/bin/python

Nu lukt het wel om opencv weer beschikbaar te krijgen. Helaas ben ik wel weer Theano kwijt.

>>> import theano

ERROR (theano.sandbox.cuda): nvcc compiler not found on $PATH. Check your nvcc installation and try again.

Gelukkig weet ik dat ook weer met behulp van mijn vorige blog bericht te herstellen. De globale (PATH) variablen moeten weer naar de juiste diectories worden geleid.

Na wat worstelen met goniometrie (sinussen / arccosinussen etc) weet ik nu ook de robotarmsimulatie juist te krijgen:

Op basis van gewenste reik-lengte en vaste hoogte de hoeken van de armen uitrekenen.



maandag 18 april 2016

Theano issues -opgelost (weer eens)

Phoe ... het blijkt lastig om Theano aan de praat te houden. Theano helpt ondermeer om gebruik te maken van van de GPU bij NN's. Ik meen dat bij het proberen te activeren van CuDNN e.e.a. is fout gelopen maar heel zeker weet ik dat niet. Het kan ook te maken hebben gehad met een upgrade van Xcode.
Ik heb van alles geprobeerd maar wat ik mij iig kan herinneren:

[global]
floatX=float32
device=gpu
#force_device = True
#allow_gc = False
#optimizer_including=cudnn

[cuda]
#root=/Developer/NVIDIA/CUDA-7.0/lib
#cxxflags = -L/Developer/NVIDIA/CUDA-7.0/lib

[lib]
#cnmem=.75
  • Cuda opnieuw geinstalleerd
  • Xcode terug naar 6.4 - inclusief activeren van developer tools.
  • Anaconda installatie van Theano --> pip install Theano

  • De hidden theano directory verwijderd sudo rm -rf ~/.theano

export LD_LIBRARY_PATH="/usr/local/cuda/lib"
export PATH=/usr/local/cuda/bin:$PATH
export DYLD_LIBRARY_PATH=/usr/local/cuda/lib:$DYLD_LIBRARY_PATH


En eindelijk werk het dus (weer :-): 


>>> import theano
Using gpu device 0: GeForce GTX 980 (CNMeM is disabled, CuDNN not available)


Een andere keer nog maar eens proberen om CuDNN aan de praat te krijgen : 


zondag 10 april 2016

05 - Santander Customer Satisfaction - Verdere feature selectie

De grote hoeveelheid features maakt het wellicht moeilijk voor een NN om tot een goede voorspelling te komen. Ik vindt een voorbeeld om de hoeveelheid features terug te bernegen.
Die pas ik toe. Daarin worden het aantal features teruggebracht tot 36:

  • de constante kolommen verwijderd. (std = 0)
  • de dubbele kolommen verwijderd
  • de niet samenhangende kolommen verwijderd
In mijn programma worden er daardoor 357 kolommen overgeslagen. 


Columns:  39 Number off class columns: 14 Number of classcols total: 357 Number of skipped columns: 0 Number of lin columns: 25


Helaas leidt het nog niet tot een hogere Kaggle score. Ondanks dat mijn evaluatiewaarde naar 0.275 zakt. 




04 - Santander Customer Satisfaction - Eerste verbeteringen

De verbeteringen zoals eerder voorgesteld hebben in ieder geval iets gedaan. Het is niet spectaculair maar ik klim 122 posities van 2898 naar de 2816e plaats:


Nog veel te doen dus. In ieder geval even kijken of meer training noodzakelijk is. Was nu nog maar 25 epochs met een evaluatie score van: 0.390422424548 Dat moet beter kunnen. Maar eens kijken wat 25 epochs erbij kunnen betekenen.

De score is met 25 epochs wel verbeterd: score: 0.376238739804 maar kaggle vindt het niet genoeg :-)


Ik eigenlijk ook niet. Tijd voor radicalere aanpassingen ...





03 - Santander Customer Satisfaction - Eerste submission

Gisteren mijn eerste submission gemaakt in de competitie. Hoewel nog zeker geen bijster resultaat, 0.729499 en dus 2898 (van de 3549) op de ranglijst, wel de gehele 'workstream' zelf gemaakt.


De hoogste score is vandaag 0.843381 dus dat is iig de uitdaging :-)


De eerste kolom (feature) selectie heb ik in mijn voorgaande bericht beschreven. In het 2e deel maak ik eerst de balans tussen het aantal ontevreden en tevreden klanten wat meer evenredig. De trainset ziet er als volgt uit:

  • 76.020 aantal klanten
  • 3.009 aantal ontevreden klanten
  • Dat is dus 3,958%
Om de trainset wat meer evenredig te maken selecteer ik 1/5 van de tevreden klanten. (15.204) Samen met de 3.009 ontevreden klanten komt de trainset formeel dan op 18.213. (In praktijk 17.834 - Ik moet ook uitzoeken hoe dat verschil komt.) Een loop door de data blijkt enorm traag te verlopen. Ik verzin een slimmere code:


Select = .2 # Select approximately 5x satisfied customer records compared to non satisfied

# First select all records with satisfied customers y[:1] = 0
X_tr = DataTr[y[:,1]==0]
y_tr = y[y[:,1]==0]

# Make random array of lengh number of rows X_tr. Then select only those with value lower than 'Select'.
Sel = np.random.rand(X_tr.shape[0])
X_tr = X_tr[Sel[:]<Select]
y_tr = y_tr[Sel[:]<Select]

# Add all dissatisfied customers
X_tr = np.vstack((X_tr,DataTr[y[:,1]==1]))
y_tr = np.vstack((y_tr,y[y[:,1]==1] ))


Dat werkt teminste snel!
De testset bestaat uit:
  • 75.818 aantal klanten.
  • Ik verwacht dus feitelijk 3,958 * 75.818 = 3001 ontevreden klanten.
Het eerste model heeft ~ 50 epochs doorlopen. Ik heb hem nogmaals aangeboden met ~ 100 epochs maar dan gaat het resultaat achteruit. Tijd dus voor meer serieuze aanpassingen.

Ik denk in ieder geval aan de volgende:
  • Splitsen van traindata in een train en validatie set. Was er nog niet van gekomen.
  • Per epoch een nieuwe trainset voor de tevreden klanten. Hoewel deze random wordt gekozen zorgt eenzelfde 'seed' voor steeds dezelfde dataset Dit is noodzakelijk wegens de, door Kaggle, vereiste herhaalbaarheid. MAar ik kan de seed wel steeds gecontroleerd aanpassen per epoch.
  • Ik wil dus uitkomen op ongeveer 3001 ontevreden klanten. Wellicht helpt het om de submission aan te passen zodat 3001 van de kansen boven de 0.5 uitkomen. 
  • Bewaren van de optimale 'weights'.
  Misschien bedenk ik ondertussen nog wel iets extras. Eerst dit maar eens proberen.






zondag 3 april 2016

02 - Santander Customer Satisfaction - De data strategie

Goed, nu de praktijk. Het ophalen van de data gaat vrij snel. Heel wat beter dan de gigabytes uit de vorige challenge. Ik maak een programma om de kolomvariabelen te analyseren. Dat geeft bijvoorbeeld de volgende resultaten:

kolom =  17, aantal =   8149, nonzero =  11749 , nonzero disat =    441 classif:  -   
kolom =  17 skip: -    max:     47598, min:         0,  mean:       140 Log: log

kolom =  18, aantal =     66, nonzero =     96 , nonzero disat =      9 classif:  -   
kolom =  18 skip: skip max:    105000, min:         0,  mean:         5 Log: log

kolom =  19, aantal =      2, nonzero =    871 , nonzero disat =     37 classif: class
kolom =  19 skip: -    max:         1, min:         0,  mean:         0 Log: log

kolom =  20, aantal =      2, nonzero =    286 , nonzero disat =     20 classif: class
kolom =  20 skip: -    max:         1, min:         0,  mean:         0 Log: log

kolom =  21, aantal =      1, nonzero =      0 , nonzero disat =      0 classif:  -   
kolom =  21 skip: skip max:         0, min:         0,  mean:         0 Log: -  

kolom =  22, aantal =      1, nonzero =      0 , nonzero disat =      0 classif:  -   

kolom =  22 skip: skip max:         0, min:         0,  mean:         0 Log: -  

Het 'aantal' geeft het aantal verschillende waardes op. Hiermee bepaal ik later of ik denk dat het classificatiewaardes gaan worden.
Daarnaast druk ik het aantal waardes <> nul af en dezelfde waarde maar nu voor de ~ 4% ontevreden klanten.
Ook de maximale, minimale en gemiddelde waarde druk ik af.
Om mijn selectie te controleren voeg ik 3 'boolean-waardes' toe:

  • classif: Als ik denk dat het een classifier variabele is
  • skip:    Als ik denk dat de kolom geen bijdrage biedt en dus overgeslagen kan worden. 
  • log:     Als ik denk dat het beter is om de 'lineaire kolommen' naar logaritmisch om te zetten omdat er te veel uitschieters in zitten. (En dus de variatie rond het gemiddelde in weg kan vallen.)
Ik besluit de kolommen te skippen als er minder dan 50% van de waardes gevuld zijn en van de 'ontevreden klanten' minder dan 11. Is wat arbitrair maar scheelt 205 kolommen van de 369!!!

Ik besluit dat kolommen met meer dan 100 verschillende waarden 'lineaire kolommen' zijn. De anderen zijn dus classificatie kolommen. Dit resulteert in 117 classificatiekolommen en 47 lineaire kolommen.

Daarnaast kijk ik of bij de lineaire kolommen het maximum meer dan 10 x groter is dan het gemiddelde. In die gevallen zet ik ze om naar een logaritmische verdeling. Uiteindelijk blijkt dat bij deze instelling voor alle lineaire kolommen van toepassing te zijn.

De classificatie kolommen worden omgezet naar aparte kolommen per klasse hetgeen uiteindelijk 2147 kolommen oplevert. Oeps, wel heel veel. Maar daar kijken we later nog wel naar. In elke kolom staat een 1 of een 0 indien de betreffende klasse voor de klant geldig is.

Na de logaritmische bewerking worden alle lineaire kolommen terug gebracht naar een waarde tussen 0 en 1. Daar waar er negatieve getallen zijn worden ze opgeschaald zodat alles toch tussen 0 en 1 blijft. Ik voeg een test toe of mijn data aan de voorwaarden voldoet. (Geen nan / inf / tussen 0 en 1) Dat zou ik eigelijk in een bibliotheek moeten plaatsen voor algemeen gebruik.

In eerste instantie zijn er nog veel fouten met -nan waarden of -inf waarden in de kolommen. Ik moet corrigeren dat het logaritmische resultaat van een waarde tussen 0 en 1 een negatieve waarde is. Ook worstel ik enige tijd met een numpy array dat niet goed geinitialiseerd is. Ik moet mij toch weer aanleren om de programma's niet vanuit de Python schil te starten maar rechtstreeks vanuit de terminal. Daardoor blijven variabelen en dus ook arrays niet 'onthouden'.

De data lijkt nu in orde. Ik heb 2 arrays opgeslagen. 1 van 76020 x 2194 (de X) en 1 met de targets van 76020 (de y). Daarmee kan ik trainen! Ik besef mij dat ik wel dezelfde bewerking moet doen op de test data. Dat is niet zomaar eenvoudig vervangen omdat ik daar, uiteraard, de target data niet heb. Ik denk dat ik deze gelijk moet bewerken tijdens de train data. Ik hoop dat het geheugen dat aankan. Tevens moet ik controleren of de classificatiedata overeenkomt tussen de train en de test dataset.




     
  








01 - Santander Customer Satisfaction

Na de 'titanen-competitie',  om de ejection fraction van de linker ventrikel (kamer) te bepalen aan de hand van mri-beelden, nu een competitie die wat traditioneler lijkt wat structuur betreft. De Santander Customer Satisfaction. Gewoon een heleboel klanten waarvan ongeveer 4% uiteindelijk ontevreden is. Het gaat er dus om om te voorspellen of een klant, gedefinieerd in 369 kentallen, een tevreden klant zal zijn of niet. Het bijzondere is dat het van de meeste kentallen onbekend is wat ze voorstellen. Ze worden aangeduid met raadselachtige namen zoals "imp_op_var39_comer_ult1".



De trainingsset is 76020 klanten groot maal (dus) 369 kentallen. De testset is van vergelijkbare grootte. (75818) Het zijn dus stevige bestandjes om te verwerken.

Ook bij dit soort competities gaat een groot deel van het werk in de data-voorbereiding zitten. Of te wel het geschikt maken van de data voor gebruik in een of ander leer algoritmen. Aanbevolen is dan om :

  • Classificatie gegevens een eigen 'kolom' per klasse te geven. bijvoorbeeld 1 kolom voor man (yes/no) en een voor vrouw (yes/no)
  • Ook alfanumerieke waarden zijn vaak classificatie gegevens. Bij deze data is echter alles numeriek.
  • De kolommen onderling in balans te brengen zodat ze vergelijkbaar zijn.
  • Daarmee samenhangend de waarden binnen een bepaalde range, bijvoorbeeld 0 en 1 te brengen.
  • Daarnaast bestaat er zoiets als 'dimensionality reduction' oftewel het terugbrengen van het aantal kolommen naar alleen die vermoedelijk relevant zijn. 

Lekker aan de slag voor tevreden klanten! :-)