Last active
November 17, 2021 01:06
-
-
Save lrq3000/8217674 to your computer and use it in GitHub Desktop.
Efficient n-layers neural network implementation in NetLogo, with some useful matrix extended functions in Octave-style (like matrix:slice and matrix:max)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; N-Layer Neural Network semi-vectorized implementation in NetLogo 5.0.4 by Stephen Larroque | |
; This code implements standalone procedure to learn a n-layer neural network in regression/prediction of real-valued outputs or classification using one-vs-all in case of multiple classes. See go-learn for a practical example of usage. | |
; This is a somewhat direct translation from an Octave code, hence the recreation of missing functions like matrix:slice. | |
; This code does not necessitate any external library but the matrix extension, included in the standard NetLogo. | |
; Licensed under Simplified BSD License, feel free to reuse the code. | |
; | |
; TODO: implement nnCheckGradient | |
; TODO: implement classification | |
; TODO: implement optional visualisation, with turtles nodes, links, label on nodes and links with values (both forward and backward), one output node to show the prediction and two controls to disable/enable and for refresh rate | |
extensions [matrix] | |
;============================================================== | |
;================= EXAMPLE USAGE ================= | |
;============================================================== | |
to test | |
let m matrix:from-column-list [[1 -0.5 0 0.5 1]] | |
print matrix:dimensions m | |
print matrix:pretty-print-text m | |
print matrix:pretty-print-text sigmoid m | |
print matrix:pretty-print-text sigmoidGradient m | |
print matrix:pretty-print-text addBias m | |
end | |
to test2 | |
print matrix:pretty-print-text (nnDebugInitializeWeights 2 5) | |
print matrix:pretty-print-text (nnRandInitializeWeights 2 5) | |
end | |
; Real example for learning a neural network, either in debug mode (weights fixed and stochasticity removed) or not | |
to go-learn [debug?] | |
clear-all | |
set stop-learn false | |
;====== CONFIGURATION ====== | |
; Change anything here to your heart's content | |
; Parameters | |
;let neurons_per_layer (list 2 5 2) ; you can directly specify all the neurons if you want | |
let neurons_per_layer [] | |
let fmode 0 ; 0 = regression/prediction , 1 = classification (TODO: not implemented yet!) | |
let lambda nnlambda ; to reduce overfitting, this is the cost of parameters complexity | |
let epsilon nnepsilon ; gradient step, use smaller values if using stochastic gradient descent. May need a bit lower epsilon than in the Octave code because here the precision is more by default | |
let nIterMax 2000 | |
let diffThreshold 0 ; 0 to disable and force the learning for all iterations | |
let stochOrBatch 0 ; 0 batch learning, 1 stochastic learning | |
let learnPart 0.6 ; 0.6 = 60% points will be attributed to learning and the rest to the test set, 0 to disable | |
let checkGrad false ; Check the gradient at the end? | |
; Toy datasets | |
let X [] | |
let y [] | |
;1- Simple factor (epsi = 0.1 stoch) | |
if chooseExample = "Simple factor" [ | |
set X matrix:from-column-list [[1 2 3 4 5]] | |
set y matrix:from-column-list [[2 4 6 8 10]] | |
] | |
;2- Housing prices (epsi = 0.03 stoch) | |
if chooseExample = "Housing prices" [ | |
set X matrix:from-column-list [[1 3 4 5 9]] | |
set y matrix:from-column-list [[2 5.2 6.8 8.4 14.8]] | |
] | |
;3- Multivariate factor (epsi = 0.01 stoch) | |
if chooseExample = "Multivariate factor" [ | |
set X matrix:from-row-list [[1 3] [2 4] [3 5] [4 6] [5 7]] | |
set y matrix:from-row-list [[2 9] [4 12] [6 15] [8 18] [10 21]] | |
] | |
;4- Multivariate combination of features factor (epsi = 0.003 stoch and epsi = 0.01 batch) | |
if chooseExample = "Multivariate combination of features" [ | |
set X matrix:from-row-list [[1 3] [2 4] [3 5] [4 6] [5 7]] | |
set y matrix:from-row-list [[2 3] [4 8] [6 15] [8 24] [10 35]] | |
] | |
;====== PROGRAM ====== | |
; If using GUI to define the network layout, we generate the variable here | |
if empty? neurons_per_layer [ | |
let dim matrix:dimensions X | |
let N (item 1 dim) | |
let dimY matrix:dimensions Y | |
let NY (item 1 dimY) | |
set neurons_per_layer (sentence N (n-values hlayers [hneurons]) NY) | |
] | |
; If debug mode, remove all parameters that introduce stochasticity | |
if debug? [ | |
set learnPart 0 | |
set stochOrBatch 0 | |
] | |
let useCrossval false | |
if learnPart > 0 and learnPart < 1 [ | |
set useCrossval true | |
] | |
let init_Theta (nnInitializeWeights neurons_per_layer debug?) | |
let Theta (matrix:copy-recursive init_Theta) | |
;pretty-print-submatrix Theta | |
; Splitting dataset and then learning the neural network | |
let Xlearn [] | |
let Ylearn [] | |
let Xtest [] | |
let Ytest [] | |
ifelse useCrossval [ | |
let temp (crossval X y learnPart) | |
set Xlearn (item 0 temp) | |
set Ylearn (item 1 temp) | |
set Xtest (item 2 temp) | |
set Ytest (item 3 temp) | |
] | |
; No splitting | |
[ | |
set Xlearn X | |
set Ylearn y | |
set Xtest [] | |
set Ytest [] | |
] | |
; Learn | |
let temp (nnLearn fmode stochOrBatch | |
Theta neurons_per_layer lambda | |
Xlearn Ylearn Xtest Ytest | |
epsilon nIterMax diffThreshold) | |
set Theta (item 0 temp) | |
let err (item 1 temp) | |
let errtest (item 2 temp) | |
let t (item 3 temp) | |
; Prediction just to check the result | |
let tmp (nnForwardProp fmode neurons_per_layer Theta Xlearn) | |
let Ypred (item 0 tmp) | |
let A (item 1 tmp) | |
let Ypredtest [] | |
let Atest [] | |
if useCrossval [ | |
let tmptest (nnForwardProp fmode neurons_per_layer Theta Xtest) | |
set Ypredtest (item 0 tmptest) | |
set Atest (item 1 tmptest) | |
] | |
; Cost | |
let M (item 0 matrix:dimensions Xlearn) | |
let J (nnComputeCost fmode neurons_per_layer lambda M Theta A Ylearn Ypred) | |
let Mtest 0 | |
let Jtest 0 | |
if useCrossval [ | |
set Mtest (item 0 matrix:dimensions Xtest) | |
set Jtest (nnComputeCost fmode neurons_per_layer lambda Mtest Theta Atest Ytest Ypredtest) | |
] | |
; Printing infos | |
print "Xlearn:" | |
print matrix:pretty-print-text Xlearn | |
print "Ylearn:" | |
print matrix:pretty-print-text Ylearn | |
if useCrossval [ | |
print "Xtest:" | |
print matrix:pretty-print-text Xtest | |
print "Ytest:" | |
print matrix:pretty-print-text Ytest | |
] | |
print (word "Ypred:\n" matrix:pretty-print-text Ypred "\n") | |
if useCrossval [ | |
print (word "Ypred test:\n" matrix:pretty-print-text Ypredtest "\n") | |
] | |
print (word "Learn error:" J "\n") | |
if useCrossval [ | |
print (word "Test error:" Jtest "\n") | |
] | |
print "---------------------------------\n" | |
end | |
; Init and do only one step in debug mode (great to check the correct initialization and first working step of the neural network) | |
to one-step-debug | |
clear-all | |
set stop-learn false | |
let neurons_per_layer (list 2 5 2) | |
let lambda nnlambda | |
let fmode 0 | |
let X matrix:from-row-list [[1 3] [2 4] [3 5] [4 6] [5 7]] | |
let y matrix:from-row-list [[2 3] [4 8] [6 15] [8 24] [10 35]] | |
let M (item 0 matrix:dimensions X) | |
; Init | |
let Theta (nnInitializeWeights neurons_per_layer true) | |
; Forward prop | |
let tmp (nnForwardProp fmode neurons_per_layer Theta X) | |
let Ypred (item 0 tmp) | |
let A (item 1 tmp) | |
let Z (item 2 tmp) | |
; Cost | |
let J (nnComputeCost fmode neurons_per_layer lambda M Theta A y Ypred) | |
; Backward prop | |
let Theta_grad (nnBackwardProp fmode neurons_per_layer lambda M Theta A Z y) | |
print (word "Ypred:\n" matrix:pretty-print-text Ypred "\n") | |
print (word "J:" J "\n") | |
print (word "Theta_grad:" matrix:pretty-print-recursive Theta_grad "\n") | |
print (word "Theta:" matrix:pretty-print-recursive Theta "\n") | |
print "-------------------------\n" | |
end | |
;============================================================== | |
;================= NEURAL NETWORK FUNCTIONS ================= | |
;============================================================== | |
to-report addBias [X] | |
let dim matrix:dimensions X | |
let N item 0 dim | |
let M item 1 dim | |
let X2 matrix:make-constant N (M + 1) 1 | |
let i 0 | |
let j 0 | |
while [i < N] [ | |
while [j < M] [ | |
let a (matrix:get X i j) | |
matrix:set X2 i (j + 1) a ; we don't touch on the first column | |
set j (j + 1) | |
] | |
set i (i + 1) | |
set j 0 | |
] | |
report X2 | |
end | |
to-report sigmoidGradient [X] | |
let sigX (sigmoid X) | |
report matrix:times-element-wise sigX (matrix:plus-scalar (matrix:times-scalar sigX -1) 1) | |
end | |
to-report sigmoid [X] | |
let dim matrix:dimensions X | |
let M item 0 dim | |
let N item 1 dim | |
let X2 matrix:copy X | |
let i 0 | |
let j 0 | |
while [i < M] [ | |
while [j < N] [ | |
let a (matrix:get X i j) | |
matrix:set X2 i j (sig_aux a) ; WARNING: it's possible to edit X directly, but this will produce a side-effect, as modifying X in this procedure will also modify X in the parent procedure and anywhere else where the same matrix X is used! So if we call let X2 sigmoid (sigmoid X), X will also be modified, and twice! That's why we must use a copy of X here. | |
set j (j + 1) | |
] | |
set i (i + 1) | |
set j 0 | |
] | |
report X2 | |
end | |
to-report sig_aux [x] | |
let ret 0 | |
carefully [ | |
set ret 1 / (1 + e ^ (- x)) ; use e ^ (-x) so as to show to user that some values are too big and may produce weird results in the learning | |
] | |
[ | |
show (word "Number too big for NetLogo, produces infinity in sig_aux with e ^ (- x): -x = " (- x)) | |
set ret 1 / (1 + exp (- x)) ; prefer using (exp x) rather than (e ^ x) because the latter can produce an error (number is too big) while exp will produce Infinity without error | |
] | |
report ret | |
end | |
;ln(sigmoid(x) * (1+e^x)) = ln(1) | |
;ln(sigmoid(x)) + ln(1+e^x) = 0 | |
;ln(s) + x * e = 0 | |
;ln(s) = -(x * e) | |
;s = exp | |
to-report nnInitializeWeights [neurons_per_layer debug?] | |
let Layers (length neurons_per_layer) | |
let Theta n-values Layers [0] | |
let i 1 | |
while [i < Layers] [ | |
ifelse debug? [ | |
set Theta replace-item (i - 1) Theta (nnDebugInitializeWeights (item (i - 1) neurons_per_layer) (item i neurons_per_layer)) | |
] | |
[ | |
set Theta replace-item (i - 1) Theta (nnRandInitializeWeights (item (i - 1) neurons_per_layer) (item i neurons_per_layer)) | |
] | |
set i (i + 1) | |
] | |
report Theta | |
end | |
to-report nnDebugInitializeWeights [L_in L_out] | |
let N (1 + L_in) ; 1+L_in because the first row of W handles the "bias" term | |
let M L_out | |
let W matrix:make-constant M N 0 | |
let ind 1 | |
let i 0 | |
let j 0 | |
while [j < N] [ | |
while [i < M] [ | |
matrix:set W i j (sin(rad-to-angle(ind)) / 10) | |
set i (i + 1) | |
set ind (ind + 1) | |
] | |
set j (j + 1) | |
set i 0 | |
] | |
report W | |
end | |
to-report rad-to-angle [rad] | |
report 180 * rad / pi | |
end | |
to-report nnRandInitializeWeights [L_in L_out] | |
let N (1 + L_in) ; 1+L_in because the first row of W handles the "bias" term | |
let M L_out | |
let W matrix:make-constant M N 0 | |
let epsilon_init ((sqrt 6) / (sqrt (L_in + L_out))) ; or 0.12, both are magic values anyway, so you can change that to anything you want | |
let ind 1 | |
let i 0 | |
let j 0 | |
while [j < N] [ | |
while [i < M] [ | |
matrix:set W i j ((random-float 1) * 2 * epsilon_init - epsilon_init) | |
set i (i + 1) | |
set ind (ind + 1) | |
] | |
set j (j + 1) | |
set i 0 | |
] | |
report W | |
end | |
to-report crossval [X y learnPart] | |
let dim matrix:dimensions X | |
let M item 0 dim | |
let N item 1 dim | |
; Generate list of indexes and shuffle it | |
let indlist (gen-range 0 1 (M - 1)) | |
let indrand (shuffle indlist) | |
; Get the index where we must split the two datasets | |
let numlearn (round (learnPart * M)) ; Be careful with round: round a * b = (round a) * b != (round (a * b)) | |
let indrandlearn sort (sublist indrand 0 numlearn) | |
let indrandtest sort (sublist indrand numlearn M) | |
; Split the dataset in two | |
let Xlearn (matrix:slice X indrandlearn ":") | |
let Ylearn (matrix:slice y indrandlearn ":") | |
let Xtest (matrix:slice X indrandtest ":") | |
let Ytest (matrix:slice y indrandtest ":") | |
report (list Xlearn Ylearn Xtest Ytest) | |
end | |
to-report nnLearn [fmode stochOrBatch | |
Theta neurons_per_layer lambda | |
Xlearn Ylearn Xtest Ytest | |
epsilon nIterMax diffThreshold] | |
let dim matrix:dimensions Xlearn | |
let M item 0 dim | |
let Mtest [] | |
if not is-list? Xtest [ ; if it's not a matrix, it's an empty list | |
let dimtest matrix:dimensions Xtest | |
set Mtest item 0 dimtest | |
] | |
let Layers (length neurons_per_layer) | |
; Prepare for stochastic gradient | |
let orig_Xlearn [] | |
let orig_Ylearn [] | |
let orig_M M | |
if stochOrBatch = 1 [ | |
set orig_Xlearn Xlearn | |
set orig_Ylearn Ylearn | |
set M 1 | |
] | |
let t 1 | |
let err [] | |
let errtest [] | |
let converged false | |
let temp [] | |
while [not converged] [ | |
; == Preparing for stochastic gradient (pick only one example for each iteration instead of all examples at once) | |
let randind -1 | |
if stochOrBatch = 1 [ | |
set randind (floor ((random-float 1) * orig_M)) | |
set Xlearn (matrix:slice orig_Xlearn randind ":") | |
set Ylearn (matrix:slice orig_Ylearn randind ":") | |
] | |
; == Forward propagating + Computing cost | |
; = Learning dataset | |
set temp (nnForwardProp fmode neurons_per_layer Theta Xlearn) | |
let Ypred (item 0 temp) | |
let A (item 1 temp) | |
let Z (item 2 temp) | |
let er (nnComputeCost fmode neurons_per_layer lambda M Theta A Ylearn Ypred) | |
;set err (lput er err) ; Works OK but commented out to save memory space since it's plotted anyway | |
plot-learning-curve "learn" er | |
if not is-list? Xtest [ ; if it's not a matrix, it's an empty list | |
set temp (nnForwardProp fmode neurons_per_layer Theta Xtest) | |
let Ypredtest (item 0 temp) | |
let Atest (item 1 temp) | |
let Ztest (item 2 temp) | |
let ert (nnComputeCost fmode neurons_per_layer lambda Mtest Theta Atest Ytest Ypredtest) | |
;set errtest (lput ert errtest) ; Works OK but commented out to save memory space since it's plotted anyway | |
plot-learning-curve "test" ert | |
] | |
; == Back propagating | |
; Computing gradient | |
let Theta_grad (nnBackwardProp fmode neurons_per_layer lambda M Theta A Z Ylearn) | |
; Comitting gradient to change our parameters Theta | |
let Theta2 (n-values Layers [0]) | |
let i 0 | |
while [i < (Layers - 1)] [ | |
let epsi (epsilon / (1 + (t - 1) * nnDecay)) ; Implementing learning rate decay (aka gradient step decay) so that the network converges faster | |
let newval (matrix:plus (item i Theta) (matrix:times-scalar (matrix:times-scalar (item i Theta_grad) epsi) -1)) | |
set Theta2 (replace-item i Theta2 newval) | |
set i (i + 1) | |
] | |
; Computing gradient diff (to stop if we are below diffThreshold, meaning there's no change anymore in the gradient, which may not be true if we are in a plateau!) | |
let wdiff 999 | |
if diffThreshold > 0 [ | |
let mdiff (matrix:plus (item 0 Theta2) (matrix:times-scalar (item 0 Theta) -1)) | |
set wdiff (matrix:sum (matrix:sqrt (matrix:sum (matrix:times-element-wise mdiff mdiff) 2) ) 1) ; First we must sum over the features and square root to compute the euclidian distance, then we can sum over all examples errors | |
; 2nd stop criterion: not enough change in the latest gradient, we suppose we converged (warning: way simply may be in a plateau, happens frequently in neural networks and other concave problems!) | |
if wdiff <= diffThreshold [ set converged true ] | |
; NB: no need to recompute the cost/error, since the gradient didn't change so much, the error is about stable | |
] | |
; Update Theta now (we delayed and used Theta2 only to compute the gradient diff) | |
set Theta Theta2 | |
; Increment t (iteration counter) | |
set t (t + 1) | |
; 1st stop criterion: we reached the maximum number of iterations allowed or if the user want to stop learning | |
if t >= nIterMax or stop-learn [ | |
set converged true | |
; Recompute the forward propagation and cost with the latest gradient... Below is just a copy-paste of what is above (FIXME) | |
set er (nnComputeCost fmode neurons_per_layer lambda M Theta A Ylearn Ypred) | |
;set err (lput er err) | |
plot-learning-curve "learn" er | |
if not is-list? Xtest [ ; if it's not a matrix, it's an empty list | |
set temp (nnForwardProp fmode neurons_per_layer Theta Xtest) | |
let Ypredtest (item 0 temp) | |
let Atest (item 1 temp) | |
let Ztest (item 2 temp) | |
let ert (nnComputeCost fmode neurons_per_layer lambda Mtest Theta Atest Ytest Ypredtest) | |
;set errtest (lput ert errtest) | |
plot-learning-curve "test" ert | |
] | |
] | |
; Force refreshing of the plots | |
display | |
] | |
report (list Theta err errtest t) | |
end | |
to-report nnForwardProp [fmode neurons_per_layer Theta X] | |
let dim matrix:dimensions X | |
let M item 0 dim | |
let Layers (length neurons_per_layer) | |
; == Forward propagation | |
let Ypred [] | |
let A (n-values Layers [0]) ; Stores the untampered scores on each layer (mainly hidden layers) | |
let Z (n-values Layers [0]) ; Stores the scores on each layer passed through a sigmoid function (you can edit here if you want to change the function of the hidden layers. For the output layer it's in nnComputeCost and nnBackwardProp) | |
; Init the propagation with X (with added bias unit) | |
set A (replace-item 0 A addBias(X)) | |
; Forward propagating the prediction scores | |
let L 1 | |
while [L < Layers] [ | |
let Zval matrix:times (item (L - 1) A) (matrix:transpose (item (L - 1) Theta)) | |
set Z (replace-item L Z Zval) | |
ifelse fmode = 0 and L = (Layers - 1) [ | |
set A (replace-item L A (item L Z)) | |
] | |
[ | |
set A (replace-item L A (sigmoid (item L Z))) | |
] | |
if L < (Layers - 1) [ | |
set A (replace-item L A (addBias (item L A))) ; adding bias unit (except for the last layer) | |
] | |
set L (L + 1) | |
] | |
; Post-processing the scores into a prediction (of class or of value) | |
ifelse fmode = 0 [ | |
set Ypred (item (Layers - 1) A) | |
] | |
[ | |
set Ypred (matrix:max (item (Layers - 1) A) 2) | |
] | |
report (list Ypred A Z) | |
end | |
to-report nnComputeCost [fmode neurons_per_layer lambda M Theta A Y Ypred] | |
let Layers (length neurons_per_layer) | |
let J -1 ; -1 so that it will produce an error later if J is not assigned since a cost cannot be negative | |
ifelse fmode = 0 [ | |
if is-number? Y [ set Y matrix:from-row-list (list (list Y)) ] ; Convert to a matrix if it's only a number | |
if is-number? Ypred [ set Ypred matrix:from-row-list (list (list Ypred)) ] ; Convert to a matrix if it's only a number | |
let ydiff (matrix:plus Y (matrix:times-scalar Ypred -1)) | |
set J (matrix:sum (matrix:sum (matrix:times-element-wise ydiff ydiff) 2) 1) ; First we must sum over the features to compute some kind of euclidian distance, then we can sum over all examples errors (don't try to put a square root here, it degrades a lot the performances! This is a correct implementation after checking with nnCheckGradient) | |
set J (1 / (2 * M) * J) ; scale cost relatively to the size of the dataset | |
] | |
[ | |
; TODO: Classification multiclass logistic cost | |
; Here is the Octave code to translate into NetLogo | |
; | |
;% == Preparing Y (converting classes of 1,2..K to binary vectors | |
;num_labels = neurons_per_layer(end); % or num_labels = size(Theta{Layers-1}, 1) | |
;Y = zeros(m, num_labels); | |
;% Method1: 0.044s | |
;%for k = 1:num_labels | |
;% Y(:, k) = (y == k); | |
;%end | |
;% Method2: 0.00087s | |
;%K = num_labels; | |
;%temp1=ones(m,1)*[1:K];temp2=y*ones(1,K);Y=(temp1==temp2); | |
;% Method3: 0.00016s | |
;K = num_labels; | |
;Y=bsxfun(@eq,y,1:K); | |
;J = 1/m * sum(sum(-Y.*log(A{end}) -(1-Y).*log(1-A{end}), 2), 1); % A3 (ypred) is a probability of certainty over y which is the perfect result to achieve (which is impossible in practice, we can only have a probability between [0..1] of detecting the right class) | |
;% Note: A{end} is the same as ypred but with more informations: ypred is the predicted class, while A{end} is analog to the conditional probability of likelihood of each class, not just the class that scored the maximum proba! We need this "details" to compute the cost as it will tell us how far we are from really guessing the right class (even if it's correctly predicted! but a probability of 0.2 for class 1 and 0.1 for all the others is not the same as a proba of 0.9 for class 1 and 0.1 for the others!). | |
] | |
let sum_thetas 0 | |
let L 0 | |
while [L < (Layers - 1)] [ | |
let th (matrix:slice (item L Theta) ":" "1:end") | |
set sum_thetas (sum_thetas + (matrix:sum (matrix:sum (matrix:times-element-wise th th) 1) 2) ) | |
set L (L + 1) | |
] | |
set J (J + lambda / (2 * M) * sum_thetas) | |
report J | |
end | |
to-report nnBackwardProp [fmode neurons_per_layer lambda M Theta A Z Y] | |
let Layers (length neurons_per_layer) | |
let delta (n-values Layers [0]) | |
let Ypredscores (item (Layers - 1) A) | |
if is-number? Y [ set Y matrix:from-row-list (list (list Y)) ] ; Convert to a matrix if it's only a number | |
; == Initializing first value for back propagation | |
; We initialize the last delta for the last layer, and we backpropagate to the first layer (kind of the opposite of the forward propagation) | |
ifelse fmode = 0 [ | |
set delta (replace-item (Layers - 1) delta (matrix:plus Ypredscores (matrix:times-scalar Y -1))) | |
] | |
[ | |
let num_labels (item (Layers - 1) neurons_per_layer) | |
; TODO: Classification multiclass | |
; Here is the Octave code to translate into NetLogo | |
; | |
;% == Preparing Y (converting classes of 1,2..K to binary vectors | |
;num_labels = neurons_per_layer(end); % or num_labels = size(Theta{Layers-1}, 1) | |
;Y = zeros(m, num_labels); | |
;% Method1: 0.044s | |
;%for k = 1:num_labels | |
;% Y(:, k) = (y == k); | |
;%end | |
;% Method2: 0.00087s | |
;%K = num_labels; | |
;%temp1=ones(m,1)*[1:K];temp2=y*ones(1,K);Y=(temp1==temp2); | |
;% Method3: 0.00016s | |
;K = num_labels; | |
;Y=bsxfun(@eq,y,1:K); | |
;delta{Layers} = ypredscores - Y; | |
] | |
; == Backpropagating errors (for nodes) from last layer towards first layer | |
let L (Layers - 2) | |
while [L >= 1] [ | |
let tmp (matrix:times (item (L + 1) delta) (matrix:slice (item L Theta) ":" "1:end") ) | |
set tmp (matrix:times-element-wise tmp (sigmoidGradient (item L Z))) ; Change here if you want to use another function for the hidden layers than sigmoid! Sigmoid was used for its non-linearity and because it's pretty easy to use and understand. | |
set delta (replace-item L delta tmp) | |
set L (L - 1) | |
] | |
; == Backpropagating error gradient (for the weights) from last layer towards first layer | |
let D (n-values Layers [0]) ; D = Theta_grad | |
set L (Layers - 2) | |
while [L >= 0] [ | |
let tmp (matrix:times (matrix:transpose (item (L + 1) delta)) (item L A)) | |
set tmp (matrix:times-scalar tmp (1 / M)) ; scale cost relatively to the size of the dataset | |
set D (replace-item L D tmp) | |
set L (L - 1) | |
] | |
; == Regularize the gradient | |
set L (Layers - 2) | |
while [L >= 0] [ | |
let tg (matrix:slice (item L D) ":" "1:end") | |
let t (matrix:slice (item L Theta) ":" "1:end") | |
let tmp matrix:plus tg (matrix:times-scalar t (lambda / M)) | |
let t1 (matrix:get-column (item L D) 0) | |
set D (replace-item L D (matrix:prepend-column tmp t1)) | |
set L (L - 1) | |
] | |
let Theta_grad D | |
report Theta_grad | |
end | |
to plot-learning-curve [pen cost] | |
set-current-plot "Learning curve" | |
set-current-plot-pen pen | |
plot cost | |
end | |
;============================================================== | |
;================= MATRIX AUXILIARY FUNCTIONS ================= | |
;============================================================== | |
to-report matrix:slice [X indx indy] | |
let X2 matrix:copy X | |
let dim matrix:dimensions X2 | |
let M item 0 dim | |
let N item 1 dim | |
ifelse is-number? indx and is-number? indy [ | |
report matrix:get X2 indx indy | |
] | |
[ | |
let indx1 0 | |
let indx2 M | |
let indy1 0 | |
let indy2 N | |
; ROW VECTORIZED SLICING | |
; indx is a range of indexes (given as a string, format: "start:end") | |
ifelse is-string? indx [ | |
; Special case: we want all rows, in this case there's no processing necessary here | |
ifelse indx = ":" or indx = "0:end" or indx = (word "0:" (M - 1)) [ | |
set indx1 0 | |
set indx2 M | |
] | |
[ | |
; Special case: contains only "end", shorthand for the maximum index | |
ifelse indx = "end" [ | |
set indx (end-to-index M indx) | |
] | |
; Any other case we have a range | |
[ | |
; Extract the starting and ending indexes | |
let indxsplit (split indx ":") | |
set indx1 (item 0 indxsplit) | |
set indx2 (item 1 indxsplit) | |
; Check if one of them contains "end" and replace with the correct value | |
set indx1 (end-to-index M indx1) | |
set indx2 (end-to-index M indx2) | |
set indx2 min (list M (indx2 + 1)) ; add 1 because that's how submatrix works for the end column: it's exclusive, so indx1=1 indx2=2 will only select the 2nd row (not the 2nd and 3rd) | |
] | |
] | |
] | |
[ | |
; indx is just one index (a number) | |
; Note: indx as a list of indexes is processed later (since we can't vectorize it, there's no built-in function) | |
if (is-list? indx) = false [ | |
set indx1 indx | |
set indx2 (indx + 1) | |
;set X2 matrix:submatrix X2 indx 0 (indx + 1) N ; submatrix is more consistent than get-row or get-column since it always returns a matrix, and not a list or a number | |
] | |
] | |
; COLUMN VECTORIZED SLICING | |
; indx is a range of indexes (given as a string, format: "start:end") | |
ifelse is-string? indy [ | |
; Special case: we want all rows, in this case there's no processing necessary here | |
ifelse indy = ":" or indy = "0:end" or indy = (word "0:" (N - 1)) [ | |
set indy1 0 | |
set indy2 N | |
] | |
[ | |
; Special case: contains only "end", shorthand for the maximum index | |
ifelse indy = "end" [ | |
set indy (end-to-index N indy) | |
] | |
; Any other case we have a range | |
[ | |
; Extract the starting and ending indexes | |
let indysplit (split indy ":") | |
set indy1 (item 0 indysplit) | |
set indy2 (item 1 indysplit) | |
; Check if one of them contains "end" and replace with the correct value | |
set indy1 (end-to-index N indy1) | |
set indy2 (end-to-index N indy2) | |
set indy2 min (list N (indy2 + 1)) ; add 1 because that's how submatrix works for the end column: it's exclusive, so indy1=1 indy2=2 will only select the 2nd column (not the 2nd and 3rd) | |
] | |
] | |
] | |
[ | |
; indy is just one index (a number) | |
; Note: indy as a list of indexes is processed later (since we can't vectorize it, there's no built-in function) | |
if (is-list? indy) = false [ | |
set indy1 indy | |
set indy2 (indy + 1) | |
;set X2 matrix:submatrix X2 0 indy M (indy + 1) ; submatrix is more consistent than get-row or get-column since it always returns a matrix, and not a list or a number | |
] | |
] | |
; PROCESSING VECTORIZED SLICING | |
; Show precise error if out of bounds | |
;show (word indx1 " " indx2 " " indy1 " " indy2) | |
if indx1 < 0 or indx2 > M or indy1 < 0 or indy2 > N [ | |
let errmsg "" | |
if indx1 < 0 [ set errmsg (word errmsg "x (" indx1 ") can't be negative. ") ] | |
if indx2 > M [ set errmsg (word errmsg "x (" indx2 ") exceeds matrix dimensions (" M "). ") ] | |
if indy1 < 0 [ set errmsg (word errmsg "y (" indy1 ") can't be negative. ") ] | |
if indy2 > N [ set errmsg (word errmsg "y (" indy2 ") exceeds matrix dimensions (" N "). ") ] | |
error errmsg | |
] | |
; Doing the slicing using submatrix | |
set X2 matrix:submatrix X2 indx1 indy1 indx2 indy2 | |
; UNVECTORIZED SLICING | |
; if indx and/or indy is a list of indexes (not a range nor number), thus it can be a non-contiguous range of indexes (eg: 1, 3, 4), we have to do it by ourselves in a for loop | |
; We suppose that if indx is a list, then necessarily all rows from X were not touched and are intact in X2 (with same indexes), and thus we can extract from X2 with same indexes as in X. Same for indy and columns. | |
; indx is a list of indexes | |
if is-list? indx [ | |
let Xlist [] | |
let i 0 | |
; For each index in the list | |
while [i < (length indx)] [ | |
; Extract the index ind and then the row from X2 at this index | |
let ind (item i indx) | |
let row (matrix:get-row X2 ind) | |
; Append this row to our list of rows | |
set Xlist lput row Xlist | |
; Increment... | |
set i (i + 1) | |
] | |
; Finally, convert back to a matrix! | |
set X2 matrix:from-row-list Xlist | |
] | |
; indy is a list of indexes | |
if is-list? indy [ | |
let Xlist [] | |
let j 0 | |
; For each index in the list | |
while [j < (length indy)] [ | |
; Extract the index ind and then the column from X2 at this index | |
let ind (item j indy) | |
let column (matrix:get-column X2 ind) | |
; Append this column to our list of columns | |
set Xlist lput column Xlist | |
; Increment... | |
set j (j + 1) | |
] | |
; Finally, convert back to a matrix! | |
set X2 matrix:from-column-list Xlist | |
] | |
] | |
; RETURN THE SLICED MATRIX | |
report X2 | |
end | |
; row is a list | |
to-report matrix:append-row [X row] | |
if not is-list? row [ | |
error "matrix:append-row: specified row is not a list!" | |
] | |
report matrix:from-row-list lput row (matrix:to-row-list X) | |
end | |
; column is a list | |
to-report matrix:append-column [X column] | |
if not is-list? column [ | |
error "matrix:append-column: specified column is not a list!" | |
] | |
report matrix:from-column-list lput column (matrix:to-column-list X) | |
end | |
; row is a list | |
to-report matrix:prepend-row [X row] | |
if not is-list? row [ | |
error "matrix:prepend-row: specified row is not a list!" | |
] | |
report matrix:from-row-list fput row (matrix:to-row-list X) | |
end | |
; column is a list | |
to-report matrix:prepend-column [X column] | |
if not is-list? column [ | |
error "matrix:prepend-column: specified column is not a list!" | |
] | |
report matrix:from-column-list fput column (matrix:to-column-list X) | |
end | |
to-report end-to-index [maxind itm] | |
let ret itm | |
; If it's a special string, we process it | |
ifelse is-string? itm [ | |
if itm = "end" [ | |
set ret maxind | |
] | |
] | |
; Else if it's not a string (number, matrix, etc.), we return it as-is | |
[ | |
set ret itm | |
] | |
report ret | |
end | |
to-report split [string delimiter] | |
let splitted [] | |
let i 0 | |
let previ 0 | |
; Append any item place before where we meet the delimiter | |
while [i < (length string)][ | |
if (item i string) = delimiter [ | |
let substr (substring string previ i) | |
; Try to convert to a number if possible | |
carefully [ | |
set substr (read-from-string substr) | |
][] | |
set splitted (lput substr splitted) | |
set previ (i + 1) | |
] | |
set i (i + 1) | |
] | |
; Appending the remaining substring after the last delimiter found | |
if (length string) > previ [ | |
let substr (substring string previ (length string)) | |
carefully [ | |
set substr (read-from-string substr) | |
][] | |
set splitted (lput substr splitted) | |
] | |
report splitted | |
end | |
to-report gen-range [start step endd] | |
report n-values (((endd - start) + step) / step) [(? * step) + start] | |
end | |
; Square root element wise for matrixes | |
; NB: does not support imaginary values (so you need to make sure there's no negative number in the matrix!) | |
to-report matrix:sqrt [X] | |
let X2 matrix:copy X | |
let dim matrix:dimensions X2 | |
let M item 0 dim | |
let N item 1 dim | |
let i 0 | |
let j 0 | |
while [j < N] [ | |
while [i < M] [ | |
matrix:set X2 i j (sqrt (matrix:get X2 i j)) | |
set i (i + 1) | |
] | |
set j (j + 1) | |
set i 0 | |
] | |
report X2 | |
end | |
; Semi-vectorized procedure to sum a matrix over rows or columns | |
; If the matrix is not summable or there is only one element, it will return the same matrix | |
to-report matrix:sum [X columnsOrRows?] ; columnsOrRows? 2 = over columns | |
if is-number? X [report X] ; if it's already a number, we've got nothing to do, just return it | |
if is-list? X [report sum X] ; if it's a list we use the built-in function | |
let dim matrix:dimensions X | |
let M item 0 dim | |
let N item 1 dim | |
let Xret [] | |
; Sum over columns | |
ifelse columnsOrRows? = 2 [ | |
let i 0 | |
while [i < M] [ | |
set Xret lput (sum matrix:get-row X i) Xret | |
set i (i + 1) | |
] | |
; Convert to a number if the list contains only one number | |
ifelse (length Xret) = 1 [ | |
set Xret (item 0 Xret) | |
] | |
; Else convert back to a matrix (a vector in fact) to ease computations later | |
[ | |
set Xret (matrix:from-column-list (list Xret)) | |
] | |
] | |
; Else sum over rows | |
[ | |
let j 0 | |
while [j < N] [ | |
set Xret lput (sum matrix:get-column X j) Xret | |
set j (j + 1) | |
] | |
; Convert to a number if the list contains only one number | |
ifelse (length Xret) = 1 [ | |
set Xret (item 0 Xret) | |
] | |
; Else convert back to a matrix (a vector in fact) to ease computations later | |
[ | |
set Xret (matrix:from-row-list (list Xret)) | |
] | |
] | |
report Xret | |
end | |
; Semi-vectorized procedure to return the max value of a matrix over rows or columns | |
; If the matrix is not summable or there is only one element, it will return the same matrix | |
; NB: it's a copy-cat of matrix:sum | |
to-report matrix:max [X columnsOrRows?] ; columnsOrRows? 2 = over columns | |
if is-number? X [report X] ; if it's already a number, we've got nothing to do, just return it | |
if is-list? X [report max X] ; if it's a list we use the built-in function | |
let dim matrix:dimensions X | |
let M item 0 dim | |
let N item 1 dim | |
let Xret [] | |
; Over columns | |
ifelse columnsOrRows? = 2 [ | |
let i 0 | |
while [i < M] [ | |
set Xret lput (max matrix:get-row X i) Xret | |
set i (i + 1) | |
] | |
; Convert to a number if the list contains only one number | |
ifelse (length Xret) = 1 [ | |
set Xret (item 0 Xret) | |
] | |
; Else convert back to a matrix (a vector in fact) to ease computations later | |
[ | |
set Xret (matrix:from-column-list (list Xret)) | |
] | |
] | |
; Else Over rows | |
[ | |
let j 0 | |
while [j < N] [ | |
set Xret lput (max matrix:get-column X j) Xret | |
set j (j + 1) | |
] | |
; Convert to a number if the list contains only one number | |
ifelse (length Xret) = 1 [ | |
set Xret (item 0 Xret) | |
] | |
; Else convert back to a matrix (a vector in fact) to ease computations later | |
[ | |
set Xret (matrix:from-row-list (list Xret)) | |
] | |
] | |
report Xret | |
end | |
; Semi-vectorized procedure to return the min value of a matrix over rows or columns | |
; If the matrix is not summable or there is only one element, it will return the same matrix | |
; NB: it's a copy-cat of matrix:sum | |
to-report matrix:min [X columnsOrRows?] ; columnsOrRows? 2 = over columns | |
if is-number? X [report X] ; if it's already a number, we've got nothing to do, just return it | |
if is-list? X [report min X] ; if it's a list we use the built-in function | |
let dim matrix:dimensions X | |
let M item 0 dim | |
let N item 1 dim | |
let Xret [] | |
; Over columns | |
ifelse columnsOrRows? = 2 [ | |
let i 0 | |
while [i < M] [ | |
set Xret lput (min matrix:get-row X i) Xret | |
set i (i + 1) | |
] | |
; Convert to a number if the list contains only one number | |
ifelse (length Xret) = 1 [ | |
set Xret (item 0 Xret) | |
] | |
; Else convert back to a matrix (a vector in fact) to ease computations later | |
[ | |
set Xret (matrix:from-column-list (list Xret)) | |
] | |
] | |
; Else Over rows | |
[ | |
let j 0 | |
while [j < N] [ | |
set Xret lput (min matrix:get-column X j) Xret | |
set j (j + 1) | |
] | |
; Convert to a number if the list contains only one number | |
ifelse (length Xret) = 1 [ | |
set Xret (item 0 Xret) | |
] | |
; Else convert back to a matrix (a vector in fact) to ease computations later | |
[ | |
set Xret (matrix:from-row-list (list Xret)) | |
] | |
] | |
report Xret | |
end | |
; Recursively print a mega matrix (recursive list of matrixes or in fact any other element) | |
; Should be used with print | |
to-report matrix:pretty-print-recursive [megamatrix] | |
report matrix:pretty-print-recursive-aux megamatrix 1 | |
end | |
to-report matrix:pretty-print-recursive-aux [megamatrix level] ; megamatrix is a list of matrixes | |
ifelse is-list? megamatrix [ | |
let n (length megamatrix) | |
let i 0 | |
let text "" | |
let levelstring (word (reduce [word ?1 ?2] (n-values level ["-"])) ">") | |
while [i < n] [ | |
set text (word text "\n" (word levelstring i ": " (matrix:pretty-print-recursive-aux (item i megamatrix) (level + 1)))) | |
set i (i + 1) | |
] | |
report text | |
] | |
[ | |
if megamatrix = nobody [ | |
report "nobody" | |
] | |
ifelse is-number? megamatrix or is-string? megamatrix [ | |
report megamatrix | |
] | |
[ | |
report (word "\n" matrix:pretty-print-text megamatrix) | |
] | |
] | |
end | |
; Deep recursive copy of a megamatrix (list of matrix) | |
to-report matrix:copy-recursive [megamatrix] | |
; Entry point: if it's a list, we will recursively copy everything inside (deep copy) | |
ifelse is-list? megamatrix [ | |
let n (length megamatrix) | |
let m2 (n-values n [0]) | |
let i 0 | |
while [i < n] [ | |
set m2 (replace-item i m2 (matrix:copy-recursive (item i megamatrix))) | |
set i (i + 1) | |
] | |
report m2 | |
] | |
; Recursively called from here | |
[ | |
; If it's a number or string we just report it | |
ifelse is-number? megamatrix or is-string? megamatrix [ | |
report megamatrix | |
] | |
; Else if it's a matrix (we have no other way to check it but by default), then we make a copy and report it | |
[ | |
report matrix:copy megamatrix | |
] | |
] | |
end | |
@#$#@#$#@ | |
GRAPHICS-WINDOW | |
282 | |
10 | |
527 | |
210 | |
6 | |
6 | |
13.0 | |
1 | |
10 | |
1 | |
1 | |
1 | |
0 | |
1 | |
1 | |
1 | |
-6 | |
6 | |
-6 | |
6 | |
0 | |
0 | |
1 | |
ticks | |
30.0 | |
BUTTON | |
466 | |
12 | |
529 | |
45 | |
NIL | |
test | |
NIL | |
1 | |
T | |
OBSERVER | |
NIL | |
NIL | |
NIL | |
NIL | |
1 | |
BUTTON | |
528 | |
12 | |
591 | |
45 | |
NIL | |
test2 | |
NIL | |
1 | |
T | |
OBSERVER | |
NIL | |
NIL | |
NIL | |
NIL | |
1 | |
BUTTON | |
4 | |
115 | |
80 | |
148 | |
Learn! | |
go-learn false | |
NIL | |
1 | |
T | |
OBSERVER | |
NIL | |
NIL | |
NIL | |
NIL | |
1 | |
BUTTON | |
126 | |
148 | |
227 | |
181 | |
NIL | |
one-step-debug | |
NIL | |
1 | |
T | |
OBSERVER | |
NIL | |
NIL | |
NIL | |
NIL | |
1 | |
PLOT | |
1 | |
212 | |
279 | |
362 | |
Learning curve | |
Iteration | |
Cost | |
0.0 | |
10.0 | |
0.0 | |
0.0 | |
true | |
true | |
"" "" | |
PENS | |
"learn" 1.0 0 -14070903 true "" "" | |
"test" 1.0 0 -5298144 true "" "" | |
BUTTON | |
80 | |
115 | |
227 | |
148 | |
Learn debug (fixed params) | |
go-learn true | |
NIL | |
1 | |
T | |
OBSERVER | |
NIL | |
NIL | |
NIL | |
NIL | |
1 | |
CHOOSER | |
3 | |
10 | |
227 | |
55 | |
chooseExample | |
chooseExample | |
"Simple factor" "Housing prices" "Multivariate factor" "Multivariate combination of features" | |
3 | |
INPUTBOX | |
4 | |
55 | |
60 | |
115 | |
hneurons | |
5 | |
1 | |
0 | |
Number | |
INPUTBOX | |
60 | |
55 | |
110 | |
115 | |
hlayers | |
1 | |
1 | |
0 | |
Number | |
SWITCH | |
4 | |
148 | |
99 | |
181 | |
stop-learn | |
stop-learn | |
1 | |
1 | |
-1000 | |
INPUTBOX | |
170 | |
55 | |
227 | |
115 | |
nnepsilon | |
0.05 | |
1 | |
0 | |
Number | |
INPUTBOX | |
110 | |
55 | |
170 | |
115 | |
nnlambda | |
0 | |
1 | |
0 | |
Number | |
INPUTBOX | |
227 | |
56 | |
280 | |
116 | |
nnDecay | |
0.01 | |
1 | |
0 | |
Number | |
@#$#@#$#@ | |
## WHAT IS IT? | |
(a general understanding of what the model is trying to show or explain) | |
## HOW IT WORKS | |
(what rules the agents use to create the overall behavior of the model) | |
## HOW TO USE IT | |
(how to use the model, including a description of each of the items in the Interface tab) | |
## THINGS TO NOTICE | |
(suggested things for the user to notice while running the model) | |
## THINGS TO TRY | |
(suggested things for the user to try to do (move sliders, switches, etc.) with the model) | |
## EXTENDING THE MODEL | |
(suggested things to add or change in the Code tab to make the model more complicated, detailed, accurate, etc.) | |
## NETLOGO FEATURES | |
(interesting or unusual features of NetLogo that the model uses, particularly in the Code tab; or where workarounds were needed for missing features) | |
## RELATED MODELS | |
(models in the NetLogo Models Library and elsewhere which are of related interest) | |
## CREDITS AND REFERENCES | |
(a reference to the model's URL on the web if it has one, as well as any other necessary credits, citations, and links) | |
@#$#@#$#@ | |
default | |
true | |
0 | |
Polygon -7500403 true true 150 5 40 250 150 205 260 250 | |
airplane | |
true | |
0 | |
Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15 | |
arrow | |
true | |
0 | |
Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150 | |
box | |
false | |
0 | |
Polygon -7500403 true true 150 285 285 225 285 75 150 135 | |
Polygon -7500403 true true 150 135 15 75 150 15 285 75 | |
Polygon -7500403 true true 15 75 15 225 150 285 150 135 | |
Line -16777216 false 150 285 150 135 | |
Line -16777216 false 150 135 15 75 | |
Line -16777216 false 150 135 285 75 | |
bug | |
true | |
0 | |
Circle -7500403 true true 96 182 108 | |
Circle -7500403 true true 110 127 80 | |
Circle -7500403 true true 110 75 80 | |
Line -7500403 true 150 100 80 30 | |
Line -7500403 true 150 100 220 30 | |
butterfly | |
true | |
0 | |
Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240 | |
Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240 | |
Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163 | |
Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165 | |
Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225 | |
Circle -16777216 true false 135 90 30 | |
Line -16777216 false 150 105 195 60 | |
Line -16777216 false 150 105 105 60 | |
car | |
false | |
0 | |
Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180 | |
Circle -16777216 true false 180 180 90 | |
Circle -16777216 true false 30 180 90 | |
Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89 | |
Circle -7500403 true true 47 195 58 | |
Circle -7500403 true true 195 195 58 | |
circle | |
false | |
0 | |
Circle -7500403 true true 0 0 300 | |
circle 2 | |
false | |
0 | |
Circle -7500403 true true 0 0 300 | |
Circle -16777216 true false 30 30 240 | |
cow | |
false | |
0 | |
Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167 | |
Polygon -7500403 true true 73 210 86 251 62 249 48 208 | |
Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123 | |
cylinder | |
false | |
0 | |
Circle -7500403 true true 0 0 300 | |
dot | |
false | |
0 | |
Circle -7500403 true true 90 90 120 | |
face happy | |
false | |
0 | |
Circle -7500403 true true 8 8 285 | |
Circle -16777216 true false 60 75 60 | |
Circle -16777216 true false 180 75 60 | |
Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240 | |
face neutral | |
false | |
0 | |
Circle -7500403 true true 8 7 285 | |
Circle -16777216 true false 60 75 60 | |
Circle -16777216 true false 180 75 60 | |
Rectangle -16777216 true false 60 195 240 225 | |
face sad | |
false | |
0 | |
Circle -7500403 true true 8 8 285 | |
Circle -16777216 true false 60 75 60 | |
Circle -16777216 true false 180 75 60 | |
Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183 | |
fish | |
false | |
0 | |
Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166 | |
Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165 | |
Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60 | |
Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166 | |
Circle -16777216 true false 215 106 30 | |
flag | |
false | |
0 | |
Rectangle -7500403 true true 60 15 75 300 | |
Polygon -7500403 true true 90 150 270 90 90 30 | |
Line -7500403 true 75 135 90 135 | |
Line -7500403 true 75 45 90 45 | |
flower | |
false | |
0 | |
Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135 | |
Circle -7500403 true true 85 132 38 | |
Circle -7500403 true true 130 147 38 | |
Circle -7500403 true true 192 85 38 | |
Circle -7500403 true true 85 40 38 | |
Circle -7500403 true true 177 40 38 | |
Circle -7500403 true true 177 132 38 | |
Circle -7500403 true true 70 85 38 | |
Circle -7500403 true true 130 25 38 | |
Circle -7500403 true true 96 51 108 | |
Circle -16777216 true false 113 68 74 | |
Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218 | |
Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240 | |
house | |
false | |
0 | |
Rectangle -7500403 true true 45 120 255 285 | |
Rectangle -16777216 true false 120 210 180 285 | |
Polygon -7500403 true true 15 120 150 15 285 120 | |
Line -16777216 false 30 120 270 120 | |
leaf | |
false | |
0 | |
Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195 | |
Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195 | |
line | |
true | |
0 | |
Line -7500403 true 150 0 150 300 | |
line half | |
true | |
0 | |
Line -7500403 true 150 0 150 150 | |
pentagon | |
false | |
0 | |
Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120 | |
person | |
false | |
0 | |
Circle -7500403 true true 110 5 80 | |
Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90 | |
Rectangle -7500403 true true 127 79 172 94 | |
Polygon -7500403 true true 195 90 240 150 225 180 165 105 | |
Polygon -7500403 true true 105 90 60 150 75 180 135 105 | |
plant | |
false | |
0 | |
Rectangle -7500403 true true 135 90 165 300 | |
Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285 | |
Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285 | |
Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210 | |
Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135 | |
Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135 | |
Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60 | |
Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90 | |
sheep | |
false | |
15 | |
Circle -1 true true 203 65 88 | |
Circle -1 true true 70 65 162 | |
Circle -1 true true 150 105 120 | |
Polygon -7500403 true false 218 120 240 165 255 165 278 120 | |
Circle -7500403 true false 214 72 67 | |
Rectangle -1 true true 164 223 179 298 | |
Polygon -1 true true 45 285 30 285 30 240 15 195 45 210 | |
Circle -1 true true 3 83 150 | |
Rectangle -1 true true 65 221 80 296 | |
Polygon -1 true true 195 285 210 285 210 240 240 210 195 210 | |
Polygon -7500403 true false 276 85 285 105 302 99 294 83 | |
Polygon -7500403 true false 219 85 210 105 193 99 201 83 | |
square | |
false | |
0 | |
Rectangle -7500403 true true 30 30 270 270 | |
square 2 | |
false | |
0 | |
Rectangle -7500403 true true 30 30 270 270 | |
Rectangle -16777216 true false 60 60 240 240 | |
star | |
false | |
0 | |
Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108 | |
target | |
false | |
0 | |
Circle -7500403 true true 0 0 300 | |
Circle -16777216 true false 30 30 240 | |
Circle -7500403 true true 60 60 180 | |
Circle -16777216 true false 90 90 120 | |
Circle -7500403 true true 120 120 60 | |
tree | |
false | |
0 | |
Circle -7500403 true true 118 3 94 | |
Rectangle -6459832 true false 120 195 180 300 | |
Circle -7500403 true true 65 21 108 | |
Circle -7500403 true true 116 41 127 | |
Circle -7500403 true true 45 90 120 | |
Circle -7500403 true true 104 74 152 | |
triangle | |
false | |
0 | |
Polygon -7500403 true true 150 30 15 255 285 255 | |
triangle 2 | |
false | |
0 | |
Polygon -7500403 true true 150 30 15 255 285 255 | |
Polygon -16777216 true false 151 99 225 223 75 224 | |
truck | |
false | |
0 | |
Rectangle -7500403 true true 4 45 195 187 | |
Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194 | |
Rectangle -1 true false 195 60 195 105 | |
Polygon -16777216 true false 238 112 252 141 219 141 218 112 | |
Circle -16777216 true false 234 174 42 | |
Rectangle -7500403 true true 181 185 214 194 | |
Circle -16777216 true false 144 174 42 | |
Circle -16777216 true false 24 174 42 | |
Circle -7500403 false true 24 174 42 | |
Circle -7500403 false true 144 174 42 | |
Circle -7500403 false true 234 174 42 | |
turtle | |
true | |
0 | |
Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210 | |
Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105 | |
Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105 | |
Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87 | |
Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210 | |
Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99 | |
wheel | |
false | |
0 | |
Circle -7500403 true true 3 3 294 | |
Circle -16777216 true false 30 30 240 | |
Line -7500403 true 150 285 150 15 | |
Line -7500403 true 15 150 285 150 | |
Circle -7500403 true true 120 120 60 | |
Line -7500403 true 216 40 79 269 | |
Line -7500403 true 40 84 269 221 | |
Line -7500403 true 40 216 269 79 | |
Line -7500403 true 84 40 221 269 | |
wolf | |
false | |
0 | |
Polygon -16777216 true false 253 133 245 131 245 133 | |
Polygon -7500403 true true 2 194 13 197 30 191 38 193 38 205 20 226 20 257 27 265 38 266 40 260 31 253 31 230 60 206 68 198 75 209 66 228 65 243 82 261 84 268 100 267 103 261 77 239 79 231 100 207 98 196 119 201 143 202 160 195 166 210 172 213 173 238 167 251 160 248 154 265 169 264 178 247 186 240 198 260 200 271 217 271 219 262 207 258 195 230 192 198 210 184 227 164 242 144 259 145 284 151 277 141 293 140 299 134 297 127 273 119 270 105 | |
Polygon -7500403 true true -1 195 14 180 36 166 40 153 53 140 82 131 134 133 159 126 188 115 227 108 236 102 238 98 268 86 269 92 281 87 269 103 269 113 | |
x | |
false | |
0 | |
Polygon -7500403 true true 270 75 225 30 30 225 75 270 | |
Polygon -7500403 true true 30 75 75 30 270 225 225 270 | |
@#$#@#$#@ | |
NetLogo 5.0.4 | |
@#$#@#$#@ | |
@#$#@#$#@ | |
@#$#@#$#@ | |
@#$#@#$#@ | |
@#$#@#$#@ | |
default | |
0.0 | |
-0.2 0 1.0 0.0 | |
0.0 1 1.0 0.0 | |
0.2 0 1.0 0.0 | |
link direction | |
true | |
0 | |
Line -7500403 true 150 150 90 180 | |
Line -7500403 true 150 150 210 180 | |
@#$#@#$#@ | |
0 | |
@#$#@#$#@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment