From 2ee9123f08ac7007c52a197775b141ee1d8290aa Mon Sep 17 00:00:00 2001 From: IgorA Date: Sat, 28 May 2022 12:21:03 +0000 Subject: [PATCH] update library 'nnp.obj' git-svn-id: svn://kolibrios.org@9821 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/libraries/nnp/about.htm | 60 +- programs/develop/libraries/nnp/but01.png | Bin 0 -> 381 bytes programs/develop/libraries/nnp/but04.png | Bin 0 -> 654 bytes programs/develop/libraries/nnp/but05.png | Bin 0 -> 458 bytes .../develop/libraries/nnp/examples/build.bat | 6 + .../libraries/nnp/examples/nnp_points.asm | 747 ++++++++++++++++++ .../libraries/nnp/examples/toolbar.png | Bin 0 -> 2007 bytes programs/develop/libraries/nnp/img01.png | Bin 0 -> 42722 bytes programs/develop/libraries/nnp/nnp.asm | 357 +++++---- 9 files changed, 1008 insertions(+), 162 deletions(-) create mode 100644 programs/develop/libraries/nnp/but01.png create mode 100644 programs/develop/libraries/nnp/but04.png create mode 100644 programs/develop/libraries/nnp/but05.png create mode 100644 programs/develop/libraries/nnp/examples/build.bat create mode 100644 programs/develop/libraries/nnp/examples/nnp_points.asm create mode 100644 programs/develop/libraries/nnp/examples/toolbar.png create mode 100644 programs/develop/libraries/nnp/img01.png diff --git a/programs/develop/libraries/nnp/about.htm b/programs/develop/libraries/nnp/about.htm index 624d97aa26..2c00f71b0a 100644 --- a/programs/develop/libraries/nnp/about.htm +++ b/programs/develop/libraries/nnp/about.htm @@ -53,6 +53,7 @@ table { font-size: 15px; } @@ -69,7 +71,7 @@ table { font-size: 15px; }

Документация к библиотеке nnp.obj, для ОС Колибри. Эта библиотека создана для работы с нейросетями (neural network perceptron). Видео по нейросетям: 1, 2. Исходный код (язык java), на основе которого делалсь библиотека: 3.

-

Последнее обновление библиотеки 01.03.22.

+

Последнее обновление библиотеки 28.05.22.

Функции

@@ -96,40 +98,45 @@ ends nnlopt dd 2,8,8,8,8,8,3 ... stdcall [NNP_Create], nnp_0, 0.01, 0, 0, nnlopt, NNLOPT_LEN -

где nnp_0 - структура буфера.

+

где nnp_0 - структура нейросети.

0.01 - скорость обучения.

0 - адрес функции активации, если 0 то берется стандартная функция внутри библиотеки.

0 - адрес функции свёртки, если 0 то берется стандартная функция внутри библиотеки.

nnlopt - массив с числом нейронов на каждом слое.

NNLOPT_LEN - длинна массива nnlopt.

+

NNP_Reset

+

Сброс параметров нейросети. Для каждого слоя базисный вектор и веса заполняются случайными числами от -1 до 1. Такие же действия происходят в конструкторе NNP_Create.

+
stdcall [NNP_Reset], nnp_0
+

где nnp_0 - структура нейросети.

+

NNP_FeedForward

Функция расчета значений выходных нейронов. На вход подаються значения входных нейронов. На выходе возвращается указатель на слой выходных нейронов.

n_input dq ?,?,?
 ...
 stdcall [NNP_FeedForward], nnp_0,n_input
-

где nnp_0 - структура буфера, n_input - указатель на данные входных нейронов.

+

где nnp_0 - структура нейросети, n_input - указатель на данные входных нейронов.

NNP_BackPropagation

Функция для обучения сети. Пример:

n_targ dq ?,?,?
 ...
 stdcall [NNP_BackPropagation], nnp_0, n_targ
-

где nnp_0 - структура буфера, n_targ - указатель на данные для обучения сети.

+

где nnp_0 - структура нейросети, n_targ - указатель на данные для обучения сети.

NNP_GetMemData

Берет данные нейросети и записывает их в указанное место в памяти. Пример:

f_data dd ?
 ...
 stdcall [NNP_GetMemData], nnp_0, NNP_FF_JSON, [f_data]
-

где nnp_0 - структура буфера, f_data - указатель на данные для записи параметров сети.

+

где nnp_0 - структура нейросети, f_data - указатель на данные для записи параметров сети.

NNP_SetMemData

-

Берет данные из указанного места памяти и записывает их в нейросеть. Пример:

+

Берет данные из указанного места памяти и записывает их в нейросеть. В случае успеха в регистре eax возвращается 0, иначе указатель на строку с текстом ошибки. Пример:

