I worked a little on Speedmasters example grid for section 2 of your tutorial.
-On clicking the VALIDATION CASE the resulting values will be updated automatically
Code: Select all
; Neural Network basics tutorial (section 2)
; tutorial by Gio
; interactive display grid by Speedmaster
; modified by nnnik to make things easier
; topic: https://autohotkey.com//boards/viewtopic.php?f=7&t=42420
class HiddenLayerNetwork {
__New( inputCount, neuronCount, outputCount ) {
This.inputCount := inputCount
This.neuronCount := neuronCount
This.outputCount := outputCount
This.hiddenLayer := []
This.outputLayer := []
This.resetNeurons()
}
train( dataSet, iterations, callBack := "" ) {
splitData := {}
for each, data in dataSet {
If ( data.MaxIndex() != This.inputCount + This.outputCount )
Throw exception("bad data count at index " each, -1)
i := [data.clone()]
i.1.removeAt(This.inputCount + 1, This.outputCount)
i.1.push(1)
itrans := TRANSPOSE_MATRIX(i)
o := [data.clone()]
o.1.removeAt(1, This.inputCount)
splitData.Push({input:i, output:o, trans:itrans})
}
hiddenLayer := TRANSPOSE_MATRIX( This.hiddenLayer )
outputLayer := TRANSPOSE_MATRIX( This.outputLayer )
Loop %iterations% {
for each, data in splitData {
HL := SIGMOID_OF_MATRIX(MULTIPLY_MATRICES(data.input, hiddenLayer))
HL.1.push(1)
output := SIGMOID_OF_MATRIX(MULTIPLY_MATRICES(HL, outputLayer))
outputError := DEDUCT_MATRICES(data.output, output)
outputDelta := MULTIPLY_MEMBER_BY_MEMBER(outputError, DERIVATIVE_OF_SIGMOID_OF_MATRIX(output))
outputAdjust := MULTIPLY_MATRICES(TRANSPOSE_MATRIX(HL), outputDelta)
HLError := MULTIPLY_MATRICES(outputError, This.outputLayer)
HL.1.Pop()
HLError.1.Pop()
HLDelta := MULTIPLY_MEMBER_BY_MEMBER(HLError, DERIVATIVE_OF_SIGMOID_OF_MATRIX(HL))
HLAdjust := MULTIPLY_MATRICES(data.trans, HLDelta)
hiddenLayer := ADD_MATRICES(hiddenLayer, HLAdjust)
outputLayer := ADD_MATRICES(outputLayer, outputAdjust)
totalError := averageArray(outputError.1)
}
} Until %callBack%(A_Index, totalError, iterations)
This.hiddenLayer := TRANSPOSE_MATRIX( hiddenLayer )
This.outputLayer := TRANSPOSE_MATRIX( outputLayer )
}
calculate( input ) {
input := [input.clone()]
input.1.push(1)
HL := SIGMOID_OF_MATRIX(MULTIPLY_MATRICES(input, TRANSPOSE_MATRIX( This.hiddenLayer )))
HL.1.push(1)
return SIGMOID_OF_MATRIX(MULTIPLY_MATRICES(HL, TRANSPOSE_MATRIX( This.outputLayer))).1
}
resetNeurons() {
Loop % This.neuronCount {
neuronNr := A_Index
Loop % This.inputCount + 1 { ;inputs + bias
Random, weight, -1.0, 1.0
This.hiddenLayer[neuronNr, A_Index] := weight
}
}
Loop % This.outputCount {
outputNr := A_Index
Loop % This.neuronCount + 1 {
Random, weight, -1.0, 1.0
This.outputLayer[outputNr, A_Index] := weight
}
}
}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The function below applies a sigmoid function to a single value and returns the results.
Sigmoid(x)
{
return 1 / (1 + exp(-1 * x))
}
; The function below applies the derivative of the sigmoid function to a single value and returns the results.
Derivative(x)
{
Return x * (1 - x)
}
; The function below applies the sigmoid function to all the members of a matrix and returns the results as a new matrix.
SIGMOID_OF_MATRIX(A)
{
RESULT_MATRIX := Object()
Loop % A.MaxIndex()
{
CURRENT_ROW := A_Index
Loop % A[1].MaxIndex()
{
CURRENT_COLUMN := A_Index
RESULT_MATRIX[CURRENT_ROW, CURRENT_COLUMN] := 1 / (1 + exp(-1 * A[CURRENT_ROW, CURRENT_COLUMN]))
}
}
Return RESULT_MATRIX
}
; The function below applies the derivative of the sigmoid function to all the members of a matrix and returns the results as a new matrix.
DERIVATIVE_OF_SIGMOID_OF_MATRIX(A)
{
resultingMatrix := {}
For rowNr, rows in A
For columnNr, value in rows
resultingMatrix[rowNr, columnNr] := value * (1 - value)
Return resultingMatrix
}
; The function below multiplies the individual members of two matrices with the same coordinates one by one (This is NOT equivalent to matrix multiplication).
MULTIPLY_MEMBER_BY_MEMBER(A,B)
{
If ((A.MaxIndex() != B.MaxIndex()) OR (A[1].MaxIndex() != B[1].MaxIndex()))
Throw exception("You cannot multiply matrices member by member unless both matrices are of the same size!", -1)
resultingMatrix := {}
For rowNr, rows in A
For columnNr, value in rows
resultingMatrix[rowNr, columnNr] := value * B[rowNr, columnNr]
Return resultingMatrix
}
; The function below transposes a matrix. I.E.: Member[2,1] becomes Member[1,2]. Matrix dimensions ARE affected unless it is a square matrix.
TRANSPOSE_MATRIX(A)
{
TRANSPOSED_MATRIX := Object()
Loop % A.MaxIndex()
{
CURRENT_ROW := A_Index
Loop % A[1].MaxIndex()
{
CURRENT_COLUMN := A_Index
TRANSPOSED_MATRIX[CURRENT_COLUMN, CURRENT_ROW] := A[CURRENT_ROW, CURRENT_COLUMN]
}
}
Return TRANSPOSED_MATRIX
}
; The function below adds a matrix to another.
ADD_MATRICES(A,B)
{
If ((A.MaxIndex() != B.MaxIndex()) OR (A[1].MaxIndex() != B[1].MaxIndex()))
Throw exception("You cannot add matrices member by member unless both matrices are of the same size!", -1)
RESULT_MATRIX := Object()
Loop % A.MaxIndex()
{
CURRENT_ROW := A_Index
Loop % A[1].MaxIndex()
{
CURRENT_COLUMN := A_Index
RESULT_MATRIX[CURRENT_ROW, CURRENT_COLUMN] := A[CURRENT_ROW,CURRENT_COLUMN] + B[CURRENT_ROW,CURRENT_COLUMN]
}
}
Return RESULT_MATRIX
}
; The function below deducts a matrix from another.
DEDUCT_MATRICES(A,B)
{
If ((A.MaxIndex() != B.MaxIndex()) OR (A[1].MaxIndex() != B[1].MaxIndex()))
Throw exception("You cannot subtract matrices member by member unless both matrices are of the same size!", -1)
RESULT_MATRIX := Object()
Loop % A.MaxIndex()
{
CURRENT_ROW := A_Index
Loop % A[1].MaxIndex()
{
CURRENT_COLUMN := A_Index
RESULT_MATRIX[CURRENT_ROW, CURRENT_COLUMN] := A[CURRENT_ROW,CURRENT_COLUMN] - B[CURRENT_ROW,CURRENT_COLUMN]
}
}
Return RESULT_MATRIX
}
; The function below multiplies two matrices according to matrix multiplication rules.
MULTIPLY_MATRICES(A,B)
{
If (A[1].MaxIndex() != B.MaxIndex())
Throw exception("Number of Columns in the first matrix must be equal to the number of rows in the second matrix.", -1)
RESULT_MATRIX := Object()
Loop % A.MaxIndex() ; Rows of A
{
CURRENT_ROW := A_Index
Loop % B[1].MaxIndex() ; Cols of B
{
CURRENT_COLUMN := A_Index
RESULT_MATRIX[CURRENT_ROW, CURRENT_COLUMN] := 0
Loop % A[1].MaxIndex()
{
RESULT_MATRIX[CURRENT_ROW, CURRENT_COLUMN] += A[CURRENT_ROW, A_Index] * B[A_Index, CURRENT_COLUMN]
}
}
}
Return RESULT_MATRIX
}
;returns the average of an array
averageArray(arr) {
for each, errorValue in arr
totalError += errorValue
return totalError / arr.length()
}
SetBatchLines, -1
gui, -dpiscale
gui, font, s12
gui, add, text, cblack x20 y20, (click a cell to change its value)
gui, add, text, cred x20 y60, Training rules
gui, add, text, cgreen x280 yp, Expected output
;create a display grid
network := new HiddenLayerNetwork(3, 8, 2)
rows:=8, cols:=5, cllw:=100, cllh:=30,
clln:="", cmj:=0
gpx:=20, gpy:=90, wsp:=-1, hsp:=-1,
r:=0, c:=0 , opt:="0x200 center BackGroundTrans border gclickcell "
While r++ < rows {
while c++ < cols{
gui 1: add, text, % opt " w"cllw " h"cllh " v" ((cmj) ? (clln c "_" r " Hwnd" clln c "_" r):(clln r "_" c " Hwnd" clln r "_" c)) ((c=1 && r=1) ? " x"gpx " y"gpy " section"
: (c!=1 && r=1) ? " x+"wsp " yp" : (c=1 && r!=1) ? " xs" " y+"hsp : " x+"wsp " yp"),
} c:=0
} r:=0, c:=0
gui, add, text, cblue x20 y+1, Validation case
gui, add, text, cpurple x310 yp, Final solution
gui, font, s12
gui, add, button, h30 x155 gcalculate, ANN calculation
gui, add, text, cblack x20 y+10 vProgr, Training Progress:`t`t`t`t
gui, add, text, cblack x20 y+10 vError, Total Error:`t`t`t`t`t`t`t
gui, show,, Neural Network (SECTION 2)
TRAINING_INPUTS := array([0, 0, 1], [0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1], [0, 0, 0]) ; We will also feed the net creator code with the values of the inputs in the training samples (all organized in a matrix too). MATRIX 7 x 3.
EXPECTED_OUTPUTS := Array([0, 1],[1, 1],[1, 1],[1, 0],[1, 0],[0, 1],[0, 0]) ; And we will also provide the net creator with the expected answers to our training samples so that the net creator can properly train the net.
VALIDATION_CASE := Array([1,1,0])
drawTRAINING(TRAINING_INPUTS)
drawEXPECTED(EXPECTED_OUTPUTS)
drawValidation(VALIDATION_CASE)
return
PREPARATION_STEPS:
calculate:
dataSet := TRAINING_INPUTS.clone()
for each, row in dataSet {
newRow := row.clone()
newRow.Push(EXPECTED_OUTPUTS[each]*)
dataSet[each] := newRow
}
network.train(dataSet, 10000, "displayProgress")
gosub, calculateValidation
drawValidation(VALIDATION_CASE)
return
calculateValidation:
input := VALIDATION_CASE.1.clone()
if (input.length() > 3)
input.removeAt(4, input.length() - 3)
output := network.calculate(input)
input.push(output*)
VALIDATION_CASE.1 := input
return
clickcell:
if (debug)
msgbox, % a_guicontrol
s:=strsplit(a_guicontrol, "_")
if !(s.1=rows) && !(s.2>=cols-1) {
TRAINING_INPUTS[s.1,s.2] := !TRAINING_INPUTS[s.1,s.2]
drawTRAINING(TRAINING_INPUTS)
}
if !(s.1=rows) && (s.2>=cols-1) {
EXPECTED_OUTPUTS[s.1,s.2-3] := !EXPECTED_OUTPUTS[s.1,s.2-3]
drawEXPECTED(EXPECTED_OUTPUTS)
}
if (s.1=rows) {
if (s.2=cols)
return
VALIDATION_CASE[1,s.2] := !VALIDATION_CASE[1,s.2]
if ( VALIDATION_CASE.1.4 != "" )
gosub, calculateValidation
} else {
VALIDATION_CASE.1.4 := ""
VALIDATION_CASE.1.5 := ""
}
drawVALIDATION(VALIDATION_CASE)
return
drawTRAINING(array){
for i, r in array
for j, c in r
drawchar( i "_" j , c, color:="red")
}
drawEXPECTED(array){
global cols
for i, r in array
for j, c in r
drawchar( i "_" 3 + j , c, color:="green")
}
drawValidation(array){
global rows
for i, r in array
for j, c in r
drawchar( rows "_" j , c, color:="blue")
}
drawchar(varname, chartodraw:="@", color:=""){
guicontrol,, %varname%, %chartodraw%
if color
colorcell(varname, color)
}
ColorCell(cell_to_paint, color:="red"){
GuiControl, +c%color% , %cell_to_paint%
GuiControl, MoveDraw, % cell_to_paint
}
CellFont(cell, params:="", fontname:="") {
Gui, Font, %params%, %fontname%
GuiControl, font , %cell%
guicontrol, movedraw, %cell%
}
displayProgress( iterationNr, totalError, maxIterations ) {
static lastIterationNr := -100000
if ( iterationNr < lastIterationNr ) {
lastIterationNr := iterationNr - 600
}
if ( iterationNr >= lastIterationNr + 600 ) {
GUIControl , , Progr, % "Training Progress: " . Format( "{:u}%", iterationNr / maxIterations * 100 )
GUIControl , , Error, % "Total Error: " . Format( "{:}%", totalError )
}
}
~f7::
debug:=!debug
return
guiclose:
esc::
exitapp
return