EihiS

March 25, 2017

Using the Data-Folder libraries

Filed under: linux, neuron — admin @ 11:34 am

Pour cette fois, le post est en anglais

Today i released a first bunch of my homebrew libraries , so i’m going to post a first ‘hello world’ example program, wich uses those libraries.
I have not enough time to expose and explain all of that libraries functions, so the best is to dive into the code if you wish to understand the things.

In order to continue with the ‘neural net learning ‘ series, i need to use some graphic functions like displaying bitmaps, displaying text and buttons , and so on.. so, i’ll use those libraries in the next séries of post.

a simple “hello world” program (reminder : it uses the EHS2D_V2 folder from data.eihis.com/common/:

Opens a sdl2.0 based window, and creates a ‘text window’ inside it, displaying bitmap-based char texts :

This is a ultra-simple , first program just to use some simple functions of the library.

You can grab the necessary files from here : (ZIP : data.eihis.com/web_ehs2d_helloworld/web_ehs2d_helloworld.zip )

  • Use the makefile to build the executable
Here is , for information, the main.c code which is pretty small :
#include "classics.h"
// ehs 2d , sdl2.0 etc includes
#include "local_config.h"
int main(int argc, char **argv)
{

	int32_t h_textwindow;
	char* cb_text;
	char* cb_temp=malloc(sizeof(char)*256); // some room for sprintf functions
	uint32_t i_eventreturn;
	// hello world related variables
	uint32_t roll;
	uint32_t quit;
	//
	// (uses EHS2D globals)
	//
	ehs_main_x=0;
	ehs_main_y=0;
	ehs_main_w=900;
	ehs_main_h=600;
	// mandatory.. we wont resize the main window in this example
	ehs_dynamic_main_w=ehs_main_w;
	ehs_dynamic_main_h=ehs_main_h;
	//
	ehs_target_main_w=ehs_main_w;
	ehs_target_main_h=ehs_main_h;
	// enables/disables the background image (see local_config.h for the image's definition )
	ehs_background_name="../common/BITMAP/ARGB8888/helloworld_900x600.bmp";
	ehs_use_background=1;// if 1, would start with background enabled, displayed
	// could have been 0, with no background name defined
	//
	//
	// init EHS2D
	//
	EHS_init();
	//
	cb_text=(char*) malloc(sizeof(char)*32*12); // alloc size for the window's text
	h_textwindow=EHS_reg_elem(_EHS_SUBWINDOW,50,50,32,12,0,0,_EHS_IDLE,(uint8_t*) cb_text,"Console demo\0",_EHS_DM_CHAR,_EHS_FONTB_SIZE,fontB,fontC);//
	EHS_set_fonts(h_textwindow,0,2); // this sets the font used , aka 'font A / font C'
	EHS_SUBWIN_clear(h_textwindow,' '); // clear the window's display buffer ('cb_text') with ' ' (space) chars
	//
	EHS_SUBWIN_textAt(h_textwindow,"Hello world!",0,0);// place a text inside, at coordinates 0,0
	//
	quit=0;
	roll=0;
	while(quit==0)// loop there
	{
		// sprintf to a temp buffer for dynamic text content, then displat @ x=0,y=2 inside the ehs window
		sprintf(cb_temp,"Roll value is:%d \n",roll);
		EHS_SUBWIN_textAt(h_textwindow,cb_temp,0,2);
		// render the main window
		SDL_RenderPresent(sdlRenderer);
		// update the window's contents
		EHS_update();
		// now manage with input events
		i_eventreturn=EHS_process_events();
		switch (i_eventreturn)
		{
			case _EHS_EVENT_QUIT:
				quit=1;
			break;
			case _EHS_EVENT_KEYINPUT:
				//
				switch (input_key)
				{
					case SDLK_ESCAPE:
						quit=1;
					break;
					case SDLK_t:
						//
					break;
					//
					case SDLK_SPACE:

					break;
					//
					default:
					break;
				}
			break;
			case _EHS_MOUSECLICK:

			break;

			default:
			break;
		}
		//	some delay
	usleep(50000);
	roll++;
	}
	EHS_exit();
}
314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808

December 28, 2016

Neural nets,bases en C, part 9 : Features

Filed under: linux, neuron — Tags: , , , , — admin @ 7:42 pm

## ajout, le 25-03-2017 : les images de ce post proviennent de programmes compilés avec mes librairies ‘maison’ qui utilisent la sdl2.0. pour faciliter les exemples dans les posts qui vont suivre bientôt, j’ai mis a disposition ces librairies , ‘telles qu’elles sont’ , dans le répertoire ‘DATA’ de ce site ( INDEX )

Je vous invite a lire cette page pour les utiliser

Ou on on ré-apprend à faire un dessin :

Si on devait décomposer l’original ( un carré ) en éléments, on peut rapidement discerner qu’il est composé de :

  • traits verticaux
  • traits horizontaux
  • et éventuellement, d’angles ( notés c, c’ c” c”’ )

Ce travail de décomposition de l’image, c’est tout l’art de l’artiste peintre qui traduit sur sa toile une scène qu’il a sous les yeux : du peintre débutant au plus expérimenté, les deux sachant décomposer, de facon de plus en plus précise la scène en éléments importants et caractéristiques : géométrie, couleurs …
Mais la précision du rendu de la scène dépend de l’artiste : un voudra rendre le plus précisement possible la scene, un autre rendra une scene plus abstraite, voire completement abstraite , n’en retenant que l’essence .

On va prendre l’exemple ci dessus pour un réseau tels que ceux décrits dans les posts précédents, et utiliser le réseau pour analyser une image en entrée .

Comment faire apprendre au réseau les ‘features’ d’interet d’une image qu’on lui fournit en entrée ? ( et quels sont ces ‘features’ ? )

La réponse à la question , c’est un reseau de ce type :

N x Entrées -> R x Hidden -> N x Sorties

Le réseau à le même nombre d’entrées que de sorties, mais, dans la couche cachée, on limite la quantité de neurones à une valeur inférieure au nombre d’entrées.

Pour l’apprentissage, on demande au réseau de recomposer exactement l’information fournie en entrée, rien de plus : c’est un apprentissage sans supervision
Posons N=9 , R=3 :

Du fait que le nombre de neurones de la couche cachée et inférieur au nombre d’entrées , il va y avoir ‘compression’ des données par le réseau, au niveau de la couche cachée ( réduction d’une information à 9 variables en une information à 3 variables )
Mais, dans le même temps, l’apprentissage lui demande de restituer, sur ses sorties, la même information qu’a l’entrée ( ce qui équivaut à décompresser maintenant , une information composée de 3 variables vers une information composée de 9 variables , la sortie ) , on effectue l’opération : vecteur(9) vers vecteur(3) vers vecteur(9) pour l’information.

Ce reseau est auto-encodeur,
Et une fois l’apprentissage sans supervision terminé, il est capable d’extraire des éléments clé (features) de n’importe qu’elle sortes de données en entrée, et ceci, sans aucune supervision.

Pour traiter une image bitmap en entrée, un petit schéma descriptif :

Pour les besoins du post, on pose :

  • le bitmap est composé de valeurs 0.0 a 1.0 (float) , ou bien -1.0 / 1.0 ) , equivalent a la luminosité du pixel.
  • la grille (tile) d’entrée vers le réseau est composée de 3×3pixels = 9 entrées ( a,b,c,d,e,f,g,h,i)
  • La couche cachée est composée de 3 neurones, chacun entièrement connectés aux entrées ( il sont chacun 9 entrées + une de bias )
  • La couche de sortie comporte 9 neurones, entièrement connectés a la couche cachée ( + entrée bias pour chacun ) , notés A,B,C,D,E,F,G,H,I
  • Cette couche de sortie recompose l’entrée de 3×3 pixels , de sorte que, en terme de coordonnées spatiales (x,y)  : a correspond a A , b correspond à B etc
