Appendix 1: voorbeelden van Nutshell commando's
In deze appendix geven we een aantal voorbeelden van
script-commando's die je nodig hebt om bijvoorbeeld de code te schrijven voor
opdracht 5.1. Veel van deze commando's kan je in elk paradigma gebruiken, maar
sommigen zijn specifiek voor één paradigma. Enkel degenen die je ook in de
Nutshell omgeving kunt vinden als je met een paradigma, kan je in scripting
gebruiken bij dat paradigma. Het volgende zal ervan uitgaan dat je dit het
hards nodig hebt op het moment dat je in opdracht 5.1 zelf commando's in moet
voeren; daarom zijn de voorbeelden met het 'MacGregor'-paradigma.
Hoe verwijs je naar Nutshell?
In Nutshell heb je te maken met een workspace, waar
weer lagen en tracts en knopen in zitten, en een 'applicatie' (=het programma)
er omheen. Om Nutshell met scripting vanuit een ander programma te besturen, moet
je minstens die workspace en al die dingen kunnen bereiken. Je moet met die
'objecten', zoals dat in softewarespeak heet, kunnen 'praten'. In principe kan
dat allemaal via een ingewikkelde hiërarchie naar beneden, tot je bent waar je
wezen moet. Veel simpeler gaat het door een variabele te laten verwijzen naar
objecten. In al onze VBA-scripts staan ergens -misschien in een subprocedure of
in een andere module- de regels:
Dim workspaces As Object
Set workspcs = CreateObject("Nutshell.Workspaces")
Dim worksp As Object
Set worksp = workspcs.Add("MacGregor.np")
(waarbij in de plaats van "Macgregor.np"
ook de naam van een ander paradigma kan staan). In deze vier regels worden twee
variabelen aangemaakt in de Dim-statements [een variabele is een naam die een
waarde kan hebben of ergens naar kan verwijzen], die komen te verwijzen naar
resp. een "Workspaces"-object en een "Workspace"-object.
Zo'n "Workspaces"-object is een verzameling open workspacen. Als je
zoiets maakt (wat in regel 2 gebeurt) start je in feite een nieuwe Nutshell op.
In die verzameling workspacen wordt in regel 4 één bepaalde workspace gemaakt,
van het type "MacGregor". Als je dit niet helemaal snapt is dat niet
erg (copy-paste die vier regels in al je scripts en je bent klaar), het
belangrijkste is dat je een variabele overhoudt, "worksp", die
verwijst naar de Nutshell workspace die is aangemaakt (in veel scripts heet
deze variabele 'workspace', maar hier is het afgekort om verwarring met de
echte Nutshell workspace te voorkomen). Overal waar je, tenminste binnen de
procedure waarin die regels staan, nu 'worksp' schrijft, weet VBA dat je de
geopende Nutshell workspace bedoelt, en dat je dus in feite orders aan een
ander programma dan VBA wilt geven.
De truc met verwijzende variabelen lukt ook op lager
niveau. Nieuwe lagen krijgen een nummer op volgorde dat ze zijn aangemaakt. De
eerste laag die je maakt krijgt bijvoorbeeld nummer 0 (omdat bijna alle
programmeertalen tellen vanaf nul). Nu kun je die laag aanwijzen door vanaf de
workspace naar beneden te gaan, naar die laag. "layers" is de
verzameling lagen in een workspace, en als je uit die verzameling de nulde pakt
zit je goed. Dat doe je met een punt ertussen:
worksp.layers(0)
Zo wijs je de nulde laag aan. Als je de derde knoop
van de nulde laag wilt aanwijzen, moet je gewoon nog wat verder naar beneden
gaan:
worksp.layers(0).nodes(3)
Zo begrijpt VBA met welke knoop je iets wilt.
"Nodes" is hier weer de verzameling knopen in een laag, en weer moet
er een puntje tussen (zo gaat Nutshell door de hiërarchie heen). Omdat dit wat
lang is kan je ook met variabelen naar de laag verwijzen.
Dim frontLayer as object
Set frontLayer = worksp.layers(0)
Nu verwijst frontLayer naar de nulde laag, en kan je
naar die derde knoop verwijzen met:
frontLayer.nodes(3)
VBA weet, dankzij de toewijzing van de variabele
frontLayer aan de nulde laag, waar je het over hebt.
Een commando vertalen uit de omgeving
Het basisprincipe achter de scriptcommando's is
simpel: je schrijft uit wat je in Nutshell zou doen. Als je bijvoorbeeld een
laag wilt 'resetten', dan moet je de laag selecteren en vervolgens de functie
'reset layer' aanklikken in het 'General'-menu. Het 'General'-menu hoort bij de
workspace. Je 'stuurt' de instructie die je aanklikt naar de workspace. Tijdens
het scripten kan je dat ook doen door de workspace 'aan te roepen' via de
variabele 'worksp', dan een punt te zetten, en de functienaam. De functienamen
-en voor de parameternamen geldt hetzelfde- die je bij het scripten gebruikt
zijn precies dezelfde als degenen die je in Nutshell ziet, alleen worden de
spaties weggelaten. "Reset Layer Nodes", de functienaam in Nutshell, wordt zo
bijvoorbeeld "resetlayernodes". Het commando wordt dan:
"worksp.resetlayernodes".
Nu moet je nog wel een laag selecteren. Dat doe je
door de naam van een laag achter het commando te schrijven. Je kunt dat weer
via een variabele doen die naar de laag verwijst (bijv. 'frontLayer' voor een
frontale laag), of via de workspace en het laagnummer (bijv. "worksp.layer(0)").
Het volledige commando wordt dan bijvoorbeeld:
worksp.ResetLayerNodes worksp.layer(0)
Ander voorbeeld: Insert Tract. Om een tract aan te
maken moet je niet één maar twee lagen selecteren, eentje waar de tract vandaan
komt en eentje waar die naar toe gaat (als je één laag selecteert en op 'Insert
Tract' drukt, gaat Nutshell er vanuit dat de laag met zichzelf verbonden moet
worden, waardoor twee keer één en dezelfde laag geselecteerd is). Bij het
scripten schrijf je de twee lagen die je selecteert (waar je een verbinding
tussen wil) achter elkaar, met een komma ertussen. Hoe ziet dat eruit? Net als
bij 'reset' begin je met 'worksp', een punt, en dan de functienaam zonder
spaties: InsertTract. Vervolgens moet je aangeven tussen welke lagen de tract
moet lopen, stel van laag 0 naar laag 1. Connectionisten hebben de wat
onintuïtieve afspraak dat de ontvanger eerst komt in het benoemen van een
connectie, en dan pas de zender. Daarom schrijf je eerst de laag waar de tract
heen gaat, daarna waar hij vandaan komt. Met een komma tussen de twee lagen
wordt het:
worksp.InsertTract worksp.layer(1), worksp.layer(0)
In het Hopfieldparadigma ben je dan klaar. In het
MacGregorparadigma en veel andere paradigma's moet je echter meer informatie
meegeven: de functie "Insert Tract" heeft in die paradigma's
argumenten. [9] Open een
nieuwe MacGregorworkspace in de Nutshell omgeving, maak twee lagen aan,
selecteer die (shift ingedrukt houden, op beide lagen klikken) en druk op
'Insert Layer'. Je krijgt een venstertje waarin je twee argumenten moet
opgeven: de leerparameter mu moet je instellen, en je moet aanvinken of de
'tract' normalizerende gewichten heeft of niet. Bij de leerparameter moet je
een getal opgeven, en een vinkje bij "Is Normalizing" staat voor
'true' (waar, de tract is normalizing). Geen vinkje daar betekent 'false'
(onwaar, de tract is niet normalizing). Bij het scripten zet je de waardes die
de parameters moet krijgen, allemaal met komma's ertussen, achter de lagen.
Stel ook dat je wilt dat de leerparameter gelijk moet zijn aan 0.1 en dat je
een niet-normalizaerende tract wilt. Dan moet je schrijven:
worksp.InsertTract worksp.layer(1), worksp.layer(0), 0.1, false
Je moet altijd net zoveel dingen tussen
komma's zetten als er argumenten zijn wanneer je de functie uitvoert in
Nutshell. In dit geval moeten het er dus twee zijn, anders krijg je een
foutmelding.
Het recept voor het vertalen van een Nutshell
functie in een scripting-commando is dus:
♦ Je begint met een variabele, meestal 'workspace' geheten of zoals hier
'worksp', die verwijst naar de echte Nutshell workspace (zie boven hoe we die
aanmaken).
♦ Achter deze variabele komt een punt, en dan de naam van de
nutshell-functie zonder spaties.
worksp.DitIsEenFunctie
♦ Als er voor de functie in Nutshell iets geselecteerd moet worden, bijv.
een laag of een tract of een knoop (soms hoeft er niets geselecteerd te
worden), schrijf een naam of verwijzing daarnaar achter de functienaam. Meestal
doe je dit met een of een variabele die direct naar je laag of tract verwijst,
of vanaf de variabele 'worksp'. Dan een punt, en de laag met laagnummer of
tract met de lagen waartussen de tract zit (zie hieronder voor voorbeelden).
worksp.DitIsEenFunctie laagnaamOfZo
♦ Tenslotte moet je nog de argumenten van de functie opgeven. Door de
functie in Nutshell uit te voeren krijg je, tenminste als er argumenten zijn,
een dialoogschermpje waarin je kunt zijn welke argumenten er zijn, in welke
volgorde ze staan en van welk type ze zijn. Zet voor elk argument een waarde,
allemaal door komma's gescheiden, achter het commando, en je bent klaar:
worksp.DitIsEenFunctie laagnaamOfZo, argument1, argument2.
Instellen van knoop-parameters als activatie en vuren:
Voor het instellen van parameters geldt in grote
lijnen wat geldt voor functies: je doet na wat je in de Nutshell omgeving doet.
In de Nutshell omgeving kan je altijd kijken wat voor parameters er zijn en
waar ze bij horen. Vervolgens kan je ze bereiken met de hiërarchie uitgelegd in
de sectie "Hoe verwijs je naar Nutshell?".
Hoe parameters heten hangt af van het paradigma. In
het MacGregorparadigma heb je de knoop-parameters "Membrane" en
"Fires" (om ze te zien: klik in een MacGregor-workspace een knoop
aan, klik op de rechtermuisknop, en dan onder "node(x)" op "parameters").
In opdracht 5.1 moet je een 'Frontale' laag aanmaken en een 'Thalamuslaag'.
Stel dat je "membrane" (het membraanpotentiaal) van de nulde knoop
van de frontale laag (frontLayer) op 1 wilt zetten. Dan schrijf je als
commando:
frontLayer.nodes(0).membrane = 1.0
frontLayer is hier een variabele die naar de
frontale laag verwijst. Zonder die variabele was het geworden (gegeven dat
frontLayer laag 0 is):
worksp.layers(0).nodes(0).membrane = 1.0
In dit voorbeeld is activatie (bij MacGregor gelijk
aan het membraanpotentiaal) een 'reële' parameter, een parameter waarbij je
reële getallen als waarden moet opgeven (vaak zijn de waarden wel aan maxima en
minima gebonden; wat die zijn kan je lezen in de Nutshell help bij
paradigma's). Je kunt ook andere soorten parameters hebben: parameters waarbij
je enkel 'integer'-waarden op kunt geven (=natuurlijke getallen), of
'Booleans'. In het macGregor-paradigma is bijvoorbeeld vuren een 'booleaanse'
parameter, een parameter die 'true' is als de knoop vuurt en 'false' als de
knoop niet vuurt (ook het normalizen van een 'tract', hierboven besproken, is
een boolean). Zo'n parameter kan je bijvoorbeeld als volgt instellen:
frontLayer.nodes(0).Fires = true
Instellen van een gewicht
Stel dat je het gewicht van de vierde knoop van een
frontale laag naar de tweede knoop van de thalamuslaag wilt instellen op 0.5.
Dan geef je als commando:
worksp.Tracts(thalLayer, frontLayer).connections(2,4).Weight=0.5
Naar connectionistenconventies komen ontvangers
eerst, dan pas zenders, zowel op het niveau van 'tracts' (bundel connecties van
één laag naar een andere laag) als op het niveau van individuele connecties.
"Tracts(thalLayer, frontLayer)" is dus de tract van de frontlayer naar de
thalamuslayer, Tracts(thalLayer, frontLayer).connections(2,4) is de connectie
van de 4e frontale knoop naar de 2e thalamusknoop. Daar roep je het gewicht van
aan, en dat zet je gelijk aan 0.5.
Instellen van de leerrate
Stel dat je de leerparameter, in de meeste
paradigma's 'mu' geheten, wilt instellen op 0.4 in de 'tract' van de frontale
laag naar de thalamuslaag. Dan schrijf je:
worksp.Tracts(frontLayer, thalLayer).mupos=0.4.
Weer gebruiken we variabelen om naar de lagen te
verwijzen. Vergeet niet dat de ontvanger eerst komt in het aanroepen van de
'tract', en dan pas de zender. Er is een aparte leerparameter voor elke
'tract'; d.w.z., voor elke bundel connecties van één laag naar een andere laag.
Als je de leerparameter voor de 'tract' van laag 1 naar laag 2 verandert,
blijft de leerparameter van laag 2 naar laag 3 dus precies hetzelfde - om die te
veranderen moet je een nieuw commando geven waarin je die leerparameter
verandert.
In de meeste paradigma's hoort de leerparameter bij
de 'tract', en moet je dus de 'tract' aanroepen zoals hierboven om hem te
veranderen. In het Backprop-paradigma is de leerparameter hetzelfde voor de
hele 'Workspace'. In dit geval stel je deze parameter (daar 'eta' geheten) in
als volgt:
workspace.eta = 0.05
(Voor opdracht 5.1:Er is ook een 'muneg' die
'Long-Term Depression' regelt. Deze parameter staat in elke 'tract' op 0, en
dat kan je beter zo houden.)
Leren en activatie updaten
Leren en activatie-updaten zijn commando's die je
doorgeeft aan de 'workspace'. Activatie updaten (=uitrekenen voor een nieuwe
iteratie) doe je met het volgende commando:
worksp.ActCycle
Enkel de activatie wordt ge-update, zonder dat er
sprake is van leren. De activatie wordt ge-update voor een aantal iteraties
tegelijk; de workspace-parameter 'Cycle Steps' bepaalt voor hoeveel iteraties
dit is. De uitgangswaarde is voor de meeste paradigma's gelijk aan 1. Enkel
voor Hopfield geldt dit niet: hier is de uitgangswaarde 100. Deze parameter kan
je als volgt instellen (bijvoorbeeld op 50):
worksp.CycleSteps = 50
Voor als je zeker wilt zijn dat de activatie maar
voor 1 iteratie ge-update wilt worden is er in de meeste paradigma's het
commando:
worksp.ActStep
Voor leren is er het commando:
worksp.learn
Bij de meeste paradigma's gebeurt dit voor 1
iteratie. Hoe leren precies gebeurt hangt af van het paradigma: elk paradigma
heeft zijn eigen leerregel.
In het MacGregor-paradigma is er ook een commando
voor het tegelijk activatie-updaten en leren:
worksp.cycle
Dit zorgt ervoor dat de activatie ge-'update' en de
gewichten aangepast worden. Wel is er een eigenaardigheid aan wanneer de
gewichten ge-update worden (zie uitleg opdracht 5).
Resetten van een laag
Hoger in deze appendix al uitgelegd. De variabele
"frontLayer" gebruikend wordt het:
worksp.resetlayernodes frontLayer
Hoe en wat ge-'reset' wordt hangt af van het
paradigma. In Hopfield wordt de activatie ge-'reset' op een willekeurige
waarde; in Kohonen, TraceLink en CALM wordt de activatie van knopen op 0 gezet.
Knopen blijven wel geclampd of gedeactiveerd als ze dat waren. In MacGregor
zorgt 'reset' ervoor dat alle knopen niet meer vuren, en dat alle activaties en
kaliumconcentraties weer gelijk gezet worden aan 0.
Clampen en deactiveren
Of een knoop ge'clamped' of ge'deactiveerd' is of
niet is een knoop-parameter. Je stelt ze in het script in op dezelfde manier
als andere knoop-parameters.
frontLayer.nodes(0).clamped=true (of: " = false")
frontLayer.nodes(0).deactivated=true (of: " = false")
Als je een hele laag wilt clampen of deactiveren is
het natuurlijk onhandig om alle knopen af te lopen. Daarom is er ook een
variabele voor de laag:
frontLayer.clamped=false
frontLayer.deactivated=true
Dit ont'clampt' alle knopen in de laag eerst (door
'clamped' op 'false' te zetten), en deactiveert ze vervolgens.
Zien wat er gebeurt
'Default' in Nutshell is dat je niet ziet wat er
gebeurt als je je script runt. Om op het scherm te zien hoe je simulatie erbij
staat moet je een speciaal commando in je code zetten:
workspace.update
Zet dit commando overal in je script waar je wilt
zien wat er gebeurt.
[9] Een argument van een functie
of procedure is een getalletje (of andere waarde) dat je mee moet geven om te
bepalen wat er precies moet gebeuren. In de functie 'plus' (x + y) heb je twee
argumenten: x en y, de twee getallen die je bij elkaar op moet tellen. Bij de functie
'Insert Layer' zijn de breedte en de hoogte van de aan te maken laag de
argumenten.
|