Courses  

II.Werken met Nutshell

Tot voor kort schreven alle connectionisten hun eigen simulatieprogramma’s, met eigen algoritmes, eigen opties, eigen leerregels, outputmodules, patrooninlezers, etc. Iedereen kon zo zijn code aan de eigen wensen aanpassen, maar het resultaat was wel dat het wiel telkens opnieuw uitgevonden werd. Sinds enige jaren komen er standaardsimuleeromgevingen beschikbaar. Idealiter maken die het mogelijk om zonder eerst maanden te programmeren meteen simulaties te doen, met behoud van de flexibiliteit die de gevorderde gebruiker nodig heeft. Nutshell is zo’n simuleeromgeving. Er is één buitenkant waarmee je veel verschillende connectionistische paradigma’s (=soorten netwerken) kunt simuleren. Aangezien Nutshell toevallig ontwikkeld werd aan de UvA1 (en ook nog eens heel goed is) zullen we dit programma gebruiken in het practicum.

A. Werken met de omgeving

Om je te laten wennen aan Nutshell zullen we eerst een aantal simpele stappen doen. We gebruiken hierbij het Hopfield paradigma dat ook in de eerstvolgende opdracht zal worden gebruikt. Je start Nutshell op door in je start-menu Nutshell aan te klikken (staat in onze Windows onder ‘Programs’ en dan ‘Nutshell 1.0’). De Nutshell-applicatie start nu op. Je kan uit verschillende paradigma’s kiezen. Een paradigma is in connectionisme een bepaalde manier waarop netwerken werken – een definitie van hoe leren gaat, hoe knopen ge-update worden, wat je allemaal met lagen kunt doen, etc. Hopfield is zo'n paradigma. Kies "Hopfield.np".

Opmaak van de Nutshell-omgeving

