- initial import
git-svn-id: http://moon:8086/svn/mips@1 a8ebac50-d88d-4704-bea3-6648445a41b3
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
/***************************************************************************
|
||||
- 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* <c>1998 Thomas Hasenknopf */
|
||||
/* Listing zu "Künstliche Intelligenz, Teil 3 */
|
||||
/* Elektronik, Heft 7/2000 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#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;n<NumberNeurons;n++) { /* Init. der Neuronen */
|
||||
L->N[n].NumberInputs=NumberInputs;
|
||||
L->N[n].F=ActFct; /* Zuweisung von F */
|
||||
L->N[n].Fd=DerivFct; /* Zuweisung von F' */
|
||||
for(i=0;i<NumberInputs;i++) { /* Init. der Gewichte */
|
||||
L->N[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;m<L->NumberNeurons;m++) {
|
||||
N=L->N[m];
|
||||
n=0.0;
|
||||
for(i=0;i<N.NumberInputs;i++) { /* Summieren d. gewichteten Eingänge */
|
||||
n+=Input[i]*N.w[i];
|
||||
}
|
||||
n+=N.b; /* Summieren der Schwellwerte */
|
||||
N.n=n; /* Neuronenaktivierung */
|
||||
N.a=N.F(n); /* Aufruf der Aktivierungsfunktion */
|
||||
L->N[m]=N;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayNeuron(Neuron *N) {
|
||||
int i;
|
||||
for(i=0;i<N->NumberInputs;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;i<Net->NumberLayers;i++) {
|
||||
printf("\n>>>> Layer %d <<<<\n",i);
|
||||
for(m=0;m<Net->L[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;epoch<MAX_EPOCH;epoch++)
|
||||
{
|
||||
sse=0.0;
|
||||
printf("Epoch %d\n",epoch);
|
||||
for(set=0;set<numSets;set++)
|
||||
{
|
||||
/* Vorwaertsvermittlung */
|
||||
for(layer=0;layer<numLayers;layer++)
|
||||
{
|
||||
if(layer==0)
|
||||
{
|
||||
SimuLayer(&Input[set*inputs],&Net->L[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0;i<Net->L[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;m<numNeurons;m++)
|
||||
{
|
||||
pthis=&Net->L[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;n<Net->L[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;layer<numLayers;layer++)
|
||||
{
|
||||
numNeurons=Net->L[layer].NumberNeurons;
|
||||
for(m=0;m<numNeurons;m++)
|
||||
{
|
||||
pthis=&Net->L[layer].N[m];
|
||||
for(i=0;i<pthis->NumberInputs;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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user