/*************************************************************************** - description ------------------- begin : Sun Mar 12 2000 copyright : (C) 2000 by email : ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*************************************************************************** Backpropagation.cpp - description ------------------- begin : Sun Mar 12 2000 copyright : (C) 2000 by email : ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*************************************************************************** Backpropagation.cpp - description ------------------- begin : Fri Mar 10 2000 copyright : (C) 2000 by email : ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* 1998 Thomas Hasenknopf */ /* Listing zu "Künstliche Intelligenz, Teil 3 */ /* Elektronik, Heft 7/2000 */ #include #include #include #include #define MAX_NEURON_INPUTS 64 #define MAX_NEURON_PER_LAYER 512 #define MAX_LAYER_PER_NET 16 #define MAX_EPOCH 10000 typedef struct NF{ /* Definition eines Neurons */ int NumberInputs; /* Anzahl der Neuroneneingänge */ double w[MAX_NEURON_INPUTS]; /* Gewichtsfaktoren (max. 16) */ double dw[MAX_NEURON_INPUTS]; /* letzte Gewichtsaenderungen */ double b; /* Schwellwert */ double db; /* letzte Schwellwertaenderung */ double n; /* Neuronenaktivierung */ double a; /* Ausgang des Neurons */ double ebp; /* Rückvermittlungs-Fehler */ double (*F)(double); /* Zeiger auf Aktivierungsfunktion */ double (*Fd)(struct NF*); /* Zeiger auf Ableitungsfunktion */ } Neuron; typedef struct { /* Definition einer Neuronenschicht */ int NumberNeurons; /* Anzahl der Neuronen in der Schicht */ Neuron N[MAX_NEURON_PER_LAYER]; /* Neuronen der Schicht (max. 16) */ } NeuronLayer; typedef struct { /* Definition eines Neuronennetzwerks */ int NumberLayers; /* Anzahl der Schichten im Netzwerk */ NeuronLayer L[MAX_LAYER_PER_NET]; /* Schichten im Netzwerk (max. 8) */ } NeuronNet; typedef struct { /* Trainingsergebnis */ double sse; /* Summierter quadratischer Fehler */ unsigned long epochs; /* Trainingsepochen */ int overflow; /* Ziel des Trainings verfehlt? */ } TrainingResult; double LinearFunction(double x) { return x; } double LinearDerivative(Neuron *N) { return 1; } double TanhDerivative(Neuron *N) { return (1.0-pow(N->a,2)); } /* Initialisieren einer Neuronenschicht mit Zufallszahlen */ void InitLayer(int NumberInputs, int NumberNeurons, NeuronLayer *L, double(*ActFct)(double), double(*DerivFct)(Neuron*)) { int i,n; L->NumberNeurons=NumberNeurons; srand(1); /* Init. des Generators */ for(n=0;nN[n].NumberInputs=NumberInputs; L->N[n].F=ActFct; /* Zuweisung von F */ L->N[n].Fd=DerivFct; /* Zuweisung von F' */ for(i=0;iN[n].w[i]=rand()*2.0/RAND_MAX-1.0; } L->N[n].b=rand()*2.0/RAND_MAX-1.0; /* Init. des Schwellwertes */ } } Neuron N; /* Simulation einer Neuronenschicht */ void SimuLayer(double *Input, NeuronLayer *L) { int m,i; double n; for(m=0;mNumberNeurons;m++) { N=L->N[m]; n=0.0; for(i=0;iN[m]=N; } } void DisplayNeuron(Neuron *N) { int i; for(i=0;iNumberInputs;i++) { printf("w[%d] = %lf\n",i,N->w[i]); /* Ausgabe der Eingangsgewichte */ } printf("b = %lf\n",N->b); /* Ausgabe des Schwellwertes */ } void DisplayNet(NeuronNet* Net) { int i,m; for(i=0;iNumberLayers;i++) { printf("\n>>>> Layer %d <<<<\n",i); for(m=0;mL[i].NumberNeurons;m++) { printf("Neuron %d \n",m); DisplayNeuron(&Net->L[i].N[m]); } } } void DisplayTrainingResult(TrainingResult Result) { printf("\nTraining %ld epochs, SSE=%e:\n",Result.epochs,Result.sse); if(Result.overflow) { printf("Training not succeeded. Change training parameters!\n"); } } Neuron *pthis; TrainingResult TrainNet(int NumberTargets, double *Input, double *Target, NeuronNet *Net, double Lrate, double Mf, double SseMax) { long layer,epoch,inputs,outputs,set,numSets,numLayers,numNeurons,i,m,n; double sse,inp[MAX_NEURON_INPUTS],err; TrainingResult result; numLayers=Net->NumberLayers; outputs=Net->L[numLayers-1].NumberNeurons;/* Anz. d. Netzwerkausgaenge*/ numSets=NumberTargets/outputs; /* Trainings-Wertepaare*/ inputs=Net->L[0].N[0].NumberInputs; /* Anz. d. Netzwerkeingaenge*/ /* Backpropagation Algorithmus */ for(epoch=0;epochL[0]); } else { for(i=0;iL[layer-1].NumberNeurons;i++) { inp[i]= Net->L[layer-1].N[i].a; } SimuLayer(&inp[0],&Net->L[layer]); } } /* Fehlerrückvermittlung */ for(layer=numLayers-1;layer>=0;layer--) { numNeurons=Net->L[layer].NumberNeurons; for(m=0;mL[layer].N[m]; if(layer== (numLayers-1)) { /* Ausgangsschicht */ err=Target[set*outputs+m] - pthis->a; sse+=pow(err,2); } else { /* verborgene Schicht */ err=0; for(n=0;nL[layer+1].NumberNeurons;n++) { err+=Net->L[layer+1].N[n].w[m]*Net->L[layer+1].N[n].ebp; } } pthis->ebp=pthis->Fd(pthis)*err; } } /* Gewichte berechnen */ for(layer=0;layerL[layer].NumberNeurons; for(m=0;mL[layer].N[m]; for(i=0;iNumberInputs;i++) { if(layer==0) { /* Eingangsschicht */ pthis->dw[i]=(1.0-Mf)*pthis->ebp*Input[set*inputs+i]*Lrate + Mf*pthis->dw[i]; } else { pthis->dw[i]=(1.0-Mf)*pthis->ebp*Net->L[layer-1].N[i].a*Lrate + Mf*pthis->dw[i]; } pthis->w[i]+=pthis->dw[i]; } pthis->db=(1.0-Mf)*pthis->ebp*Lrate + Mf*pthis->db; pthis->b+=pthis->db; } } } if(sse<=SseMax) break; } result.sse=sse; result.epochs=epoch; result.overflow=(epoch==MAX_EPOCH); return result; } double P[]={-1.0, -0.5, 0.0, 0.2, 0.5, 1.0, -0.6}; double T[]={ 1.0, 0.5, 0.0, 0.0, 0.3, 0.2, 0.1}; NeuronNet Net; void main(void) { TrainingResult result; unsigned long epochs; /* Definition eines 3-lagigen Netzwerks mit 1 Eingang und 1 Ausgang, 2 verborgenen nichtlin. Schichten und lin. Ausgangsschicht */ Net.NumberLayers=3; /* 1 Input 4 Neuronen */ InitLayer(1,4,&Net.L[0],tanh,TanhDerivative); /* 4 Input 2 Neuronen */ InitLayer(4,2,&Net.L[1],tanh,TanhDerivative); /* 2 Inputs 1 Neuron */ InitLayer(2,1,&Net.L[2],LinearFunction,LinearDerivative); /* Lrate=0.7, Momentfaktor=0.8, SSE=0.005 */ result=TrainNet(sizeof(T)/sizeof(double),P,T,&Net,0.7,0.8,0.005); DisplayNet(&Net); DisplayTrainingResult(result); }