On fait donc l’apprentissage pour que :
A B C
D E F
G H I
reflète les valeurs d’entrées :
a b c
d e f
g h i
Pour mieux comprendre, une capture d’écran , en bas de ce post
  • IN MAP est le bitmap fourni en entrée au réseau. il est parcouru de haut en bas, et de gauche a droite, en faisant des incréments de 3 pixels a chaque itération. a chaque pas, on effectue un cycle d’apprentissage au reseau.
Ci dessous, IN MAP , zoomé : la grille rouge représent les surfaces de 3×3 pixels qui sont parcourues lors de l’apprentissage.elle ne se recouvrent pas et sont contigues :
  • OUT MAP est la réponse en sortie du réseau, au bout de l’apprentissage (erreur RMS <0.01)
  • La sortie est faite sur le canal rouge
Pour afficher les éléments clé utilisés (les features), il suffit d’utiliser les 3 neurones de la couche cachée. en effet, leur déclenchement est combiné par la couche de sortie pour refabriquer l’image a l’identique que l’original :
Il suffit donc de visualiser les poids déclencheurs de ces 3 neurones pour afficher l’aspect du ‘feature’ utilisé pour chacun des 3 neurones.
  • C’est ce qui est visible sur la capture d’écran, noté ‘FEATURE FEATURE FEATURE’
  • Chaque feature a été colorisé Rouge,Vert,Bleu afin de pouvoir le distinguer dans la zone ‘F USAGE’