f_data dd ?
 ...
 stdcall [NNP_SetMemData], nnp_0, NNP_FF_JSON, [f_data]
-

где nnp_0 - структура буфера, f_data - указатель на данные с параметрами сети.

+

где nnp_0 - структура нейросети, f_data - указатель на данные с параметрами сети.

NNP_Destroy

Освобождает память занятую нейросетью.

@@ -145,24 +152,31 @@ stdcall [NNP_SetMemData], nnp_0, NNP_FF_JSON, [f_data]
align 4
 import_nnp_lib:
 	dd sz_lib_init
-	NNP_Create dd sz_nnp_create
-	NNP_FeedForward dd sz_nnp_FeedForward
-	NNP_BackPropagation dd sz_nnp_BackPropagation
-	NNP_GetMemData dd sz_nnp_GetMemData
-	NNP_SetMemData dd sz_nnp_SetMemData
-	NNP_Destroy dd sz_nnp_Destroy
-	dd 0,0
-	sz_lib_init db 'lib_init',0
-	sz_nnp_create db 'NNP_Create',0
-	sz_nnp_FeedForward db 'NNP_FeedForward',0
-	sz_nnp_BackPropagation db 'NNP_BackPropagation',0
-	sz_nnp_GetMemData db 'NNP_GetMemData',0
-	sz_nnp_SetMemData db 'NNP_SetMemData',0
-	sz_nnp_Destroy db 'NNP_Destroy',0
+	NNP_Create      dd sz_create
+	NNP_Reset       dd sz_reset
+	NNP_FeedForward dd sz_feedforward
+	NNP_BackPropagation dd sz_backpropagation
+	NNP_GetMemData  dd sz_getmemdata
+	NNP_SetMemData  dd sz_setmemdata
+	NNP_Destroy     dd sz_destroy
+dd 0,0
+	sz_lib_init     db 'lib_init',0
+	sz_create       db 'NNP_Create',0
+	sz_reset        db 'NNP_Reset',0
+	sz_feedforward  db 'NNP_FeedForward',0
+	sz_backpropagation db 'NNP_BackPropagation',0
+	sz_getmemdata   db 'NNP_GetMemData',0
+	sz_setmemdata   db 'NNP_SetMemData',0
+	sz_destroy      db 'NNP_Destroy',0
 
-

История

-

01.03.22 - самая первая версия библиотеки (примеры использования возможно будут позже).

+

Пример

+

В данном примере создаются 8 объектов (точек с координатами x, y), каждый из которых имеет тип 0 (синие) или 1 (зеленые). При нажатии кнопки происходит тренировка нейросети. В процессе тренировки нейросеть учится определять какой цвет должен соответствовать заданным координатам x, y. Тренировать сеть можно много раз, число циклов тренировки показано в заголовке окна. Кнопка переставляет точки случайным образом. Кнопка сбрасывает состояние нейросети.

+

+

Рис. 1. Пример использования библиотеки

+

История

+

01.03.22 - самая первая версия библиотеки.

+

28.05.22 - пример использования библиотеки, новая функция NNP_Reset, обновление функции NNP_SetMemData.