Je ziet nu een lege ‘workspace’ (een groot leeg venster waarin je een model kunt bouwen), en verschillende werkbalken met tal van functies. Onder het Helpmenu (in de menu's bovenin) staat de op het moment nog vrij beperkte helpinformatie van Nutshell, en onder andere een Hopfield tutorial. In de tutorial worden een aantal functies uitgebreidere besproken dan hier, dus als je na dit hoofdstuk nog steeds weinig snapt van Nutshell moet je die doorlopen. Belangrijk is ook de ‘Edit’-balk (meestal rechts in Nutshell), te herkennen aan de muispointer met daarnaast een loep waar je mee in en uit kan zoomen. Als 'default' is de muispointer geselecteerd. Verder belangrijk: de "General"-balk links waarin alle functies staan opgesomd. Als je een klein venster hebt dan kan je de onderkant de het "General"-balk niet zien. Dat is niet problematisch: alles in de "General"-balk staat ook onder het "Parameter”-menu in de menubalk boven. Als je de “General” en “Edit”-balken niet ziet, kijk dan onder het “View”-menu bovenaan of deze balken wel aangevinkt zijn (de “Edit”-balk staat onder “Toolbars”).

Links onderin Nutshell zit het 'console'-venster, en rechts onderin het outputvenster. Je kunt de console gebruiken om scripting-commando's (zie sectie B) één voor één in te voeren en het outputvenster om variabelen of andere informatie te zetten, maar beide vensters gaan we niet veel gebruiken in deze cursus.

Een Hopfieldnetwerk bestaat uit knopen die zich in een ‘laag’ (layer) bevinden. Maak een laag aan door simpelweg op "insert layer" te klikken. Je mag aangeven welke dimensies de laag gaat krijgen; standaard is 10 bij 10. Klik op "OK". Je ziet nu vierkant van knopen (de laag) met willekeurig geïnitialiseerde activaties.

Variabelen bekijken

Je kunt de waarde van de activatie –en van andere parameters- bekijken door een knoop te selecteren (1 keer erop klikken met de linkermuisknop) en dan op de rechtermuisknop te drukken. Er verschijnt nu een menu. Zet de muis op het veldje met ‘Node’ en het knoopnummer, en klik op het verschijnende veldje met ‘parameters’. Kijk wat het verschil is tussen rode en zwarte knopen. Je kunt nu ook een knoop van rood naar zwart veranderen, door de waarde van de goede parameter te veranderen en op "OK" te drukken.

Er zijn algemene parameters, parameters die bij knopen horen, parameters die bij lagen horen, bij verbindingen, en bij 'tracts' (bundels verbindingen van 1 laag naar zichzelf of een andere laag). Links in de 'General'-balk is een optie 'Parameters'. Als je daarop klikt kan je de algemene parameters bekijken. 'Laag'-parameters kan je inkijken door een laag aan te wijzen door er op te klikken, dan weer de rechtermuisknop in te drukken, en onder de "Layer"-optie te kijken. Daar zal je weinig aantreffen: 'Hopfield' is een paradigma met weinig parameters (er is bijvoorbeeld geen enkele 'tract'-parameter). Andere paradigma's hebben hele lijsten parameters.

De laag verbinden, patronen tekenen

De knopen zijn nog niet met elkaar verbonden. Dit doe je door op het bovenste deel van de laag (het witte) te klikken om hem te selecteren, en dan links in de balk op "Insert Tract" te klikken. Er verschijnt een ronde pijl rechtsboven de laag. Dit is de ‘tract’ met de verbindingen van de laag naar zichzelf. Het netwerk is nu intern volledig verbonden.

De waarden van de knopen kun je instellen door de functie van de muispointer in de editbalk in "set value" te veranderen. Deze functie staat onderaan (half gevuld vierkantje). Kies "custom value". Zorg dat de waardes gelijk zijn aan de twee mogelijke activatiewaardes in het Hopfield-paradigma: “set” moet +1 zijn, en “clear” -1. Nu kun je activatie van een knoop met een klik op je linker muisknop op de “set”-waarde van 1 zetten, en met een klik van je rechter muisknop op de “clear”-waarde van -1. Als je op een rode knoop klikt zal hij zwart worden ('set'-waarde).

Je kunt de hele laag of een deel van de laag tegelijk de 'set'-waarde geven door het 'vlakje trekken'. Zet de muispunt buiten de laag (maar in de buurt), houd de linkermuisknop ingedrukt en schuif de muispunt over een deel van de laag. Als je de knop loslaat krijgen alle knopen in het getrokken vierkantje de 'set'-waarde. Je kunt de 'clear'-waarde aan knopen geven door de shift knop ingedrukt te houden en of op een knoop te klikken, of weer een vlak te trekken om een te veranderen deel van de laag.

Als het je gelukt is de activatie-waarden onder controle te krijgen dan kun je proberen een patroon in de laag te tekenen.

Leren in het netwerk, bekijken van gewichten

Door middel van "Learn" in de linkerbalk kan dit patroon worden geleerd. Druk op "Learn".

Je kunt op twee manieren controleren of de connecties ook daadwerkelijk veranderd zijn. Je kunt de connecties bekijken. Dat doe je door boven in het scherm bij View naar de optie connection te gaan. De eerste keer dat je dit doet zie je misschien alleen maar grijze vierkantjes met kruisjes erin. Dan moet je even de functie van de muispointer veranderen in het simpele pijltje. Als je nu op een knoop in de laag klikt zie je de waarde van de verbindingen met andere knopen als kleuring van deze knopen. Een nader onderzoek is mogelijk als volgt. Klik op een knoop naar keuze. Klik op een ander knoop naar keuze maar houd daarbij de shift toets ingedrukt. Als je nu de rechtermuisknop indrukt krijg je in het menu de optie "weight(nodenummer, nodenummer)" erbij. Als je deze optie aanklikt zie je de waarde die de verbinding heeft aangenomen.

Activatie updaten, iteraties

In het simpele geval van één geleerd patroon is het makkelijk aan te tonen dat het netwerk het patroon heeft onthouden. Hiervoor ga je terug naar de "node"-mode (bovenaan: view>node). Nu reset je de layer met random waarden (hiervoor eerst de laag selecteren door klikken op de juiste plaats of het "vlakje trekken"; Klik dan links op "reset layer"). Met de linker optie “Act Step” voer je een enkele berekening uit. In het geval van een Hopfield-netwerk verandert dan soms de activatie van een enkele knoop. Druk een aantal malen op "Act Step" tot je een knoop van activatie ziet veranderen.

Met "Act Cycle" voer je er een aantal iteraties achter elkaar uit ('default' 100 in Hopfield). Druk een keer op "Act Cycle", en constateer dat er dan een heel stel knopen van activatie veranderen. Na een aantal keren op 'Act Cycle" te hebben geklikt krijg je je originele patroon terug. Als je het aantal iteraties wilt instellen moet je onder "Parameters" kijken in de "General"-balk links. Daar zal je de parameter "Cycle Step" vinden (in oudere versies van Nutshell heet die "Iteration Length").

Clampen en deactiveren

Soms is het nodig een deel van een netwerk te laten itereren, terwijl een ander deel constant dezelfde activatie houdt (bijvoorbeeld als dit tweede gedeelte de constante input van het netwerk weergeeft en je de rest van het netwerk zich wilt laten aanpassen aan de input). Hiervoor bestaat in Nutshell het 'clampen' van knopen. Een 'geclampte' knoop verandert niet van waarde als je op "Act Cycle" drukt, ook als hij het normaal wel zou doen. Knopen 'clampen' kan je door een kruisje te zetten achter "Clamped" in het parametermenu van de knoop (zie onder 'Variabelen bekijken'). Veel handiger is weer "vlakje trekken".

Om dit te zien moet je eerst de laag weer 'resetten' (laag selecteren, functie aanklikken in linkerbalk). Klik nu in de "Edit"-balk op het tekeningetje met een wit vierkant met een zwart kruis erdoor, en een klein wit pijltje. Je muispunt is nu een 'clamper' geworden. Druk in de buurt van je netwerk op de linker-muisknop, en trek de muispunt over een deel van de laag. Als je nu loslaat zie je witte en zwarte kruizen verschijnen door alle knopen in het door jou getrokken vlak. Deze knopen zijn nu geclampt. Als je nu op "Act Cycle" drukt zal je zien dat een aantal van de niet-geclampte knopen van activatie verandert, maar de geclampte knopen niet. Door de Shift knop ingedrukt te houden terwijl je een vlakje trekt kan je knopen weer ontclampen.

Druk op het pijltje in de "Edit" balk om de muispointer terug te krijgen.

Je kunt knopen ook deactiveren (dood maken). Druk hiervoor in de "Edit" balk op het tekeningetje met een grijs vierkant met een wit kruis erdoor, en een witte pijltje. Je muispunt is nu een 'deactivator'. Trek weer een vlak over een deel van de laag. Je zult zien dat de knopen in je vlak grijs worden met een wit kruis erdoor. Deze knopen zijn gedeactiveerd: ze doen niets meer. Je kunt deactiveren, je raadt het al, weer opheffen door de Shift knop ingedrukt te houden en weer een vlak te trekken.

B. Scripting

Je kunt met de functies die in de linkerbalk staan verschillende netwerken maken. Let wel, zolang je een Hopfield-workspace hebt opgestart blijven dit altijd Hopfield netwerken met Hopfield eigenschappen. Voor de rest kunnen deze netwerken zo complex worden gemaakt als de gebruiker wil. Je kunt ook allerlei patronen in een netwerk stoppen door ze na elkaar te tekenen en vervolgens te leren.

Voor onderzoek is het vaak nodig om je resultaten te repliceren om te laten zien dat je resultaat geen toevalstreffer is maar een robuust fenomeen. Om dan niet telkens het netwerk te hoeven maken en je patronen te leren, kun je alle informatie over het netwerk en patronen in een script zetten, een file met achter elkaar een serie commando’s die Nutshell kan uitvoeren. Ook kun je via zo’n script je resultaten handig weg laten schrijven naar bijvoorbeeld een Excel sheet. Scripts zijn eigenlijk kleine programmaatjes. Ze zijn vergelijkbaar met macro’s in word processors, of syntax-files die je misschien in SPSS hebt gebruikt.

In de volgende sectie zullen we uitleggen hoe een standaardscript in Visual Basic (VBA) er uit ziet. Als je nog geen kaas gegeten hebt van programmeren kan je dit misschien gebruiken om de scripts die je in opdracht 2.2 moet maken te begrijpen. Meer introductie van VBA en ook over het werken met VBA in Excel kun je vinden in:

C. Het lezen van een Visual Basic-script.

Programmeren draait om datastructuren (arrays en variabelen) en algoritmen. In de datastructuren wordt de data die je wilt gaan bewerken gezet. Algoritmen zijn de bewerkingen op de datastructuren. Stel dat je een rij van tien getallen (je data) wilt opslaan binnen Visual Basic (VB). Dit definieer je zo:



Dim MaxSize as Integer
MaxSize = 9 ‘ 10 – 1
Dim GetalArray(MaxSize) as Integer



We beginnen met de onderste van de drie regels code. Dim staat voor Dimension; dit is in VB de aankondiging dat er een datastructuur gedefinieerd gaat worden. GetalArray is je datastructuur, in dit geval een rij (array) van getallen. MaxSize is ook een datastructuur, een variabele (een naam voor iets dat kan variëren). We gebruiken deze variabele hier om de maximale hoeveelheid van getallen aan te geven die je in de array wilt stoppen. ‘as Integer’ geeft aan wat voor soort getallen je in de array wilt stoppen. Integers zijn de gehele getallen, de verzameling Z (zowel negatieve als positieve getallen). Op de tweede regel code krijgt Maxsize een waarde toegekend, namelijk de waarde 9. Het deel na het accent ‘ is commentaar (zie verderop). Arrays beginnen in VB altijd bij element 0, dus als je tien getallen op wilt slaan dan moet je een ‘array’ hebben van grootte 9: doordat je het element 0 mee moet rekenen zitten er dan eigenlijk 10 elementen in de Array. Op de bovenste regel wordt Maxsize gedefinieerd als een Integer.

Je stopt een getal in een datastructuur door de datastructuur gelijk te stellen aan het getal:



GetalArray(0) = 2



Het gelijkteken betekent hier niet, zoals bij normale wiskunde, dat wat links staat gelijk is aan wat rechts staat, maar dat wat links staat gelijk moet worden aan wat rechts staat. In dit geval moet de eerste van de tien plekken in array GetalArray (die plek wordt aangegeven als: GetalArray(0)) gelijk worden aan 2. In softwarespeak heet dit: Je kent de waarde 2 toe aan het eerste element van de array.

Stel nu dat je ook alle andere elementen de waarde 2 wilt geven. Je kunt nu een aantal regels schrijven:



GetalArray(0) = 2

GetalArray(1) = 2

. . .

GetalArray(9) = 2



Het is veel makkelijker de computer in één keer te vertellen dat er tien keer een 2 aan een element in de array moet worden gegeven. Dit kan met de “for…next”-loop, een programmalus. In zo’n “lus” wordt een bepaalde actie een aantal malen herhaald, met soms elke keer een kleine aanpassing. Bijvoorbeeld in het volgende algoritme:



For index = 0 to MaxSize
GetalArray(index) = 2
Next



In de ‘for’-loop wordt een stukje code een aantal malen herhaald; hier wordt steeds één element van de array ‘GetalArray’ gelijk gezet aan de waarde 2. De herhaling is niet letterlijk, omdat bij elke herhaling van dat stukje code een ander element de waarde 2 krijgt. Dit doen we met hulp van de index, de variabele die bijhoudt hoe vaak de for…next-loop al doorlopen is (hier heet de index ook index, maar dat hoeft niet; wij gebruiken vaak de lekker korte naam i). Deze index heeft eerst de beginwaarde 0, en wordt dan in stapjes van 1 opgehoogd tot hij de waarde MaxSize heeft. We stellen steeds het ‘index’-ste element van de array gelijk aan 2. Doordat steeds 1 element van GetalArray ingevuld wordt, wordt zo de hele GetalArray doorlopen.

De eerste actie die de “For…Next” loop doet is de GetalArray op plaats index=0 de waarde 2 toe te kennen. Dus:



GetalArray(0) = 2



Het Next statement zorgt ervoor dat de loop nog eens gedaan wordt, en de index eentje wordt opgehoogd. We springen dus weer naar de eerste regel, en de index wordt gelijk aan 1. Het volgende wat de for loop gaat doen is element index=1 van GetalArray de waarde 2 te geven. Dus:



GetalArray(1) = 2



Dit gaat door totdat de ‘For’ loop bij MaxSize is aanbeland. De index heeft dan de waarde van MaxSize, in dit geval 9. Het laatste wat de for loop doet is GetalArray op plaats 9 de waarde 2 te geven, daarna is de loop klaar en gaat het programma verder.



GetalArray(9) = 2



Een programmeertaal heeft net als elke taal een syntax. Wat je doet is communiceren met een ‘compiler’, die je programmeerconstructies vertaalt in voor de hardware van de computer begrijpelijke enen en nullen om jouw instructies uit te voeren (ik heb voor het gemak allerlei tussenstappen overgeslagen). De compiler kan alleen dingen begrijpen als jij je aan de syntax houdt. Elke programmeertaal heeft zijn eigen syntax, maar in hun essentie zien ze er allemaal vrijwel hetzelfde uit. Een taal heeft regels om datastructuren te maken/definiëren, en regels om algoritmen te schrijven die deze datastructuren bewerken.

We zijn al een syntaxconventie van Visual Basic voor datastructuren tegengekomen, namelijk dat na het woord Dim altijd een definitie volgt van een datastructuur. ‘Dim’ is een zogenaamd gereserveerd woord, een woord waarvan de betekenis is vastgelegd in de taal (zoals ook ‘For’ en ‘Next’ gereserveerde woorden zijn). Een tweede datastructuur-conventie was dat als een woord meteen wordt gevolgd door haakjes, (), het de naam van een array moet zijn. Die arraynaam, en ook namen van variabelen, mag je geheel zelf verzinnen mits het geen gereserveerd woord is. Dus sflj() is een array, terwijl sflj een variabelenaam zou zijn. Let wel dat er tussen haakjes maar één getal (die de grootte aangeeft) mag staan wil het een array zijn, dus sflj(10) is een array. Wat je vaak in de script zal tegenkomen is een matrix(aantalrijen, aantalkolommen). Iets wat twee getallen tussen de twee haken heeft staan, zoals sflj(10, 3), is een matrix volgens de Visual basic syntax.

Om algoritmen te schrijven heeft Visual Basic ook allerlei vaste taalconstructies. De ‘for…next’ loop is hier een voorbeeld van. In de visual basic ‘help’ kun je allerlei syntax-conventies voor datastructuren en algoritmen opzoeken. Je kan dit doen door met je cursor het woord te selecteren en dan op F1 te drukken. Of gewoon vanuit het helpmenu de help op te starten en dan het woord in te typen (zie ook het gratis te downloaden Visual Basic-boek http://www.microsoft.com/officedev/articles/Opg/default.htm).



Een visual basic-scripts heeft een duidelijke structuur. Er is sprake van een hoofdalgoritme of hoofdprocedure waarin allerlei subprocedures staan. Het programma begint op de eerste regel van de hoofdprocedure, en van daar uit wordt de ene na de andere regel code afgewerkt. Subprocedures lossen vaak een deelprobleem van het hoofdprobleem op. Deze subprocedures staan elders in het programma gedefinieerd. In de hoofdprocedure staat alleen een ‘aanroep’ van de subprocedure daar waar je de subprocedure wilt gebruiken. De ‘aanroep’ is gelijk aan de ‘header’ (titelregel) van de subprocedure, en bevat de naam van een subprocedure en een aantal parameters. Parameters zijn vaak datastructuren die in het hoofdprogramma zijn gedefinieerd en die je wilt gaan gebruiken in de subprocedure. Schematisch kan een programma er ongeveer zo uit zien (gereserveerde woorden zijn schuin gedrukt, namen van hoofd-en subprocedures vet):



Sub Hoofdprocedure

Dim Datastructuur1
Dim Datastructuur2
Subprocedure1 datastructuur1 datastructuur2

End Sub



Sub Subprocedure1( Dim datastructuur1, Dim datastructuur2)

Doe iets met datastructuur1 en datastructuur2

End Sub



In een subprocedure kan van alles worden gedaan. Er kan bijvoorbeeld een ‘for…next’ loop in staan, maar er kunnen ook weer allerlei andere procedures worden aangeroepen. Die je dan weer elders moet definiëren.

In een Visual basic script kun je nog drie andere soorten van taalconstructies tegenkomen, namelijk script-aanroepen, globale constanten en commentaar.

Scriptaanroepen zijn functie-aanroepen vanuit een script-taal naar een ander programma, vaak een zgn. ‘applicatieprogramma’ zoals Word of Excel, of ook Nutshell. Dit programma kan in een andere taal zijn geschreven en bevat allerlei eigen datastructuren en algoritmen. In dit geval worden er functies van de Nutshell-simulator aangeroepen vanuit Visual Basic. Nutshell is in C++ geschreven en bevat tienduizenden regels code, maar scripting maakt het mogelijk je daar niets van aan te trekken en er met Visual Basic mee te werken.

Globale constanten zijn constanten die je overal in je programma gebruikt. Als je bijvoorbeeld 5 patronen wilt leren, kan het slimmer zijn een globale constante “NrOfPatterns”te maken en die gelijk te zetten aan 5, dan om overal waar je het aantal patronen nodig hebt ‘5’ te schrijven (iets soortgelijks deden we boven al, waar we de variabele MaxSize gebruikten om het aantal elementen in de array GetalArray aan te geven).

Commentaar staat achter een accent: ` (`dit is commentaar), en dient er meestal voor om aan te geven wat een bepaald algoritme doet of een datastructuur representeert.

Schematisch kan een script er zo uit zien:



‘Globale constanten
Const GlobalConstant1 = waarde
Const GlobalConstant2 = waarde



Sub Hoofprocedure

Scriptcommando1
Scriptcommando2

Dim Datastructuur1 ‘ Commentaar over wat deze datastructuur doet
Dim Datastructuur2 ‘ Commentaar over wat deze datastructuur doet
Subprocedure1 datastructuur1 datastructuur2

Dim datastructuur3
Subprocedure2 datastructuur2 data

End Sub



Sub Subprocedure1( Dim datastructuur1, Dim datastructuur2)

Doe iets met datastructuur1 en datastructuur2

End Sub



Sub Subprocedure2( Dim datastructuur2, Dim datastructuur3)

Doe iets met datastructuur2 en datastructuur3
Subprocedure3 datastructuur3

End Sub



Sub Subprocedure3( Dim datastructuur3)

Doe iets met datastructuur3

End Sub

Dit is zo ongeveer de structuur van de scripts in de opdrachten. Hoe zo’n script met Nutshell werkt wordt uit de doeken gedaan in Appendix 1. Daarin staan een aantal commando's waarmee je dingen gedaan krijgt in Nutshell, met uitleg over hun werking. De uitleg gaat er overigens wel van uit dat je iets van visual basic begrijpt, dus bijv. de boven genoemde hoofdstukken van de Microsoft webmanual gelezen hebt.

 


[1]        Door Robert Berg, Eric Maryniak en Jaap Murre.

 


University of AmsterdamUniversity of Amsterdam
Department of Psychology
Page last modified: 2013-10-27. Validate html.
Copyright © 2000-2009 NeuroMod Group. Send us Feedback!