EihiS

December 15, 2016

Neural nets, bases en C , part 6

Filed under: linux, neuron — Tags: , , , , — admin @ 6:08 pm

De l’importance du ‘training set’

Le reseau décrit précédement aboutit a une erreur RMS en sortie inférieure a 0.05 au bout d’approximativement  cycles (epochs) d’apprentissage (epoch = 7.27Millions)

On modifie la façon dont ‘ang’ est générée, dans la boucle d’apprentissage :

de :

  • ang=NN_frand_ab(0.0,10);
en :
  • ang=(float) ((int32_t)NN_frand_ab(0.0,10.0));

On relance le programme :

  • -> il atteint le seuil RMS voulu en seulement 180000 epochs
On trace le graphe de sa sortie :
Le réseau a généralisé : la simplification du nombre d’élements dans le train-set accélère l’apprentissage, mais entraine aussi le réseau à faire une approximation des cas intermédiaires, non présents dans le train-set.
Au niveau du seuil du 3.0 en valeur d’entrée par exemple, le réseau n’a eu que deux exemples de cas en apprentissage :
  • pour 3.0 en entrée, sortie attendue = -1 ( le test est : +1 si strictement supérieur a 3.0)
  • pour 4.0 en entrée, sortie attendue = +1
  • On constate que la sortie OUTPUT bascule de -1.0 vers +1.0 à la moitié de ces 2 valeurs, 3.5 ( la fonction tanh ‘arrondi’ les angles aux extrèmes -1.0/+1.0
Peut-on faire apprendre le reseau encore plus vite ?
Il est temps de parler de la fonction d’activation :
  • pour l’heure c’est tanh()
on va changer l’attendu en sortie du reseau , de :
  • #define _REPON ((ang>3.0)&&(ang<8.0)) +1.0:-1.0
en :
  • #define _REPON ((ang>3.0)&&(ang<8.0))? +1.0:0.0
On relance le programme sans autre modifications :
Le seuil est atteint en environ 70000 ( l’affichage est fait en %10000 .. )
C’est deux fois moins de temps pour descendre vers le seuil RMS voulu.
Son graphe en sortie :
314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808

Neural nets, bases en C, part 5

Filed under: linux, neuron — Tags: , , , , — admin @ 8:58 am

..Ou l’on arrive à l’ajout nécéssaire d’une couche supplémentaire de neurones :

Si on garde le réseau (plutot le neurone daillleurs ) , à 3 entrées, on constatera que tout tentative de le faire converger vers une solution est impossible, lorsqu’on pose par exemple, un sortie attendue de la forme  :

#define _REPON	((net->in[1]>3.0)&&(net->in[1]<8.0))? +1.0:-1.0

Il va falloir créer un vrai réseau, en connectant entre eux les neurones :

J’ai gardé volontairement les 3 entrées pour chaque neurone même si elles ne sont pas nécéssaire pour résoudre le problème, mais pour un aspect pratique afin de modifier facilement les entrées du réseau constitué a fins de tests.

La littérature sur le sujet de la backpropagation étant largement diffusée et ‘mathéifiée’ , on reviendra plus tard sur une portion de la nouvelle fonction ‘backWARD_CASCADE()‘ qui sera, pour l’instant:

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++;
}

A la différence de backWARD() , on n’introduit plus une valeur attendue , mais (l’erreur*poids)=ward[] du neurone situé après celui qui est en cours de traitement ( et pour l’instant, on en aura qu’1 seul , celui de z_net )

On peut tester la configuration à trois neurones, avec le programme suivant :

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