La zone ‘FEAT GROUPS’ permet ,grace a une SOM (Self Organizing Map) , de créer des groupes de déclenchements pour ces 3 features et de les visualiser. La carte SOM présente des groupes purs de BLEU , VERT , ROUGE, qui correspondent aux usages d’une feature unique pour fabriquer une sortie determinée, tandis que les autres groupes représentent différents mixages des quantitées des 3 neurones (rouge,vert,bleu) pour certains autres états de sortie a générer : c’est le mixage des features , utilisé par le réseau
  • F USAGE est la carte d’utilisation des features : chaque couleur de cette carte traduit le mixage qui a été fait entre les 3 features (préléve de la carte SOM), pour recréer la sortie le plus correctement possible, grace a l’apprentissage.ils sont repositionnés aux coordonnées x,y correspondantes au bitmap d’entrée, afin de mettre en évidence OU ils ont été utilisés, par rapport a l’image d’entrée :

Pour faciliter la compréhension, un overlay :
Les couleurs représentent chaque mixage de features utilisé, en superposition sur le bitmap original.
(En blanc, les pixels a 1.0 du bitmap d’entrée)

Une capture sur un bitmap différent :

314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808

December 16, 2016

Neural nets, bases en C, part 8 , généralisation

Filed under: linux, neuron — Tags: , , , — admin @ 11:41 am

La fonction backWARD_CASCADE() est transformée afin d’être utilisable dans un réseau qui serait constitué de plusieurs couches, ou d’autres configurations moins conventionelles :

L’existante :

void RESO_backWARD_CASCADE(reso* n,float reverse_error)
{
	uint32_t k;
	float xb;
	xb=tanh(1.0-(n->neuron*n->neuron));
	xb*=reverse_error;
	n->error=xb;	//
	for(k=0;k<n->synapses;k++)
	{
		n->part[k]=(fabs(n->w[k])/n->wtot);//
		n->ward[k]=n->error*n->w[k];//
		n->back[k]=n->error*n->in[k];//
	}
	n->epoch++;
}

Un neurone d’une couche ‘cachée’ peut avoir plusieurs connections vers des entrées de la couche suivante :

ou, plus simplement représenté :

Il est nécéssaire de modifier la fonction pour cumuler, pour chaque neurone d’une couche ‘N’ du reseau (autre que la dernière couche , ‘de sortie ‘), l’erreur des neurones auquels il est connecté, et ceci dans la proportion à laquelle il aura participé à l’erreur de ces neurones.

on modifie donc dabord la structure du reseau, pour rendre ‘xb’ élément de la structure :

//
typedef struct {
	uint32_t synapses;
	float* in;			// forward compute inputs
	float* back;		// backward computed inputs
	float* ward;
	float* w;			// forward/backward weight for each inputs
	float* part;
	float neuron;			// forward computed output, backward compute input
	float error;
	float wtot;			// total input weights
	//
	float xb;
	//
	uint64_t epoch;
	uint64_t internal;
} reso;

Puis la fonction backWARD_CASCADE() ,dupliquée et modifiée devient :

