(* * LANGUAGE : ANS Forth * PROJECT : Forth Environments * DESCRIPTION : NN50.DLL interface * CATEGORY : Example * AUTHOR : Marcel Hendrix * LAST CHANGE : May 13, 2001, Marcel Hendrix *) NEEDS -miscutil NEEDS -dynlink NEEDS -fsl_util NEEDS -graphics REVISION -nn51 "ÄÄÄ NN51 interface Version 0.01 ÄÄÄ" PRIVATES DOC (* Visual Basic passes arrays as the OLE SAFEARRAY type. This type contains a header structure that contains the following information: unsigned short cDims; // Count of dimensions unsigned short fFeatures; // Flags unsigned long cbElements; // Size of an element of the array unsigned long cLocks; // Lock count void HUGEP* pvData; // Pointer to the data SAFEARRAYBOUND rgsabound[n]; // One bound for each dimension The SAFEARRAYBOUND type contains the following elements: unsigned long cElements; // Number of elements in this dimension long lLbound; // Lower bound The Visual C++ code can read the SAFEARRAY structure and get a pointer to the data (pvData), which contains contiguous data items, and read the SAFEARRAYBOUND structure to determine the number of elements passed. *) ENDDOC 0 VALUE nn50lib PRIVATE : UNLOAD-NN50 ( -- ) nn50lib 0= IF exit ENDIF nn50lib CLEAR nn50lib library-close ABORT" nn50.dll :: close failed" ; -- This assumes NN50.DLL is in the path : LOAD-NN50 ( -- ) nn50lib IF exit ENDIF S" nn50.dll" library-open ?DUP IF library-error CR TYPE ABORT" nn50.dll :: open failed" ENDIF TO nn50lib ;P : [NN50-LIB] ( c-addr1 u1 -- addr2 ) LOAD-NN50 nn50lib library-find ABORT" library-find: not in NN50" ; : NN50-LIB: ( "name" -- ) BL [NN50-LIB] ALITERAL ; IMMEDIATE 0 VALUE epoch 0e FVALUE RMSE 0 VALUE refresh 0 VALUE refreshrate 0 VALUE nMaxNeurons 0 VALUE nResetWeights 0 VALUE #epochs 0e FVALUE LRate -- Learning rate (0.1 to 10) 0e FVALUE nMomentum -- Neural network momentum (0.1 to 10) 1 2 DOUBLE MATRIX RELV{{ PRIVATE \ check the relevance of inputs (columns) #121 4 DOUBLE MATRIX PRED{{ PRIVATE \ holds copy of MUL{{ plus prediction parameters #120 4 DOUBLE MATRIX MUL{{ PRIVATE MUL{{ #120 4 }}FREAD \ last column is workspace for TRAIN 1 1 1 0 2 1 2 0 3 1 3 0 4 1 4 0 5 1 5 0 6 1 6 0 7 1 7 0 8 1 8 0 9 1 9 0 10 1 10 0 1 2 2 0 2 2 4 0 3 2 6 0 4 2 8 0 5 2 10 0 6 2 12 0 7 2 14 0 8 2 16 0 9 2 18 0 10 2 20 0 1 3 3 0 2 3 6 0 3 3 9 0 4 3 12 0 5 3 15 0 6 3 18 0 7 3 21 0 8 3 24 0 9 3 27 0 10 3 30 0 1 4 4 0 2 4 8 0 3 4 12 0 4 4 16 0 5 4 20 0 6 4 24 0 7 4 28 0 8 4 32 0 9 4 36 0 10 4 40 0 1 5 5 0 2 5 10 0 3 5 15 0 4 5 20 0 5 5 25 0 6 5 30 0 7 5 35 0 8 5 40 0 9 5 45 0 10 5 50 0 1 6 6 0 2 6 12 0 3 6 18 0 4 6 24 0 5 6 30 0 6 6 36 0 7 6 42 0 8 6 48 0 9 6 54 0 10 6 60 0 1 7 7 0 2 7 14 0 3 7 21 0 4 7 28 0 5 7 35 0 6 7 42 0 7 7 49 0 8 7 56 0 9 7 63 0 10 7 70 0 1 8 8 0 2 8 16 0 3 8 24 0 4 8 32 0 5 8 40 0 6 8 48 0 7 8 56 0 8 8 64 0 9 8 72 0 10 8 80 0 1 9 9 0 2 9 18 0 3 9 27 0 4 9 36 0 5 9 45 0 6 9 54 0 7 9 63 0 8 9 72 0 9 9 81 0 10 9 90 0 1 10 10 0 2 10 20 0 3 10 30 0 4 10 40 0 5 10 50 0 6 10 60 0 7 10 70 0 8 10 80 0 9 10 90 0 10 10 100 0 8.440500269 6.266413352 52.89166358 0 4.558798933 4.077588489 18.58890605 0 8.109820477 8.660170069 70.23242455 0 3.643514237 5.066587134 18.46018235 0 1.065509632 6.483361992 6.908084647 0 5.21139195 3.193615482 16.64318201 0 6.610917132 7.930427584 52.42739958 0 6.842574435 3.036799967 20.77952982 0 6.525749418 1.49830315 9.777550912 0 6.948511014 3.43993685 23.90243909 0 5.733074472 6.637656357 38.05417821 0 0.536355738 9.662970086 5.182789449 0 2.142488606 3.493871389 7.485579641 0 5.424176952 2.955117928 16.02908255 0 4.326438566 2.066430615 8.940285107 0 6.528338457 6.925260646 45.21044541 0 5.098077807 0.335407963 1.709935891 0 6.154871235 9.103673484 56.03193806 0 9.290558037 4.683752022 43.51466999 0 1.241873278 8.55073546 10.61892988 0 CREATE OLE_SAFEARRAY0 PRIVATE 1 C, 0 C, -- cDims $10 C, 0 C, -- Flags (do not resize or reallocate) 8 , -- cbElements 0 , -- lock count RELV{{ DADDR , -- pointer to data -- rgsabound[1] 2 , 1 , -- dimension 0: 2 cElements lLbound = 0? CREATE OLE_SAFEARRAY1 PRIVATE 2 C, 0 C, -- cDims $10 C, 0 C, -- Flags (do not resize or reallocate) 8 , -- cbElements 0 , -- lock count MUL{{ DADDR , -- pointer to data -- rgsabound[2] #120 , 1 , -- dimension 0: #120 cElements lLbound = 0? 4 , 1 , -- dimension 1: 4 cElements lLbound = 0? CREATE OLE_SAFEARRAY2 PRIVATE 2 C, 0 C, -- cDims $10 C, 0 C, -- Flags (do not resize or reallocate) 8 , -- cbElements 0 , -- lock count PRED{{ DADDR , -- pointer to data -- rgsabound[2] #121 , 1 , -- dimension 0: #121 cElements lLbound = 0? 4 , 1 , -- dimension 1: 4 cElements lLbound = 0? :NONAME ( epoch -- stop? ) DUP TO epoch #100000 > IF ( stop! ) -1 EXIT ENDIF 1 +TO refresh refresh refreshrate > IF CLEAR refresh GRAPHICS HOME ." Epoch: " epoch DEC. ." -- RMS error: " RMSE F.N1 8 SPACES TEXT epoch S>F RMSE blue DRAW-SCALED-LINE ENDIF epoch 1 = IF GCLEAR 0e TO PenX RMSE TO PenY 0 0 Xmax Ymax 0e 0e #epochs S>F RMSE SET-GWINDOW ENDIF 1 ( continue ) ; 1 PASCAL-CALLBACK CallBackEpoch :NONAME ( d_error -- ) FPOPD TO RMSE 1 ( ok ) ; 2 PASCAL-CALLBACK CallBackRMSError : INIT-EVERYTHING ( -- ) OLE_SAFEARRAY1 LOCAL 'array 1 TO nResetWeights 2 TO nMaxNeurons #2000 TO #epochs 100 TO refreshrate 9.5e TO Lrate ( 4.5) 0.5e TO nMomentum ( 0.5) CLEAR refresh CLEAR RMSE GRAPHICS >INVERSE< >BLINK< GCLEAR THICKPUT! TEXT 'OF 'array 'OF #epochs 'OF nResetWeights 'OF LRate 'OF nMomentum 'OF nMaxNeurons CallBackEpoch CallBackRMSError 8 NN50-LIB: TRAIN FOREIGN 1 = IF ." successful" ELSE ." unsuccessful" ENDIF >INVERSE< >BLINK< PUT! CR ." Result" MUL{{ }}print ; : PREDICT ( -- ) ( F: -- r ) OLE_SAFEARRAY2 LOCAL 'array MUL{{ ADIMS * DFLOATS >S PRED{{ DADDR S> MOVE ( copy ) 'OF 'array 'OF LRate 'OF nMomentum 'OF nMaxNeurons 4 NN50-LIB: PREDICT FFOREIGN ; : RELEVANCE ( #epochs nMaxNeurons -- ) ( F: Lrate nMomentum -- ) OLE_SAFEARRAY0 LOCAL 'array0 OLE_SAFEARRAY1 LOCAL 'array1 0 LOCAL epochs TO nMomentum TO Lrate TO nMaxNeurons TO epochs 'OF 'array1 'OF 'array0 'OF epochs 'OF LRate 'OF nMomentum 'OF nMaxNeurons 6 NN50-LIB: INPUTRELEVANCE FOREIGN -1 = ABORT" relevance :: failed" CR ." Relevance " RELV{{ }}print ; -- Simple test : N*N ( F: x1 x2 -- ) CR FOVER F.N1 ." x " FDUP F.N1 ." = " F2DUP F* FDUP F.N1 ." ? NN50 says: " 0e PRED{{ #120 3 }} DF! PRED{{ #120 2 }} DF! PRED{{ #120 1 }} DF! PRED{{ #120 0 }} DF! PREDICT F.N1 ; CREATE $buff PRIVATE 0 , #256 CHARS ALLOT -- OLE BSTR. This IS really necessary! : >BSTR ( "text" -- c-addr ) 0 $FF AND DUP $buff ! >S $buff CELL+ S MOVE $buff CELL+ S> + C0! $buff CELL+ ;P \ Works, but is very slow. File is encrypted? \ Usage: SAVE-NN c:/dfwforth/examples/nn/nn51.sav : SAVE-NN ( "name" -- ) >BSTR 1 NN50-LIB: SAVENETWORK FOREIGN -1 = ABORT" save-nn :: failed" ; \ Reads a pre-trained Neural Network into memory. Again, very slow. \ If the loaded network is much larger than the pre-allocated array, what happens? \ How to know nMaxNeurons etc.? The answer is: "Don't do that." \ Usage: 2 9.5e 0.5e LOAD-NN c:/dfwforth/examples/nn/nn51.sav : LOAD-NN ( "name" | nMaxNeurons -- ) ( F: Lrate nMomentum -- ) OLE_SAFEARRAY1 LOCAL 'array TO nMaxNeurons TO nMomentum ( 0.5) TO Lrate ( 4.5) 'OF 'array >BSTR 'OF LRate 'OF nMomentum 'OF nMaxNeurons 5 NN50-LIB: LOADNETWORK FOREIGN -1 = ABORT" load-nn :: failed" ; :ABOUT CR ." Try: INIT-EVERYTHING" ; .ABOUT -nn51 CR DEPRIVE (* End of Source *)