int main(int argc, char **argv)
{
	// le reseau S
	reso stnet;
	reso* snet=&stnet;			// pointeur vers la structure
	//
	// le reseau T
	reso ttnet;
	reso* tnet=&ttnet;			// pointeur vers la structure
	//
	// le reseau Z
	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;
	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(z_net,3);// on initialise le reseau Z, avec 3 entrées
	//
	// mise a 0.5,0.4,0.3 de tous les poids , pour S T et Z cf POST
	snet->w[0]=0.5;
	snet->w[1]=0.5;
	snet->w[2]=0.5;
	//
	tnet->w[0]=0.4;
	tnet->w[1]=0.4;
	tnet->w[2]=0.4;
	//
	//
	z_net->w[0]=0.3;
	z_net->w[1]=0.3;
	z_net->w[2]=0.3;
	//
	RMSerror=0.0;
	RMScompute=0.0;
	//
	// on définit ici pour les essais, les 3 entrées, la sortie attendue par formule
	//
	#define _INA	5.0 /* un bias */
	#define _INB 	0.0 /* inutilisé */
	#define _INC	ang /* la variable d'entrée */
	//
	#define _REPON	((ang>3.0)&&(ang<8.0))? +1.0:-1.0 /* expected formula */
	//
	// _________--------________
	// 0        3       8        10
	//
	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=_REPON;
		//
		//	CALCUL : FORWARD
		RESO_forward(snet);
		RESO_forward(tnet);
		//
		snet->neuron=tanh(snet->neuron);
		tnet->neuron=tanh(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
		// on calcule ce dernier noeud:
		RESO_forward(z_net);
		z_net->neuron=tanh(z_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);
		//
		// on reporte ** l'ERREUR ** sur sur les reseaux précédents S,T
		RESO_backWARD_CASCADE(snet,z_net->ward[0]);// <- on transmet ward[0] de z_net
		RESO_backWARD_CASCADE(tnet,z_net->ward[1]);// <- idem pour ward[1]
		// cumul RMS pour controle convergence
		RMSerror+=fabs(z_net->error);
		RMScompute=(RMSerror/(float)z_net->epoch);
		// appliquer correction, inverse : derniere couche vers premiere
		RESO_apply(z_net,0.001);
		//
		RESO_apply(snet,0.1);//
		RESO_apply(tnet,0.1);//
		// .. 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");
	// 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=_REPON;
		//	CALCUL : FORWARD
		RESO_forward(snet);
		RESO_forward(tnet);
		//
		snet->neuron=tanh(snet->neuron);
		tnet->neuron=tanh(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;
		// on calcule ce dernier noeud:
		RESO_forward(z_net);
		z_net->neuron=tanh(z_net->neuron);
		// output version human readable
		#define _OUT_TEXT 	"cycle[%lu] A[%f] B[%f] C[%f] EXP[%f] OUT[%f]\n"
		// ou pour export CSV :
		// #define _OUT_TEXT	"%lu,%f,%f,%f,%f,%f\n"
		printf(_OUT_TEXT,
			z_net->internal,
			_INA,
			_INB,
			_INC,
			_REPON,
			z_net->neuron);
		//
		ang+=0.10;
	}
	//
	// todo : malloc releases
}

L’apprentissage converge vers une solution, et on obtient en résultat (sur ma machine):

Z_NET Final Parts  :(+48.571%)(+42.593%)(+8.837%)
Z_NET Final Weights:(+2.709 )(+2.375 )(-0.493 )

SNET Final Parts  :(+37.337%)(+0.258%)(+62.405%)
SNET Final Weights:(-72.378 )(+0.500 )(+120.971 )

TNET Final Parts  :(+61.343%)(+0.139%)(+38.517%)
TNET Final Weights:(+176.048 )(+0.400 )(-110.540 )

Comme on peut le constater, l’entrée ‘B’ de snet, et tnet, qui est a 0.0 (cf. programme) , est quasiment complètement rejetée ( 0.258% et 0.139% de parts, respectivement ), ou , plus précisement, son poids n’a pas été changé, hors comparé aux poids des autres entrées, leur parts sont devenues minimes dans la résultat final.

  • snet et tnet ont utilisé les entrées A (bias) et C (la variable) en majorité
  • znet, à utilisé les 3 entrées : A qui est la sortie de snet, B qui est la sortie de tnet et C qui est son entrée BIAS, la même que A pour snet et tnet.
Plusieurs remarques s’imposent :
  • Les poids de départ ne sont plus fixés à la même valeur. La situation de départ du réseau constitué (les valeurs des poids) influe sur la rapidité de la convergence, et peut aboutir des echecs ( cf. littérature sur le sujet )
  • Les learning rates : faire des essais , cycles de comparaisons avec même situation (poids) de départ VS différents learning rates sur z_net et snet/tnet
Avant d’aborder une partie d’explication sur la fonction backWARD_CASCADE() , un graphique complet des entrées/sorties du réseau :

Annexe, détail de fonctions utiles (ou pas)

314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808

December 14, 2016

Neural nets,bases en C part 4, la fonction TANH(y)

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

Ou l’on arrive a la fonction TANH, nécéssaire dans le cas ou on s’attend à une sortie plus proche du ‘tout’ ou ‘rien’ logique que des valeurs linéaires précédentes :

Le programme de test suivant fait apprendre au réseau le déclenchement de la sortie à +1.0 si l’entrée 2 (_INB) est supérieure à +5.0, et -1.0 si elle est inférieure (ou égale) a +5.0 :

On ne change pas la structure du réseau, 3 entrées,une sortie. L’entrée inA est ‘inutilisée’, fixée à 0.01, inB est fixée entre 0.0 et +10.0 par un tirage aléatoire a chaque cycle, et inC est fixée a 2.5 fixe, servant d’entrée BIAS pour le réseau :

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

int main(int argc, char **argv)
{
	// le reseau
	reso snet;
	reso* net=&snet;			// pointeur vers la structure
	//
	float expected;				// utile pour stocker ce qu'on attend en reponse
	float RMSerror,RMScompute;
	//
	uint32_t i;		// des variables d'utilité..
	//
	//
	RESO_init(net,3);// on initialise le reseau, avec 3 entrées
	//
	net->w[0]=1.0;
	net->w[1]=1.0;
	net->w[2]=1.0;
	//
	RMSerror=0.0;
	RMScompute=1.0;
	// on définit ici pour les essais, les 3 entrées, la sortie attendue par formule
	#define _INA	0.01
	#define _INB	NN_frand_ab(0.0,10.0)
	#define _INC	2.5
	//
	#define _REPON	(net->in[1]>5.0)? 1.0:-1.0
	//
	while((RMScompute>0.05)||(net->epoch<20))// jusqu'a RMS erreur total < 0.01
	{
		//
		net->in[0]=_INA;
		net->in[1]=_INB;
		net->in[2]=_INC;
		//
		expected=_REPON;
		//
		//	CALCUL : FORWARD
		//
		RESO_forward(net);
		// application tanh() a la sortie
		net->neuron=tanh(net->neuron);
		//
		//  CALCUL : BACKWARD ( pour obtenir l'erreur de la sortie n->neuron )
		//  expected contient la valeur attendue, fournie a la fonction
		RESO_backWARD(net,expected);
		// au passage, on fait un cumul d'erreur RMS pour superviser l'apprentissage du reseau
		RMSerror+=fabs(net->error);
		RMScompute=(RMSerror/(float)net->epoch);
		// epoque de l'apprentissage, erreur immédiate dela sortie, et erreur RMS total depuis le début
		printf("\nepoch[%6.6lu] e(%+6.6f) , RMS{%5.5f} ",net->epoch,net->error,RMScompute);
		printf("wtot[%+3.3f] --",net->wtot);	// au passage, le poids total des entrées a ce cycle
		// les 'n' entrées (ici 3) , leur part en % dans le résultat que fournit la sortie
		for(i=0;i<net->synapses;i++) { printf("(%+3.3f%c)",net->part[i]*100.0,'%'); }
		//
		RESO_apply(net,0.05);
	}
	// seuil RMS ok, affiche les infos finales poids/ part dans le résultat
	printf("\nFinal Parts :\n");
	for(i=0;i<net->synapses;i++) { printf("(%+3.3f%c)",net->part[i]*100.0,'%'); }
	printf("\nFinal Weights:\n");
	for(i=0;i<net->synapses;i++) { printf("(%+3.3f )",net->w[i]);}
	printf("\n");
	// on execute un cycle de calcul FORWARD uniquement, pour vérifier que
	// tout est OK :
	// 'test run'
	net->internal=0;
	while(net->internal<80)
	{
		net->in[0]=_INA;
		net->in[1]=_INB;
		net->in[2]=_INC;
		expected=_REPON;				// uniquement pour comparer l'attendu a la sortie du reseau
		RESO_forward(net);				// forward uniquement
		net->neuron=tanh(net->neuron);	// application tanh()
		printf("\nCycle[%6.6lu] EXPECTED(%+6.6f) , ACTUAL{%5.5f} ",net->internal,expected,net->neuron);
	}
	//
}

.. on utilise les fonctions :

  • RESO_init()
  • RESO_forward()
  • RESO_backWARD()
  • RESO_apply()
  • une fonction NN_frand_ab(min,max)
  • et la structure reso

Telles que : ( je les ai listées a nouveau ici avec les modifications des précédents posts intégrées )

float NN_frand_ab(float a, float b)
{
    return (float) (( rand()/(float)RAND_MAX ) * (b-a) + a);
}
//
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
	//
	uint64_t epoch;
	uint64_t internal;
} reso;
void RESO_init(reso* n,uint32_t input_count)
{
	uint32_t k;
	float init_w=1.0;
	n->in=(float*) malloc(sizeof(float)*input_count);
	n->back=(float*) malloc(sizeof(float)*input_count);
	n->ward=(float*) malloc(sizeof(float)*input_count);
	n->w=(float*) malloc(sizeof(float)*input_count);
	n->part=(float*) malloc(sizeof(float)*input_count);
	//
	n->synapses=input_count;
	n->wtot=init_w*input_count;	//prepare startup total weights
	for(k=0;k<n->synapses;k++)
	{
		n->in[k]=0.0;
		n->w[k]=init_w;	// default, @1
		n->part[k]=n->w[k]/n->wtot;		// backed ready
	}
	n->neuron=0.0;
	n->error=0.0;
	//
	n->epoch=1;
	n->internal=1;

}
void RESO_forward(reso* n)
{
	uint32_t i;
	n->neuron=0.0;
	n->wtot=0.000001;// divide by zero ?
	for(i=0;i<n->synapses;i++)
	{
		n->neuron+=n->in[i]*n->w[i];
		n->wtot+=fabs(n->w[i]);//
	}
	n->internal++;
}
void RESO_backWARD(reso* n,float expected)
{
	uint32_t k;
	n->error=n->neuron-expected;	// actual - expected
	//
	for(k=0;k<n->synapses;k++)
	{
		n->part[k]=(fabs(n->w[k])/n->wtot);								// assume w always positive
		n->ward[k]=n->error*n->w[k];// erreur * poids
		n->back[k]=n->error*n->in[k];// erreur * input val
	}
	n->epoch++;
}
void RESO_apply(reso* n,float rate)
{
	uint32_t k;
	for(k=0;k<n->synapses;k++)
	{
		// commentée (voir plus tard ) : if(fabs(n->w[k])<0.001) n->w[k]=-n->w[k];
		n->w[k]-=n->back[k]*rate;//
	}
}