void RESO_backWARD_CASCADE_ADDERROR(reso* n,float reverse_error)
{
	uint32_t k;
	n->xb=tanh(1.0-(n->neuron*n->neuron));
	n->xb*=reverse_error;
	n->error+=n->xb;	// on cumule maintenant la part d'erreur entrante
	for(k=0;k<n->synapses;k++)
	{
		n->part[k]=(fabs(n->w[k])/n->wtot);//
		n->ward[k]=n->xb*n->w[k];//
		n->back[k]+=n->xb*n->in[k];// on cumule les backs[] générés pour chaque entrées
	}
	n->epoch++;
}

Ensuite,une fonction pour préparer (initialiser) error et les back[] avant :

//
void RESO_prepare_CASCADE(reso* n)
{
	uint32_t k;
	for(k=0;k<n->synapses;k++) { n->back[k]=0.0;}
	n->error=0.0;
}

Avant de tester avec la nouvelle mouture de programme qui suit, quelques détails sur des ajouts :

  • ajout de macros pour modifier facilement le mode d’activation des neurones ( tanh , etc )
  • mise en #define des LR

Il y précisement 2 macros pour la fonction d’activation :

#define _OUTPUT_TRANSFORM(x) tanh(x)
ou bien :
#define _OUTPUT_TRANSFORM(x) (x>0.0)? tanh(x):0.0

La deuxième est dérivée de reLU , pour rectifier Linear Unit (google pour plus d’informations), limitée a +1.0 par le tanh, ce qui aurait pu etre fait par une autre méthode.

On définit 2 sorties , la sortie z_net et la sortie y_net attendues:

#define _REPON_Z ((ang>3.0)&&(ang<6.0))? +1.0:0.0 /* expected formula, Z output */
#define _REPON_Y (ang>3.0)?  0.0:1.0 /* expected formula, Y output */

Je vous invite à tester le programme avec l’une et l’autre de fonctions pour l’activation

#include "../common/classics.h"
#include "../common/neuron/RESO_library.c"