\ No newline at end of file diff --git a/programs/develop/libraries/nnp/but01.png b/programs/develop/libraries/nnp/but01.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2a9552d7eed3b95adbdb0d55b7c1216c17477f GIT binary patch literal 381 zcmV-@0fPRCP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940TM|>K~y+Tos!LN zfPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940wYO8K~y+Tb&^j= z6j2<hSBugG%HvLL_ zxl%N?)o$P7@d`YTZHx(FBS27@jvr|}dgatL#~_&C=ZN~;BE?<4-5$|nmu(A!N+7F* zEI=Uu(1O6pX7Hoh@Z0%lv%eWrk_EY>o>X-e0Sp1!DFxU@hotcB^Sy35+aa-_ctvjk z6*C1>Nhtg44~$=b|E_mZ>6@{$e0yE6I-4P;zNgHbNg(D3F9*+DI@ay3aNLPdXSaNL zLXT2v+p9q-KF5zWxprP6?pNZ=AbT)f$wCki9QpC3T*ngh4i+TUuV8 zj4QQyZ`bjQJABf*BMrp*;|np?4(a(cv$6(Z6>n|W8{TucBh)F?OO+&MsOH{SU)O^R ouJ|8+8(2R-e)Gr`|57gh0`!r}P#tCDRR91007*qoM6N<$f&!o=IRF3v literal 0 HcmV?d00001 diff --git a/programs/develop/libraries/nnp/but05.png b/programs/develop/libraries/nnp/but05.png new file mode 100644 index 0000000000000000000000000000000000000000..27ec66d32254bedaf837a13bbec1a9615a661131 GIT binary patch literal 458 zcmV;*0X6=KP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ940bfZ(K~y+TWBmXB zKLZ29k)zkE>X*EJ{Rzm%1frsRZH+ND)|wy=P{XHB-+cmGzJLGq_wPTf2q@+0*924s zRLla@^X}b87iR-@cGmfaA3l8Z9b^m=kQd=hw3T;vGXg5(<>g?43NtW#`}KS8wYPU( zeM3V)L7)^=5d#B41Cf9N4NOcpH6u%bJPiSytjs+T+FySDf%0L1hn)o|1?3>y01UF{ zFW<8>{8bg_{`vJA5CIuLE>I8>R}g^E@ag-ntZzI_IxRYTF5PiGA)WAObRgT%aIO3aSX%1`bwcV+}DQRdJwc_69OQ z5g@}>Uxu5D6(|K(0yZ6z_<(7P$izot@@8NF0KvlCcNU4WdjJ3c07*qoM6N<$f*`G~ A)c^nh literal 0 HcmV?d00001 diff --git a/programs/develop/libraries/nnp/examples/build.bat b/programs/develop/libraries/nnp/examples/build.bat new file mode 100644 index 0000000000..b93ada8388 --- /dev/null +++ b/programs/develop/libraries/nnp/examples/build.bat @@ -0,0 +1,6 @@ +if not exist bin mkdir bin +@fasm.exe ..\nnp.asm bin\nnp.obj + +@fasm.exe -m 16384 nnp_points.asm bin\nnp_points.kex +@kpack nnp_points.kex +pause \ No newline at end of file diff --git a/programs/develop/libraries/nnp/examples/nnp_points.asm b/programs/develop/libraries/nnp/examples/nnp_points.asm new file mode 100644 index 0000000000..2a8edac0a3 --- /dev/null +++ b/programs/develop/libraries/nnp/examples/nnp_points.asm @@ -0,0 +1,747 @@ +use32 + org 0 + db 'MENUET01' ;Ё¤Ґ­вЁд. ЁбЇ®«­пҐ¬®Ј® д ©«  ўбҐЈ¤  8 Ў ©в + dd 1, start, i_end, mem, stacktop, 0, sys_path + +include '../../../../macros.inc' +include '../../../../proc32.inc' +include '../../../../KOSfuncs.inc' +include '../../../../load_img.inc' +include '../../../../load_lib.mac' +include '../../../../develop/libraries/box_lib/trunk/box_lib.mac' + +@use_library mem.Alloc,mem.Free,mem.ReAlloc,dll.Load +caption db 'NNP example 28.05.22',0 ;Ї®¤ЇЁбм ®Є­  + +run_file_70 FileInfoBlock + +IMAGE_TOOLBAR_ICON_SIZE equ 16*16*3 +image_data_toolbar dd 0 + +memory_file_size dd 512*1024 ;а §¬Ґа Ї ¬пвЁ ¤«п ®вЄалвЁп д ©«®ў (ў ­ з «Ґ 512 Kb, ­® ¬®¦Ґв 㢥«ЁзЁў вбп ЇаЁ ­Ґ®Ўе®¤Ё¬®бвЁ) + +NNP_FF_BIN equ 0x6e6962 +NNP_FF_JSON equ 0x6e6f736a + +struct NeuralNetwork + learningRate dq ? ;+ 0 бЄ®а®бвм ®Ўг祭Ёп + layers dd ? ;+ 8 [] б«®Ё + layers_length dd ? ;+12 зЁб«® б«®Ґў + activation dd ? ;+16 гЄ § вҐ«м ­  дг­ЄжЁо  ЄвЁў жЁЁ + derivative dd ? ;+20 гЄ § вҐ«м ­  дг­ЄжЁо + errors dd ? ;+24 ¬ ббЁў ¤«п ўлзЁб«Ґ­Ё© + errorsNext dd ? ;+28 + gradients dd ? ;+32 + deltas dd ? ;+36 +ends + +struct Point + x dq ? ;double + y dq ? + t dd ? ;long +ends + +align 4 +NNLOPT_LEN equ 4 +nnlopt dd 2,3,3,2 +_nn NeuralNetwork +lea_rate dq 0.01 + +POINTS_COUNT equ 8 ;зЁб«® в®зҐЄ +_p rb sizeof.Point*POINTS_COUNT + +_cycles_st dd 0 +_r_op rb 128 +txt_error db '"Error open: ',39,'%s',39,'" -tE',0 +txt_cycles db 'Cycles = %i000',0 + +;Њ Єа®б ¤«п Ї а ¬Ґва®ў вЁЇ  double (8 Ў ©в) +macro glpush double_v { + push dword[double_v+4] + push dword[double_v] +} + +align 8 +proc __ftol + sub esp,12 + wait + fstcw word[esp+8] + wait + mov al,[esp+9] + or byte[esp+9],0x0c + fldcw word[esp+8] + fistp qword[esp] + mov [esp+9],al + fldcw word[esp+8] + mov eax,[esp] + mov edx,[esp+4] + add esp,12 + ret +endp + +align 16 +Math_random: + imul eax,dword[_rand_x],22695477 + inc eax + push ecx + mov dword[_rand_x],eax + and eax,65535 + mov dword[esp],eax + fild dword[esp] + fmul dword[@f] + pop edx + ret +align 4 +@@: + db 0,0,128,55 ;dd 1.0/65536.0 +_rand_x dd 0 + + +align 8 +start: + load_libraries l_libs_start,l_libs_end + ;Їа®ўҐаЄ  ­  бЄ®«мЄ® г¤ з­® § Јг§Ё« бм ЎЁЎ«Ё®вҐЄ  + mov ebp,lib_0 + cmp dword [ebp+ll_struc_size-4],0 + jz @f + mcall SF_TERMINATE_PROCESS + @@: + mcall SF_STYLE_SETTINGS,SSF_GET_COLORS,sc,sizeof.system_colors + mcall SF_SET_EVENTS_MASK,0xC0000027 + stdcall [OpenDialog_Init],OpenDialog_data ;Ї®¤Ј®в®ўЄ  ¤Ё «®Ј  + stdcall [buf2d_create], buf_0 ;ᮧ¤ ­ЁҐ ЎгдҐа  + + include_image_file 'toolbar.png', image_data_toolbar + + stdcall mem.Alloc,[memory_file_size] + mov dword[open_file],eax + + push NNLOPT_LEN + push nnlopt + push 0 + push 0 + glpush lea_rate + stdcall [NNP_Create], _nn + call but_update + +align 8 +red_win: + call draw_window + +align 16 +still: + mcall SF_WAIT_EVENT + + cmp al,1 + jz red_win + cmp al,2 + jz key + cmp al,3 + jz button + cmp al,6 ;¬лим + jne @f + jmp mouse + @@: + jmp still + +align 8 +draw_window: +pushad + mcall SF_REDRAW,SSF_BEGIN_DRAW + + ; *** аЁб®ў ­ЁҐ Ј« ў­®Ј® ®Є­  (ўлЇ®«­пҐвбп 1 а § ЇаЁ § ЇгбЄҐ) *** + mov edx,[sc.work] + or edx,(3 shl 24)+0x30000000 + mov edi,caption + mcall SF_CREATE_WINDOW, (20 shl 16)+590, (20 shl 16)+540 + + ; *** ᮧ¤ ­ЁҐ Є­®Ї®Є ­  Ї ­Ґ«м *** + mov esi,[sc.work_button] + mcall SF_DEFINE_BUTTON, (5 shl 16)+20, (5 shl 16)+20, 3 + + add ebx,(25 shl 16) + mov edx,4 + int 0x40 + + add ebx,(25 shl 16) + mov edx,5 + int 0x40 + + add ebx,(30 shl 16) + mov edx,6 + int 0x40 + + add ebx,(25 shl 16) + mov edx,7 + int 0x40 + + ; *** аЁб®ў ­ЁҐ ЁЄ®­®Є ­  Є­®ЇЄ е *** + mcall SF_PUT_IMAGE, [image_data_toolbar], (16 shl 16)+16, (7 shl 16)+7 ;icon new + + add ebx,IMAGE_TOOLBAR_ICON_SIZE + add edx,(25 shl 16) ;icon open + int 0x40 + add ebx,IMAGE_TOOLBAR_ICON_SIZE + add edx,(25 shl 16) ;icon save + int 0x40 + + add ebx,IMAGE_TOOLBAR_ICON_SIZE + add edx,(30 shl 16) ;icon update points + int 0x40 + add ebx,IMAGE_TOOLBAR_ICON_SIZE + add edx,(25 shl 16) ;icon calculate + int 0x40 + + call PointsDraw + ; *** аЁб®ў ­ЁҐ ЎгдҐа  *** + stdcall [buf2d_draw], buf_0 + + mcall SF_REDRAW,SSF_END_DRAW +popad + ret + +align 8 +key: + mcall SF_GET_KEY + jmp still + +align 8 +mouse: + + jmp still + +align 8 +button: + mcall SF_GET_BUTTON + cmp ah,3 + jne @f + call but_new_file + jmp red_win + @@: + cmp ah,4 + jne @f + call but_open_file + jmp red_win + @@: + cmp ah,5 + jne @f + call but_save_file + jmp red_win + @@: + cmp ah,6 + jne @f + call but_update + jmp red_win + @@: + cmp ah,7 + jne @f + call but_calc + jmp red_win + @@: + cmp ah,1 + jne still +.exit: + stdcall [buf2d_delete],buf_0 + stdcall mem.Free,[image_data_toolbar] + stdcall mem.Free,[open_file] + stdcall [NNP_Destroy], _nn + mcall SF_TERMINATE_PROCESS + +align 8 +but_calc: + push esi edi ebp + add esp,-32 + mov ebp,_p + xor edi,edi ;i=0 +.cycle_0: ;for(i=0;i<50000;i++) + call Math_random + fimul dword[.172] + call __ftol + mov esi,eax ;k=(long)(Math_random()*POINTS_COUNT) + imul esi,sizeof.Point + fld qword[ebp+esi+Point.x] + fsub dword[f_0_5] + fstp qword[esp] ;v[0]=p[k].x-.5 + fld qword[ebp+esi+Point.y] + fsub dword[f_0_5] + fstp qword[esp+8] ;v[1]=p[k].y-.5 + stdcall [NNP_FeedForward], _nn,esp ;r=NNP_FeedForward(&nn,v) + + xor eax,eax + mov dword[esp+16],eax + mov dword[esp+20],eax ;t[0]=0.0 + mov dword[esp+24],eax + mov dword[esp+28],eax ;t[1]=0.0 + cmp dword[ebp+esi+Point.t],eax + je .173 + mov dword[esp+16],eax + mov dword[esp+20],1072693248 ;if(p[k].t) t[0]=1.0 + jmp .174 +.173: + mov dword[esp+24],eax + mov dword[esp+28],1072693248 ;else t[1]=1.0 +.174: + lea edx,dword[esp+16] + stdcall [NNP_BackPropagation], _nn,edx ;NNP_BackPropagation(&nn,t) + inc edi ;i++ + cmp edi,50000 + jl .cycle_0 + add dword[_cycles_st],50 + stdcall [sprintf], _r_op,txt_cycles,[_cycles_st] + add esp,12 + call NNP_DrawInBuf + call PointsDraw +; SaveNN("/tmp0/1/nnp_end.txt") + ;push s@+835 + ;call @@SaveNN$qpxc + ;pop ecx + mcall SF_SET_CAPTION,1,_r_op + add esp,32 + pop ebp edi esi + ret +align 4 +.172: + dd POINTS_COUNT + +align 8 +but_new_file: + mov dword[_cycles_st],0 + stdcall [NNP_Reset], _nn + call NNP_DrawInBuf + call PointsDraw + ret + +align 8 +but_update: + mov dword[_cycles_st],0 + call PointsInit + call NNP_DrawInBuf + call PointsDraw + ret + +align 8 +PointsInit: + push ebx esi + xor esi,esi ;i=0 + mov ebx,_p +.cycle_0: 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

b8rk0zhszplw2bT5wZ8n4fYMcc*@`q+L+Hh~Rk; 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 hJi-j`CwJ}Ix{+}&Z%g|%ilayers_length; i++) + xor esi,esi ;j=0 + mov eax,edi + imul eax,sizeof.Layer + mov edx,[ebp+8] + add eax,[edx+NeuralNetwork.layers] + mov edx,[eax+Layer.n_size] + mov [ebp-4],edx + mov edx,[eax+Layer.c_size] + mov [ebp-8],edx + jmp .2 +.cycle_1: ;for (j=0; j < o->layers[i].c_size; j++) + call Math_random + fmul dword[f_2_0] + fsub dword[f_1_0] + mov eax,[ebp+8] ;o + mov ecx,edi + imul ecx,sizeof.Layer + add ecx,[eax+NeuralNetwork.layers] + mov ecx,[ecx+Layer.biases] + fstp qword[ecx+8*esi] + xor ebx,ebx ;k=0 + cmp ebx,[ebp-4] + jae .1 +@@: ;for (k=0; k < o->layers[i].n_size; k++) + call Math_random + fmul dword[f_2_0] + fsub dword[f_1_0] + mov eax,edi + imul eax,sizeof.Layer + mov edx,[ebp+8] ;o + add eax,[edx+NeuralNetwork.layers] + mov eax,[eax+Layer.weights] + mov edx,[eax+4*esi] ;edx = &o->layers[i].weights[j] + fstp qword[edx+8*ebx] ;o->layers[i].weights[j][k] = Math_random()*2.0-1.0; + inc ebx ;k++ + cmp ebx,[ebp-4] + jb @b +.1: + inc esi ;j++ +.2: + cmp esi,[ebp-8] + jb .cycle_1 + inc edi ;i++ +.3: + mov ecx,[ebp+8] ;o + cmp edi,[ecx+NeuralNetwork.layers_length] + jb .cycle_0 + pop edi esi ebx + mov esp,ebp + pop ebp + ret 4 + +;расчет входных и выходных нейронов ;+ 8 NeuralNetwork* o ;+12 double* inputs align 16 @@ -621,7 +689,7 @@ NNP_GetMemData: mov ebp,esp add esp,-12 push ebx esi edi - cmp dword[ebp+12],1852797802 + cmp dword[ebp+12],NNP_FF_JSON jne .end_f mov esi,[ebp+16] mov byte[esi],0 @@ -665,14 +733,15 @@ align 4 add esi,eax stdcall [_strcat], esi,txt_nl_t_Qc_sizeQ add esp,8 - lea ebx,[edi+4*edi] + mov ebx,edi + imul ebx,sizeof.Layer push 1 push 0 - mov eax,[ebp+8] - mov edx,[eax+8] + mov edx,[ebp+8] + mov edx,[edx+NeuralNetwork.layers] xor eax,eax add esp,-8 - mov ecx,[edx+4*ebx] + mov ecx,[edx+ebx+Layer.c_size] mov dword[ebp-12],ecx mov dword[ebp-8],eax fild qword[ebp-12] @@ -685,11 +754,11 @@ align 4 add esp,8 push 1 push 0 - mov edx,[ebp+8] - mov ecx,[edx+8] + mov ecx,[ebp+8] + mov ecx,[ecx+NeuralNetwork.layers] xor edx,edx add esp,-8 - mov eax,[ecx+4*ebx+4] + mov eax,[ecx+ebx+Layer.n_size] mov dword[ebp-12],eax mov dword[ebp-8],edx fild qword[ebp-12] @@ -713,10 +782,11 @@ align 4 .235: push 1 push PRECISION - lea eax,[edi+4*edi] + mov eax,edi + imul eax,sizeof.Layer mov edx,[ebp+8] - mov ecx,[edx+8] - mov eax,[ecx+4*eax+8] + mov ecx,[edx+NeuralNetwork.layers] + mov eax,[ecx+eax+Layer.neurons] push dword[eax+8*ebx+4] push dword[eax+8*ebx] call @@DoubleToStr$qduso @@ -746,10 +816,11 @@ align 4 .239: push 1 push PRECISION - lea eax,[edi+4*edi] + mov eax,edi + imul eax,sizeof.Layer mov edx,[ebp+8] - mov ecx,[edx+8] - mov eax,[ecx+4*eax+12] + add eax,[edx+NeuralNetwork.layers] + mov eax,[eax+Layer.biases] push dword[eax+8*ebx+4] push dword[eax+8*ebx] call @@DoubleToStr$qduso @@ -758,17 +829,19 @@ align 4 add esp,8 inc ebx .238: - lea ecx,[edi+4*edi] + mov ecx,edi + imul ecx,sizeof.Layer mov eax,[ebp+8] - mov edx,[eax+8] - cmp ebx,[edx+4*ecx] + add ecx,[eax+NeuralNetwork.layers] + cmp ebx,[ecx+Layer.c_size] jb .cycle_2 stdcall [_strcat], esi,txt_sqbr_zap_t_QweightsQ add esp,8 mov eax,[ebp+8] - lea ecx,[edi+4*edi] - mov edx,[eax+8] - cmp dword[edx+4*ecx+4],0 + mov ecx,edi + imul ecx,sizeof.Layer + add ecx,[eax+NeuralNetwork.layers] + cmp dword[ecx+Layer.n_size],0 je .241 xor ebx,ebx jmp .243 @@ -791,10 +864,11 @@ align 4 .247: push 1 push PRECISION - lea edx,[edi+4*edi] - mov ecx,[ebp+8] - mov eax,[ecx+8] - mov edx,[eax+4*edx+16] + mov edx,edi + imul edx,sizeof.Layer + mov eax,[ebp+8] + add edx,[eax+NeuralNetwork.layers] + mov edx,[edx+Layer.weights] mov ecx,[edx+4*ebx] mov eax,[ebp-4] push dword[ecx+8*eax+4] @@ -811,20 +885,22 @@ align 4 add esp,8 inc dword[ebp-4] .246: - lea ecx,[edi+4*edi] + mov ecx,edi + imul ecx,sizeof.Layer mov eax,[ebp+8] - mov edx,[eax+8] - mov ecx,[edx+4*ecx+4] + add ecx,[eax+NeuralNetwork.layers] + mov ecx,[ecx+Layer.n_size] cmp ecx,[ebp-4] ja .245 stdcall [_strcat], esi,txt_sqbr add esp,8 inc ebx .243: - lea eax,[edi+4*edi] - mov edx,[ebp+8] - mov ecx,[edx+8] - cmp ebx,[ecx+4*eax] + mov eax,edi + imul eax,sizeof.Layer + mov ecx,[ebp+8] + add eax,[ecx+NeuralNetwork.layers] + cmp ebx,[eax+Layer.c_size] jb .242 .241: stdcall [_strcat], esi,txt_sqbr_fbr_zap @@ -852,27 +928,26 @@ NNP_GetMaxLLen: cmp dword[ebx+NeuralNetwork.layers_length],1 jge .1 xor eax,eax - jmp .5 + jmp .end_f .1: mov edx,[ebx+NeuralNetwork.layers] - mov eax,[ebx+NeuralNetwork.layers] - add eax,sizeof.Layer + lea eax,[edx+sizeof.Layer] mov ecx,[edx] - mov edx,1 - jmp .4 -.2: + mov edx,1 ;i=1 + jmp .3 +.cycle_0: ;for (i=1; i < o->layers_length; i++) mov esi,[eax] cmp esi,ecx - jbe .3 + jbe .2 mov ecx,esi -.3: +.2: inc edx add eax,sizeof.Layer -.4: +.3: cmp edx,[ebx+NeuralNetwork.layers_length] - jl .2 + jl .cycle_0 mov eax,ecx -.5: +.end_f: pop esi ebx ebp ret 4 @@ -934,18 +1009,18 @@ NNP_SetMemData: mov edx,[eax+12] cmp edx,[ebp-4] je .203 - mov eax,4 + mov eax,txt_err_layers_neq jmp .193 .203: - xor edi,edi + xor edi,edi ;i=0 jmp .205 -.204: +.204: ;for(i=0;ilayers_length;i++) stdcall @@strstr$qpxct1, esi,txt_c_size add esp,8 mov esi,eax test esi,esi jne .206 - mov eax,5 + mov eax,txt_err_c_size jmp .193 .206: stdcall @@strchr$qpxci, esi,':' @@ -997,46 +1072,39 @@ NNP_SetMemData: .211: mov byte[esi],0 inc esi - push ebx - call @@StrToInt$qpc + stdcall @@StrToInt$qpc,ebx pop ecx mov dword[ebp-8],eax - lea eax,[edi+4*edi] + mov eax,edi + imul eax,sizeof.Layer mov edx,[ebp+8] - mov ecx,[edx+8] - mov edx,[ecx+4*eax] + add eax,[edx+NeuralNetwork.layers] + mov edx,[eax+Layer.c_size] cmp edx,[ebp-4] jne .213 - mov ecx,[ebp+8] - mov edx,[ecx+8] - mov eax,[edx+4*eax+4] - cmp eax,[ebp-8] + mov edx,[eax+Layer.n_size] + cmp edx,[ebp-8] je .214 .213: mov ecx,[ebp+8] - push ecx - call NNP_GetMaxLLen + stdcall NNP_GetMaxLLen,ecx mov ecx,edi + imul ecx,sizeof.Layer mov ebx,eax - shl ecx,2 mov eax,[ebp+8] - mov edx,[eax+8] - lea ecx,[ecx+4*ecx] + mov edx,[eax+NeuralNetwork.layers] add edx,ecx - push edx - call Layer_Destroy + stdcall Layer_Destroy,edx mov eax,[ebp-8] push eax mov edx,[ebp-4] push edx mov edx,edi - shl edx,2 + imul edx,sizeof.Layer mov ecx,[ebp+8] - mov eax,[ecx+8] - lea edx,[edx+4*edx] + mov eax,[ecx+NeuralNetwork.layers] add eax,edx - push eax - call Layer_Create + stdcall Layer_Create,eax cmp ebx,[ebp-4] ;if(n>s || k>s) jb .215 cmp ebx,[ebp-8] @@ -1081,7 +1149,7 @@ NNP_SetMemData: mov ebx,eax test ebx,ebx jne .217 - mov eax,12 + mov eax,txt_err_sqbrl_b1 jmp .193 .217: inc ebx @@ -1089,11 +1157,8 @@ NNP_SetMemData: mov dword[ebp-8],edx jmp .219 .218: - mov esi,[ebp+8] dec edx cmp eax,edx - lea ecx,[edi+4*edi] - mov esi,[esi+8] jae .220 stdcall @@strchr$qpxci, ebx,',' add esp,8 @@ -1110,22 +1175,23 @@ NNP_SetMemData: jmp .193 .222: mov byte[esi],0 - push ebx - call @@StrToDouble$qpc + stdcall @@StrToDouble$qpc,ebx pop ecx - lea edx,[edi+4*edi] + mov edx,edi + imul edx,sizeof.Layer mov ecx,[ebp+8] lea ebx,[esi+1] - mov eax,[ecx+8] + mov eax,[ecx+NeuralNetwork.layers] mov ecx,[ebp-8] - mov edx,[eax+4*edx+12] + mov edx,[eax+edx+Layer.biases] fstp qword[edx+8*ecx] inc dword[ebp-8] .219: - lea edx,[edi+4*edi] + mov edx,edi + imul edx,sizeof.Layer mov ecx,[ebp+8] - mov ecx,[ecx+8] - mov edx,[ecx+4*edx] + add edx,[ecx+NeuralNetwork.layers] + mov edx,[edx+Layer.c_size] mov eax,[ebp-8] cmp edx,eax ja .218 @@ -1142,83 +1208,94 @@ NNP_SetMemData: add esp,8 mov esi,eax test esi,esi - jne .225 - mov eax,15 + jne .225 + mov eax,txt_err_sqbrl_w1 jmp .193 .225: inc esi xor edx,edx - mov dword[ebp-8],edx + mov dword[ebp-8],edx ;k=0 jmp .227 -.226: +.226: ;for(k=0;klayers[i].c_size;k++) + + mov eax,edi + imul eax,sizeof.Layer + mov edx,[ebp+8] + add eax,[edx+NeuralNetwork.layers] + mov eax,[eax+Layer.n_size] + or eax,eax + jnz .end_null_we + inc dword[ebp-8] ;k++ + jmp .227 ;if 'weights' is null array +.end_null_we: + stdcall @@strchr$qpxci, esi,'[' add esp,8 mov ebx,eax test ebx,ebx - jne .228 - mov eax,16 + jne .228 + mov eax,txt_err_sqbrl_w2 jmp .193 .228: inc ebx xor edx,edx - mov dword[ebp-12],edx - jmp .230 -.229: - mov esi,[ebp+8] + mov dword[ebp-12],edx ;j=0 + jmp .230 +.229: ;for(j=0;jlayers[i].n_size;j++) dec edx - cmp eax,edx - lea ecx,[edi+4*edi] - mov esi,[esi+8] - jae .231 + cmp eax,edx ;eax = j, edx = n_size-1 + jae .231 stdcall @@strchr$qpxci, ebx,',' add esp,8 mov esi,eax - jmp .232 + jmp .232 .231: stdcall @@strchr$qpxci, ebx,']' add esp,8 mov esi,eax .232: test esi,esi - jne .233 - mov eax,17 - jmp .193 + jne .233 + mov eax,txt_err_sqbrr_w2 + jmp .193 .233: mov byte[esi],0 - push ebx - call @@StrToDouble$qpc + stdcall @@StrToDouble$qpc,ebx pop ecx - lea edx,[edi+4*edi] + mov edx,edi + imul edx,sizeof.Layer mov ecx,[ebp+8] lea ebx,[esi+1] - mov eax,[ecx+8] + mov eax,[ecx+NeuralNetwork.layers] mov ecx,[ebp-8] - mov edx,[eax+4*edx+16] + mov edx,[eax+edx+Layer.weights] mov eax,[edx+4*ecx] mov edx,[ebp-12] fstp qword[eax+8*edx] inc dword[ebp-12] .230: - lea edx,[edi+4*edi] + mov edx,edi + imul edx,sizeof.Layer mov ecx,[ebp+8] - mov ecx,[ecx+8] - mov edx,[ecx+4*edx+4] + add edx,[ecx+NeuralNetwork.layers] + mov edx,[edx+Layer.n_size] mov eax,[ebp-12] cmp edx,eax - ja .229 + ja .229 mov esi,ebx inc dword[ebp-8] .227: - lea eax,[edi+4*edi] + mov eax,edi + imul eax,sizeof.Layer mov edx,[ebp+8] - mov ecx,[edx+8] - mov eax,[ecx+4*eax] + add eax,[edx+NeuralNetwork.layers] + mov eax,[eax+Layer.c_size] cmp eax,[ebp-8] ja .226 inc edi .205: mov edx,[ebp+8] - cmp edi,[edx+12] + cmp edi,[edx+NeuralNetwork.layers_length] jb .204 xor eax,eax jmp .193 @@ -1306,6 +1383,7 @@ align 16 EXPORTS: dd sz_lib_init, lib_init dd sz_create, NNP_Create + dd sz_reset, NNP_Reset dd sz_feedforward, NNP_FeedForward dd sz_backpropagation, NNP_BackPropagation dd sz_getmemdata, NNP_GetMemData @@ -1314,6 +1392,7 @@ EXPORTS: dd 0,0 sz_lib_init db 'lib_init',0 sz_create db 'NNP_Create',0 + sz_reset db 'NNP_Reset',0 sz_feedforward db 'NNP_FeedForward',0 sz_backpropagation db 'NNP_BackPropagation',0 sz_getmemdata db 'NNP_GetMemData',0