En suivant, un graphe de la sortie ‘neuron’, en fonction de l’entrée inB ( 0-10 ), et zoom (4.
125 à 6.0 )  - neuron et error utilisent l’axe Y gauche, ward et back, l’axe droite

..Avec le seuil RMS fixé a 0.05, on voit que le déclenchement de la sortie , passant de -1.0 a +1.0, se fait un peu avant 5 en entrée.

Si on descend le seuil RMS a 0.01 avant de terminer l’apprentissage, on obtient cette fois :

remarque : ne pas se fier a l’overshoot du neuron qui passe ‘au dela’ de 1.0 malgré la fonction tanh() . les courbes sont ‘lissées’ (spline) par le soft qui génère les graphes.

Sans smooth, et dans le range 4.9 - 5.1 , par pas de 0.025 :

La fonction tanh() sur la sortie permet de passer relativement vite d’un état a l’autre (-1.0 / +1.0 ), par une transition douce.

On peut essayer de modifer la partie du code :

commenté : //  net->neuron=tanh(net->neuron);
remplacé par : net->neuron=(net->neuron>0.0)? 1.0:-1.0;

Dans ces conditions, le réseau converge 2 fois plus vite , et son graphe devient :

.. radical..

On peut aussi essayer avec :

if(net->neuron>1.0) net->neuron=1.0;
if(net->neuron<-1.0) net->neuron=-1.0;