int main(int argc, char **argv)
{
	// le reseau S (layer1)
	reso stnet;
	reso* snet=&stnet;			// pointeur vers la structure
	//
	// le reseau T (layer1)
	reso ttnet;
	reso* tnet=&ttnet;			// pointeur vers la structure
	//
	// le reseau Y (layer 2)
	reso ytnet;
	reso* y_net=&ytnet;			// pointeur vers la structure
	// le reseau Z (layer 2)
	reso ztnet;
	reso* z_net=&ztnet;			// pointeur vers la structure
	//
	//float s_expected,t_expected,u_expected;				// utile pour stocker ce qu'on attend en reponse
	float expected_z,expected_y;// commode
	float RMSerror,RMScompute;
	float ang;					// pour un angle, sinus/cosinus
	//
	uint32_t i;		// une variable d'utilité..
	//
	//
	RESO_init(snet,3);// on initialise le reseau S, avec 3 entrées
	RESO_init(tnet,3);// on initialise le reseau T, avec 3 entrées
	//RESO_init(unet,3);// on initialise le reseau U, avec 3 entrées
	//
	RESO_init(y_net,3);// on initialise le reseau Z, avec 3 entrées
	RESO_init(z_net,3);// on initialise le reseau Z, avec 3 entrées
	//
	snet->w[0]=0.5;
	snet->w[1]=0.39;
	snet->w[2]=0.41;
	//
	tnet->w[0]=0.5;
	tnet->w[1]=0.45;
	tnet->w[2]=0.43;
	//
	//
	z_net->w[0]=0.49;
	z_net->w[1]=0.40;
	z_net->w[2]=0.5;
	//
	y_net->w[0]=0.48;
	y_net->w[1]=0.42;
	y_net->w[2]=0.5;
	//
	RMSerror=0.0;
	RMScompute=0.0;
	//
	#define _OUTPUT_TRANSFORM(x) tanh(x)
	//#define _OUTPUT_TRANSFORM(x) (x>0.0)? tanh(x):0.0
	//
	#define _LR_OUT		0.01
	#define _LR_HIDDEN	0.01
	//
	// on définit ici pour les essais, les 3 entrées, la sortie attendue par formule
	//
	#define _INA	1.0 /* un bias */
	#define _INB 	NN_frand_ab(0.0,2.0) /* inutilisé */
	#define _INC	ang /* la variable d'entrée */
	//
	#define _REPON_Z ((ang>3.0)&&(ang<6.0))? +1.0:0.0 /* expected formula, Z output */
	#define _REPON_Y (ang>3.0)?  0.0:1.0 /* expected formula, Y output */
	//
	//
	ang=0.0;
	//
	while((RMScompute>0.05)||(z_net->epoch<200))// jusqu'a RMS erreur total < 0.01
	{
		//
		snet->in[0]=_INA; //
		snet->in[1]=_INB;
		snet->in[2]=_INC;

		tnet->in[0]=_INA;
		tnet->in[1]=_INB;
		tnet->in[2]=_INC;
		//
		//
		expected_z=_REPON_Z;
		expected_y=_REPON_Y;
		//
		//	CALCUL : FORWARD
		RESO_forward(snet);
		RESO_forward(tnet);
		//
		snet->neuron=_OUTPUT_TRANSFORM(snet->neuron);
		tnet->neuron=_OUTPUT_TRANSFORM(tnet->neuron);
		// on transmet les 2 sorties de snet,tnet ver z_net, neuron de sortie, qui a 3 entrées :
		z_net->in[0]=snet->neuron;
		z_net->in[1]=tnet->neuron;
		z_net->in[2]=_INA;// entrée BIAS pour ce neurone, est INA pour les 2 neurones de la couche précédente
		//
		y_net->in[0]=snet->neuron;
		y_net->in[1]=tnet->neuron;
		y_net->in[2]=_INA;// entrée BIAS pour ce neurone, est INA pour les 2 neurones de la couche précédente
		// on calcule ce dernier noeud:
		RESO_forward(z_net);
		z_net->neuron=_OUTPUT_TRANSFORM(z_net->neuron);
		RESO_forward(y_net);
		y_net->neuron=_OUTPUT_TRANSFORM(y_net->neuron);
		//
		if(z_net->epoch%10000==0)
		{
			printf("\n\nepoch[%6.6lu]\nZNET\t e(%+5.5f) , RMS{%8.8f}\n",z_net->epoch,z_net->error,RMScompute);
			printf("\t\t wtot[%+3.3f] --",z_net->wtot);	// au passage, le poids total des entrées a ce cycle
			for(i=0;i<z_net->synapses;i++) { printf("(w=%+5.5f / ward=%+7.7f]",z_net->w[i],z_net->ward[i]); }
			//
			// affiche snet valeurs
				printf("\nSNET\t e(%+5.5f) out=[%5.5f]\t",snet->error,snet->neuron);
				printf("wtot[%+3.3f] --",snet->wtot);	//
				for(i=0;i<snet->synapses;i++) { printf("(%+3.3f)",snet->w[i]); }
			// affiche tnet valeurs
				printf("\nTNET\t e(%+5.5f) out=[%5.5f]\t",tnet->error,tnet->neuron);
				printf("wtot[%+3.3f] --",tnet->wtot);	//
				for(i=0;i<tnet->synapses;i++) { printf("(%+3.3f)",tnet->w[i]); }
		}
		//  CALCUL : BACKWARD pour Z_NET ( pour obtenir l'erreur de la sortie n->neuron )
		//  expected contient la valeur attendue, fournie a la fonction
		RESO_backWARD(z_net,expected_z);
		RESO_backWARD(y_net,expected_y);
		//
		//
		RESO_prepare_CASCADE(snet);// remise a zéro du cumul d'erreur pour ce neurone
		RESO_prepare_CASCADE(tnet);// idem
		// on reporte LES ERREURS sur les reseaux précédents S,T , et ce ,
		// pour chaque liaison du neurone vers la couche suivante
		RESO_backWARD_CASCADE_ADDERROR(snet,y_net->ward[0]);// dans quelle 'proportion' snet a participé à l'erreur de znet,A
		RESO_backWARD_CASCADE_ADDERROR(snet,z_net->ward[0]);//idem pour znet, A
		// meme chose pour tnet
		RESO_backWARD_CASCADE_ADDERROR(tnet,y_net->ward[1]);// tnet, pour ynet entrée B
		RESO_backWARD_CASCADE_ADDERROR(tnet,z_net->ward[1]);//tnet pour znet B
		// cumul RMS pour controle convergence
		RMSerror+=(fabs(z_net->error)+fabs(y_net->error))/2.0; // basé sur une moyenne des erreurs RMS des 2 sorties
		RMScompute=(RMSerror/(float)z_net->epoch);
		// appliquer correction, inverse : derniere couche vers premiere
		RESO_apply(z_net,_LR_OUT);
		RESO_apply(y_net,_LR_OUT);
		//
		RESO_apply(snet,_LR_HIDDEN);//
		RESO_apply(tnet,_LR_HIDDEN);//
		// .. valeur entre 0/10.0 pour le prochain cycle
		ang=NN_frand_ab(0.0,10.0);
		//
	}
	// seuil RMS ok, affiche les infos finales poids/ part dans le résultat
	printf("\n\tZ_NET Final Parts  :");
	for(i=0;i<z_net->synapses;i++) { printf("(%+3.3f%c)",z_net->part[i]*100.0,'%'); }
	printf("\n\tZ_NET Final Weights:");
	for(i=0;i<z_net->synapses;i++) { printf("(%+3.3f )",z_net->w[i]);}
	printf("\n");
	printf("\n\tY_NET Final Parts  :");
	for(i=0;i<y_net->synapses;i++) { printf("(%+3.3f%c)",y_net->part[i]*100.0,'%'); }
	printf("\n\tY_NET Final Weights:");
	for(i=0;i<y_net->synapses;i++) { printf("(%+3.3f )",y_net->w[i]);}
	printf("\n");
//
	// infos snet
	printf("\n\tSNET Final Parts  :");
	for(i=0;i<snet->synapses;i++) { printf("(%+3.3f%c)",snet->part[i]*100.0,'%'); }
	printf("\n\tSNET Final Weights:");
	for(i=0;i<snet->synapses;i++) { printf("(%+3.3f )",snet->w[i]);}
	printf("\n");
	// infos tnet
	printf("\n\tTNET Final Parts  :");
	for(i=0;i<tnet->synapses;i++) { printf("(%+3.3f%c)",tnet->part[i]*100.0,'%'); }
	printf("\n\tTNET Final Weights:");
	for(i=0;i<tnet->synapses;i++) { printf("(%+3.3f )",tnet->w[i]);}
	printf("\n");
	// 'test run'
	z_net->internal=0;
	ang=0.00;
	while(z_net->internal<100)
	{
		//
		snet->in[0]=_INA; // diffuses constant 5.0
		snet->in[1]=_INB;
		snet->in[2]=ang;
		//
		tnet->in[0]=_INA;
		tnet->in[1]=_INB;
		tnet->in[2]=ang;
		//
		expected_z=_REPON_Z;
		expected_y=_REPON_Y;
		//	CALCUL : FORWARD
		RESO_forward(snet);
		RESO_forward(tnet);
		//
		snet->neuron=_OUTPUT_TRANSFORM(snet->neuron);
		tnet->neuron=_OUTPUT_TRANSFORM(tnet->neuron);
		//unet->neuron=tanh(unet->neuron);
		// on transmet les 3 sorties de snet,tnet,unet ver z_net, neuron de sorties, qui a 3 entrées :
		z_net->in[0]=snet->neuron;
		z_net->in[1]=tnet->neuron;
		z_net->in[2]=_INA;
		//
		y_net->in[0]=snet->neuron;
		y_net->in[1]=tnet->neuron;
		y_net->in[2]=_INA;
		// on calcule ce dernier noeud:
		RESO_forward(z_net);
		z_net->neuron=_OUTPUT_TRANSFORM(z_net->neuron);
		RESO_forward(y_net);
		y_net->neuron=_OUTPUT_TRANSFORM(y_net->neuron);
		// output version human readable
		#define _OUT_TEXT 	"cycle[%lu] B[%f] B[%f] A[%f] EXP_Z[%f] OUT_Z[%f] || EXP_Y[%f] OUT_Y[%f]\n"
		// ou pour export CSV :
		//#define _OUT_TEXT	"%lu,%f,%f,%f,%f,%f,%f,%f\n"
		printf(_OUT_TEXT,
			z_net->internal,
			_INC,
			_INB,
			_INA,
			_REPON_Z,
			z_net->neuron,
			_REPON_Y,
			y_net->neuron);
		//
		ang+=0.10;
	}
	//
	// todo : malloc releases
}