On obtient :

314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808

December 11, 2016

Neural net,deep learning,bases en C, part 3

Filed under: linux, neuron — Tags: , , , , , , — admin @ 7:55 pm
Pour continuer avec les posts précédents, et en gardant la configuration entrées/ expected formula ,

On peut tracer la sortie du reseau, et les états des variables back[ ] pour chaque entrées :

en abcisses, l’angle ‘ang’ , axe Y gauche pour ‘back A,B,C’ , axe Y droit pour ‘neuron’

Si, on modifie la valeur de inA (qui est le bias) de -1.0 , à -2.0 , sans modifier le reseau existant. il répond alors de la façon suivante :

On voit que la réponse a été translatée de +1.0 sur Y , ce qui est cohérent avec la valeur modifiée du bias , de -1.0 a -2.0 (elle est multipliée par approximative -1.0 (poids de l’entrée A )

Mais ce qui est remarquable, c’est la modifcation de la variable back pour A : elle est passée d’une valeur négative a une valeur positive différente.
On va faire effectuer de nouveau une suite de calculs avec le reseau, en gardant les poids calculés par l’apprentissage, et faire varier l’entrée A ( le bias) par des valeurs comprises en -4.0 et +4.0 ( tout en gardant en tete que la valeur originale du bias , pour ce reseau, est de -1.0 )

Ce qui donne :

On voit que back A , décroit jusqu’a un minima, puis croit de nouveau .
Pour être précis, on réduit la variation de l’entrée A entre -1.5 et -0.5 :

Le minima pour back A est situé entre deux passage par 0 de cette variable back[ ].
On change l’axe X pour qu’il représente la variable input A , au lieu des angles pour les cos/sin :

… clairement, BACK pour A passe par zéro en 2 points :

  • pour une valeur inputA de -1.0
  • pour une valeur inputA de 0.0
la première est la valeur de bias initiale ( -1.0) qui est solution de l’apprentissage qu’on a appliqué au reseau
la deuxième est le résultat d’un passage à ZERO de l’entrée A , puisque back est calculé selon la formule vue précédement :
n->back[k]=n->neuron*n->part[k]*n->in[k];

…Si in[k] passe par zéro, back[k] est nul, quelle que soit la valeur du reste de sa formule.

Pour cette raison, on va modifier la fonction BACK() de façon à utiliser une partie seulement de la fonction existante :

n->part[k]=(fabs(n->w[k])/n->wtot);	// proportion							// assume w always positive
n->ward[k]=n->error*n->w[k];// erreur * poids
n->back[k]=n->error*n->in[k];// erreur * valeur d'entree

Pour ça, on modifie la structure du reseau, et on crée une nouvelle fonction backWARD :

// 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* delta;
	//
	//uint32_t genre;
	//
	float wtot;			// total input weights
	//
	uint64_t epoch;
	uint64_t internal;
} reso;