La sortie, en version TANH() * seuil atteint en 1100000 epochs

Le même , avec activation en mode ‘reLU’ , seuil atteint en 140000 epochs :

En descendant le seuil RMS a 0.01, et reLU en activation :

Dans cette situation , un résumé des parts de chaque élément :

Z_NET Final Parts  :(+45.641%)(+46.988%)(+7.372%)
Z_NET Final Weights:(+4.510 )(-4.643 )(-0.728 )

Y_NET Final Parts  :(+63.674%)(+6.939%)(+29.387%)
Y_NET Final Weights:(-5.336 )(-0.581 )(+2.463 )

SNET Final Parts  :(+74.550%)(+0.064%)(+25.386%)
SNET Final Weights:(-16.639 )(+0.014 )(+5.666 )

TNET Final Parts  :(+84.045%)(+0.552%)(+15.403%)
TNET Final Weights:(-8.278 )(-0.054 )(+1.517 )

SNET utilise A et C ( BIAS, et la variable ang ) : il détecte un des ’seuils’ ,celui a 3.0 ou celui a 6.0
TNET utilise A et C egalement : il detecte une des deux seuils , celui a 3.0 ou celui a 6.0
ZNET utilise majoritairement ses entrées A et B , qui sont les sorties de SNET et TNET, respectivement , pour générer la réponse attendue, ainsi que son entrée de BIAS (comparaison)
YNET, utilise majoritairement  son entrée A , qui est la sortie de SNET, et son BIAS , hors, comme on sait que ZNET et YNET , en sortie, doivent communément déclencher sur 3.0, on peut en conclure que SNET detecte le passage par 3.0 de la variable en ‘ang’ , puisqu’il est utilisé par YNET ET ZNET.

Pour finir :

Même si le reseau et les fonctions sont, pour l’instant, plutot ‘lourdes’, vous avez les bases pour constituer des réseau personnalisés beaucoup plus compacts, et j’ai volontairement découpé les fonctions et phases de l’apprentissage, afin de clarifier chacunes des étapes.
On va optimiser et rendre synthétiques les choses dans les prochains posts

314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808

Neural nets, bases en C, part 7 , backward_CASCADE()

Filed under: linux, neuron — Tags: , , , — admin @ 10:40 am

Avant de modifier la fonction backWARD_CASCADE() pour l’adapter progressivement à l’utilisation dans un reseau a plusieurs couches,une explication sur un de ses éléments.

Rappel de la fonction :

void RESO_backWARD_CASCADE(reso* n,float reverse_error)
{
	uint32_t k;
	float xb;
	//
	xb=tanh(1.0-(n->neuron*n->neuron));
	xb*=reverse_error;
	n->error=xb;	//
	for(k=0;k<n->synapses;k++)
	{
		n->part[k]=(fabs(n->w[k])/n->wtot);//
		n->ward[k]=n->error*n->w[k];//
		n->back[k]=n->error*n->in[k];//
	}
	n->epoch++;
}

Il convient d’expliquer ce qu’est le xb=tanh(1.0-(n->neuron*n->neuron)) :
Dans le post sur le même sujet, part 5 , en annexe, j’ai posté un graphe de la fonction.
Son but est de moduler le learning rate selon la valeur du neuron : si celle ci est très grande, on le réduit, et on tend vers un coef. de 1.0 pour le LR  lorsque ‘neuron’ tend vers zéro (limite).
Cette fonction optimise la vitesse d’apprentissage, et,  les pivots autour de valeurs 0.0 des neurones.
On peut se passer du tanh() et conserver 1.0-(neuron*neuron) , si la totalité du reseau exploite des neurones dont les valeurs min/max ne dépassent pas 1.0 : dans ce cas, un valeur absolue de neuron de 1.0 engage un xb=0, qui annule à 100% la modfication future du poids du neurone, puisque ‘reverse_error’ est mutltiplié par xb pour générer ‘error’

Pour l’heure, on ne l’applique qu’aux neurones des couches autres que la dernière (outputs).
On verra ensuite que cette fonction peut servir à beaucoup de choses utiles.

314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808
Older Posts »

cat{ 185 } { post_1053 } { } 2009-2015 EIhIS Powered by WordPress