nouvelle fonction backward:

void RESO_backWARD(reso* n,float expected)
{
	uint32_t k;
	n->error=n->neuron-expected;	// actual_value - expected_value
	//
	for(k=0;k<n->synapses;k++)
	{
		n->part[k]=(fabs(n->w[k])/n->wtot);	// proportion							// assume w always positive
		n->ward[k]=n->error*n->w[k];// erreur * poids
		n->back[k]=n->error*n->in[k];// erreur * valeur d'entree
	}
	n->epoch++;
}

Pour terminer, un autre graphe d’un réseau pour lequel la valeur de BIAS était fixée à -2.5.

  • On la fait varier de -10.0 a 0.0, en fixant les 2 autres entrées à un état déterminé et connu

Sur le graphe, on peut voir back , ward et error (en abcisse, la valeur d’entrée du bias (nominal -2.5), les valeurs de ward sont sur l’axe Y de droite, celles de back et error sur l’axe Y de gauche
Dans le cas ou les valeurs des 2 autres entrées provoquent une sortie attendue à +1.0 :

Puis dans le cas ou les valeurs des 2 autres entrées provoquent une sortie attendue à -1.0 :

314159265358979323846264338327950288
419716939937510582097494459230781640
628620899862803482534211706798214808
« Newer PostsOlder Posts »

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