PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Lernen aus Erfahrung?



hirnfrei
19.01.2016, 15:44
Mahlzeit!

Ich spiele seit ein paar Tagen mit OpenCV unter Linux mit C/C++ rum. Das funktioniert recht gut muss ich sagen. Webcam zugriff, Gesichtserkennung, Gesichtsvergleich klappt alles schon recht gut.

Auf die Idee bin ich eigentlich gekommen um einer Eigenbaudrohne zu zeigen das ich ich bin. Für autonome Verfolgung. Jetzt stellt sich jedoch das Problem ein, die Software läuft schon so halbwegs, aber um weiter zu machen fehlt mir eben noch die Drohne. Deshalb habe ich mal bisschen weiter geschaut und gesehen, dass man mit OpenCV auch Entscheidungsbäume, neuronale Netze usw. aufbauen kann.

Jetzt käme an dieser Stelle meine Frage. Hat hier schon jemand Erfahrung mit solchen ANwendungen gemacht? Mir schwebt da nämlich etwas vor und ich denke da könnte mir etwas Hilfe nicht schaden.

Ich würde gerne ein Programm entwickeln, was prinzipiell nur ein paar gundsätzliche Dinge kann, versteht, beherrscht oder wie auch immer man das in dem Zusammenhang nennen mag. So eine Art minimales Unterbewusstsein. Dazu würde ich mit einem Raspi, ein kleines Autochen bauen. Das Programm soll prinzipiell nur die Möglichkeit haben die Pins anzusteuern, bzw. von dort Daten zu empfangen, sowie eben Gesichter und Gegenstände erkennen können. Ansonsten sollte es möglichst leer sein. Das Programm sollte also möglichst Alles erlernen müssen.

In etwa stelle ich mir das so vor. Ich gebe ihm ein Ziel vor. Sagen wir mal, auf einem Stick befindet sich ein Bild von einem Objekt, ein roter Würfel oder so und die Aufgabe, sich zu diesem Würfel zu bewegen. Den Rest sollte das Programm dann selbst erlernen. Es kann quasi instinktiv die Pins ansteuern und sehen was dann passiert. Das müsste dann natürlich als Erfahrung abgespeichert werden. So soll zum Beispiel dann bei Aktivierung von sagen wir Pin10 eine LED leuchten, um Nachts fahren zu können. Das soll dann eben als Erfahrung abgespeichert (wäre das dann eine Neurone?) werden. Eine Erfahrung die dem Programm sagt das es für die Fortbewegung nicht dienlich ist. Wird dann irgendwann der Pin aktiviert der einem anderen Microcontroler den Befehl gibt vorwärts zu fahren soll er das als die dienlich für das Problem anspeichern usw.

Das Ganze hat letztlich kein festes Ziel. Ich will damit also kein bestimmtes Gerät bauen sondern wirklich erleben wie das Programm lernt. Wie es mit wachsender Erfahrung auch kompliziertere Aufgaben lösen kann usw. So gesehen, anschalten und schauen wo hin es sich entwickeln kann, ob es sich entwickeln kann usw.

Dazu müsste ich aber wissen, wie baut man so ein "leeres" neurales Netz? Die Beispiele von OpenCV erklären es für mich nicht, zumindest kann ich nicht so wirklich den Zusammenhang erkennen von Kreisen, Linien und Quadrate verschieben zu so etwas. Auch werde ich aus dem Trainieren noch nicht ganz schlau.

Gibt es denn hier jemand der das Wissen hat und sich zutraut es mir näher zu bringen, bzw. die Lust hat mit da zu helfen?

HeXPloreR
19.01.2016, 17:18
Hallo hirnfrei,

schau doch mal auf YouTube Hier >>https://www.youtube.com/watch?v=UbktAxbUPnk

oder

hier >>https://www.youtube.com/watch?v=7LouOajwXiI

Viele Grüße
Jörg

i_make_it
19.01.2016, 19:02
Wow Wissen lernen und Methoden lernen auf einmal.
Da willst Du ja von Anfang an gleich ganz nach vorne bei der KI Forschung.
Also zum erlernen von Wissen und Bewerten von Daten, Schau dir mal die Forschungspuplikationen zu IBMs Watson an. die sind da mit am weitesten.
Beim Erlernen und Verbessern von Methoden, such mal nach genetischen Algorithmen und Evulotionsstrategien.
Bsp.: http://www.techfak.uni-bielefeld.de/ags/wbski/lehre/digiSA/WS0304/IntAlg/Ausarbeitungen/GAES.pdf
Ein leeres neuronales Netz an sich bekommt man nicht so ohne weiteres hin. In der Regel entscheidet man sich schon mal für die Anzahl der Schichten und den Netztyp.
Bsp.: http://www.neuronalesnetz.de/netztypen.html
Je nach Vorbildung kann das eine längerfristige, spannende Beschäftigung werden.

http://www.codeplanet.eu/tutorials/csharp/70-kuenstliche-neuronale-netze-in-csharp.html

hirnfrei
19.01.2016, 19:14
Ich finde es schon lustig wie Jörn Loviscach zu nahezu allen Themen die mich interessieren irgend ein Video am Start hat. Sehr lustig, vor Allem weil ich das Meiste da auch immer recht schnell verstehe.

Ich hätte also Deep Learning da in der Planung. Das wird Lustig, da ich kaum einen Keller voll Grafikkarten an mein Projekt dran basteln kann. Aber wie er sagte, es muss nicht immer neuronal sein. Mal schauen.

Das mit dem Schwarm ist aber auch eine lustige Idee.

Nur wie nun beim Deep Learning nun wirklich gelernt wird hat er leider nicht gesagt. Nur das es automatisch geht, aber irgendwie will sich mir das nicht erschliessen.

Sehr interessant ist aber auch die Idee, das ausgegebene Signal wieder an den Input zu legen. Ist so ein wenig wie damals meine ersten BASIC Programme. Solange man nichts gedrückt hat ist auch nichts passiert. Demnach auch die Uhr nicht weiter gelaufen. Dann in C mit der while schleife zum Beispiel ist das Programm ja durchgehend gelaufen und hat auch die Uhr aktualisiert. Wäre interessant zu sehen ob das was raus kommt auch zum eigenen Lernen genutzt werden kann. Wäre ja praktisch in der Zeit wo es nicht genutzt wird das es sich selbst beschäftigt.

Bin für weitere Informationen durchaus dankbar ;)

- - - Aktualisiert - - -


Je nach Vorbildung kann das eine längerfristige, spannende Beschäftigung werden.

Na klar will ich ganz nach vorne ;). Besser ein hohes Ziel gesteckt und nur bis zur Hälfte gekommen wie gleich ein kleines Ziel gesteckt und doch nicht weiter gekommen. Kein Plan wie weit ich das, gerade auch wegen der Hardware, realisieren kann, aber wenn ichs mir nicht angucke und ausprobiere werde ich es nie erfahren. Vielleicht kommt ja ein Nobelpreis bei raus, oder nur ein "Das habe ich auch mal versucht". Gibt schlimmeres um seine Zeit zu verbringen.

Und wie gesagt, es ist super spannend und fasziniert mich sehr. Es gibt definitiv sinnlosere Sachen mit denen man sich beschäftigen kann ;).

Und danke für die Infos.

Moppi
08.09.2018, 10:24
Falls ich hier mit was falsch liege, bitte berichtigen.



In etwa stelle ich mir das so vor. Ich gebe ihm ein Ziel vor. Sagen wir mal, auf einem Stick befindet sich ein Bild von einem Objekt, ein roter Würfel oder so und die Aufgabe, sich zu diesem Würfel zu bewegen. Den Rest sollte das Programm dann selbst erlernen. Es kann quasi instinktiv die Pins ansteuern und sehen was dann passiert.

Hierzu gibt es zum Beispiel das Kameramodul Jevois A33. Wenn ich das bis jetzt richtig verstanden habe, kann man damit das tun: Bilder von Objekten speichern und wiedererkennen lassen und verfolgen. Der eingebaute Prozessor macht es möglich. Das Kameramodul gibt dann die Ergebnisse aus (seriell als Daten vermutlich). Anhand der Daten kann man ausmachen, wo sich das Objekt relativ zum Kameramodul befindet und vermutlich auch, um welches Objekt es sich handelt.


Das müsste dann natürlich als Erfahrung abgespeichert werden. So soll zum Beispiel dann bei Aktivierung von sagen wir Pin10 eine LED leuchten, um Nachts fahren zu können. Das soll dann eben als Erfahrung abgespeichert (wäre das dann eine Neurone?) werden. Eine Erfahrung die dem Programm sagt das es für die Fortbewegung nicht dienlich ist. Wird dann irgendwann der Pin aktiviert der einem anderen Microcontroler den Befehl gibt vorwärts zu fahren soll er das als die dienlich für das Problem anspeichern usw.

Controller-Anschlüsse auf LOW oder HIGH setzen. Kommt am Controller an und kann per Software erfasst werden. Alle Anschlusszustände in einem Array speichern. Dann müsste man Regeln aufstellen (wenn Werte in dem Array soundso, dann ist das Ergebnis - best. Variable bspw. - soundso). Sowohl Werte aus dem Array, als auch das Ergebnis der vorherigen Regel, fliessen in folgende Regeln ein. Die Regeln können nicht immer willkürlich abgearbeitet werden, deshalb müssen sie ordnungsfähig sein (nummeriert), weil es sein kann, dass eine Regel nur angewendet werden kann, wenn andere Regeln zuvor und weitere erst danach angewendet werden. Je mehr Regeln man hinzufügt, desto genauer wird das "Problem" gelöst. Manche Regeln können nur unter bestimmten Voraussetzungen zu richtigen Ergebnissen führen. Deshalb müssen Regeln über die Anwendung von Regeln entscheiden. Das führt zu Regelbäumen und Verzweigungen zwischen den Bäumen.


Das Ganze hat letztlich kein festes Ziel. Ich will damit also kein bestimmtes Gerät bauen sondern wirklich erleben wie das Programm lernt. Wie es mit wachsender Erfahrung auch kompliziertere Aufgaben lösen kann usw. So gesehen, anschalten und schauen wo hin es sich entwickeln kann, ob es sich entwickeln kann usw.
Dazu müsste ich aber wissen, wie baut man so ein "leeres" neurales Netz? Die Beispiele von OpenCV erklären es für mich nicht, zumindest kann ich nicht so wirklich den Zusammenhang erkennen von Kreisen, Linien und Quadrate verschieben zu so etwas. Auch werde ich aus dem Trainieren noch nicht ganz schlau.

Ich denke, hier bewegen wir uns in Ordnungen, schon bei geringen Anforderungen an eine Drohne, die Erkennen und Verfolgen lernen kann, ähnlich denen eines neuronalen Netzes, das Schach spielen lernt. Denn es gibt nicht wenige Sensor-Inputs und Aktoren die gesteuert werden sollen.

HaWe
08.09.2018, 10:50
das Topic ist ja nun schon ein paar Jahre alt, aber für Lernen per KI gibt es u.a. diese beiden bewährten Herangehensweisen:
a) Lernen durch Training (assisted): Muster werden gezeigt, die wiedererkannt werden sollen. Netztyp: mehrschichtige Perzeptron-Netze (z.B. Backpropagation)
b) Lernen durch eigenes schrittweises Probieren und Annähern des Ziels bis zum Erfolg (non-assisted): G-Learning.

Beides wurde schon erfolgreich auf MCUs gemacht, ein ARM Prozessor ist dabei zu empfehlen wegen Speicher (v.a. für Backpropagation) und Ausführungsgeschwindigkeit (für beide).

Moppi
08.09.2018, 11:02
Macht doch nichts, das paar Jahre alt ist. Ich vermisse konkretere Lösungsansätze.

Dann brauchen wir jetzt nur eine Informationen zu: "wurde schon erfolgreich auf MCUs gemacht".

Welche genau, von Wem und Wo? Evtl. Bauteile, Beschaltung, Programmierung, Erklärung im Detail?

HaWe
08.09.2018, 11:58
die Backpropagation von mir, hatte ich schon mal hier gepostet (einschichtige Netze u.a. für Lego NXT, und 2-Layer Backpropagation Netz für Arduino Due, z.B. auch rückgekoppelt vom "Elman" oder "Jordan" Typ); meines Wissen war ich der erste weltweit, der dies veröffentlciht hat 8) ).
(Das Programm ist sehr groß, die hiesige Forumsoftware erlaubt keinen solchen Programm-Upload; hatte ich gegenüber Frank etc. schon öfters reklamiert, auch für andere Dateien; ohne Reaktion leider. Das Mindstorms-Forum, wo auch der Code ursprünglich veröffentlicht wurde, ist aber z.Zt. offline, der Site-Admin und Gründer möchte es aber höchstwahrscheinlich nach der letzten Datenschutz-Verordnung nicht mehr weiter supporten)


Das G-Learning wurde von anderen schon auf dem Lego EV3 gemacht, zum Laufenlernen für einen Mehrfüssler, habe aber auch schon andere Projekte mal gesehen, z.B. Wegefindung in kleinen "Labyrinthen".

Moppi
08.09.2018, 12:52
Das ist doch schon ganz prima, dann machen wir einen Querverweis an der Stelle, damit der Leser auch weiter kommt:

da hatten wir einen Laufrobotter (https://www.roboternetz.de/community/threads/69790-Vierfuß-Laufroboter-ohne-Kniegelenk-Möglich),

und wir hatten in diesem Thread (https://www.roboternetz.de/community/threads/67798-weltweit-erstes-Neuronales-Jordan-Netz-auf-Arduino-Due-%21?highlight=Backpropagation) ein von Counterfeiter eingestelltes Video, was praktisch eine Demonstration zeigt.

Für den LEGO NXT und neuronales Netz (http://www.robotc.net/forums/viewtopic.php?f=15&t=557) habe ich auch etwas gefunden


Nachtrag:

wobei ich Differenzierung für gut halte:

1) künstliche neuronale Netze
2) Funktionsweise neuronaler Netze
3) Implementation auf Lego NXT oder auf Atmegas / Arduinos etc.

Zum ersten Fall will ich gar nichts weiter schreiben, weil die eigentliche Nachbildung menschlicher Neuronen ein Fall für sich ist.

Zum Zweiten kann man anmerken, dass man die Funktionsweise eines neuronalen Netzes hinterfragt, bzw. entwickelt. Dafür gibt es etablierte Ansichten, hinter denen auch jeweils bekannte Namen stehen. Hier wird das Regelwerk beleuchtet, nach dem künstliche Intelligenz als solches funktionieren soll und kann: Lösungsansätze, wie man Regeln miteinander verknüpft, damit die Verbindung insgesamt dazu führt, dass etwas erlernt werden kann.

Beim dritten Fall geht es darum, wie man nun diese Regeln aus dem zweiten Fall auf gängige Ausführungseinheiten (CPU / Controller) überträgt. Hier greift man als nun auf ein existierendes Regelwerk zurück (Maschinensprache des Controllers z.B.) um diese speziellen Regeln auf die unterste Ausführungsschicht drauf zu packen, die ermöglichen, dass mein Computer / Controller etwas erlernen kann.

Nachtrag:

Da der dritte Fall viel Overhead erzeugen dürfte und zusätzliche Rechenzeit (Takte), sowie Speicherplatz kostet, sind zukünftig vor allem solche Chips interessant, wie hier vorgestellt (https://www.spektrum.de/news/der-1-million-neurone-computerchip/1303980):

Eine Million simulierter Neurone haben IBM-Forscher auf einem Chip untergebracht. Sein biologisches Vorbild macht "TrueNorth" zum Energiesparwunder. Forscher bauten "Kerne" von je 256 Neuronen und 256 x 256 Synapsen auf, in denen alle nötigen Elemente verkapselt sind. Über 4000 Stück davon passen auf den Chip.

HaWe
08.09.2018, 14:58
/*
Backpropagation Netz / net
optimiert für Arduino Due
Version JON 0060

(C) HaWe 2015

to do:
- save memory to SD file
- plug real physical sensors
- pre-emptive Multitasking (currently not possible for Due)
*/



#include <SPI.h>
#include <SD.h>
#include <UTFT.h>
#include <ardustdio.h>
#include <malloc.h>
#include <DueTimer.h>



//-------------------------------------------------------------------------------------
// neural net size
#define NMAXIN 108 // max number of inputs (sensors)
#define NMAXHID 20 // max number hidden layer neurons
#define NMAXOUT 20 // max number output layer neurons

#define NMAXPAT 70 // <<< max number of possibly trained patterns;



//-------------------------------------------------------------------------------------
// neural net: neurons and patterns

float WeightLIn[NMAXIN+1][NMAXHID+1];
float WeightLOut[NMAXHID+1][NMAXOUT+1];

float Input[NMAXPAT+1][NMAXIN+1];
float Target[NMAXPAT+1][NMAXOUT+1];
float Output[NMAXPAT+1][NMAXOUT+1];
//float Contxt[NMAXOUT+1]; // Jordan-net: neuron-number == output-number

float currIn[NMAXIN+1], // currently polled inputs
inbuf[NMAXIN+1]; // intermediate stored inputs for editing
float currOut[NMAXOUT+1], // currently computed net outputs
outbuf[NMAXOUT+1]; // intermediate stored outputs

int16_t NumInput = NMAXIN, NumHidden = NMAXHID, NumOutput = NMAXOUT;
int16_t NumPattern = 0; // <<< number of actually trained patterns;

int32_t epoch; // training measures
uint32_t BPTime;
float Error;





//-------------------------------------------------------------------------------------
// TFT LCD
//UTFT myGLCD(Model, SDA=MISO, SCL, CS, RESET, RS)
//UTFT myGLCD(QD220A, A2, A1, A5, A4, A3); // adjust model parameter and pins !
UTFT myGLCD(QD220A, 50, 49, 52, 0, 51); // A0->Vc (LED), A4->BoardReset

extern uint8_t SmallFont[];

#define LCDWhiteBlack() {myGLCD.setColor(255, 255, 255); myGLCD.setBackColor( 0, 0, 0);}
#define LCDNormal() {myGLCD.setColor(255, 255, 255); myGLCD.setBackColor( 0, 0, 0);}
#define LCDInvers() {myGLCD.setColor( 0, 0, 0); myGLCD.setBackColor(255, 255, 255);}
#define LCDWhiteRed() {myGLCD.setColor(255, 255, 255); myGLCD.setBackColor(255, 0, 0);}
#define LCDRedBlack() {myGLCD.setColor(255, 0, 0); myGLCD.setBackColor( 0, 0, 0);}
#define LCDYellowBlue() {myGLCD.setColor(255, 255, 0); myGLCD.setBackColor( 64, 64, 64);}
uint8_t fontwi= 8;
uint8_t fonthi=10;
int16_t LCDmaxX , LCDmaxY ; // display size
int16_t _curx_, _cury_, // last x,y cursor pos on TFT screen
_maxx_, _maxy_; // max. x,y cursor pos on TFT screen
char wspace[50]; // line of white space

void lcdcls() { myGLCD.clrScr(); _curx_ =0; _cury_ =0; }
void curlf() { _curx_=0; if( _cury_ <=(LCDmaxY-10) ) _cury_+=10; else _cury_=0; }

void lcdprintxy(int16_t x, int16_t y, char * str) {
myGLCD.print(str, x, y);
_curx_ = x + strlen(str)*fontwi;
_cury_ = y; // check for line overflow!
}

void curxy(int16_t x, int16_t y) {_curx_ = x;_cury_ = y;}

void lcdprint(char * str) {
myGLCD.print(str, _curx_, _cury_);
_curx_ = _curx_ + strlen(str)*fontwi;
//_cury_ = _cury_; // check for line overflow!
}

//-------------------------------------------------------------------------------------







//-------------------------------------------------------------------------------------
// SD Card
#define SD_CSpin 53
File myFile;
char fname[64];
//-------------------------------------------------------------------------------------




//-------------------------------------------------------------------------------------
// misc
#define TimerMS() millis()
#define LRAND_MAX 32767
#define srand(seed) randomSeed(seed)
#define rand() random(LRAND_MAX)
#define rando() ((float)rand()/(LRAND_MAX+1))
int32_t RSeed;

#define pswitchon(pin) (!digitalRead(pin)) // btn press for pinMode(pin, INPUT_PULLUP)
#define pswitchoff(pin) ( digitalRead(pin)) // btn press for pinMode(pin, INPUT_PULLUP)
#define pbtn(pin) (!digitalRead(pin)) // alias
//-------------------------------------------------------------------------------------






//-------------------------------------------------------------------------------------
// user interface: button pad control pins
#define PIN_ESC 13
#define PIN_UP 12
#define PIN_OK 11
#define PIN_DN 4 // instead opt.: 6
#define PIN_LE 3 // instead opt.: 5
#define PIN_RI 2

// pins 10,9,8,7 : motor
// pins 22 - 37 : motor
// pins 49 - 51 : LCD TFT
// pin 53: SD CS

// available: 5+6, 38-48 for digital touch pins

//-------------------------------------------------------------------------------------
int16_t btnpressed() {
return ( pbtn(PIN_ESC)||pbtn(PIN_UP)||pbtn(PIN_OK)||pbtn(PI N_DN)||pbtn(PIN_LE)||pbtn(PIN_RI) );
}
//-------------------------------------------------------------------------------------
int16_t getbtn() {
int16_t choice= -1;

while (! btnpressed() ); // wait until button pad pressed

if( pbtn(PIN_ESC) ) choice = PIN_ESC;
if( pbtn(PIN_UP) ) choice = PIN_UP;
if( pbtn(PIN_OK) ) choice = PIN_OK;
if( pbtn(PIN_DN) ) choice = PIN_DN;
if( pbtn(PIN_LE) ) choice = PIN_LE;
if( pbtn(PIN_RI) ) choice = PIN_RI;

while ( btnpressed() ); // wait until button pad released

return choice;
}


//-------------------------------------------------------------------------------------
// misc. tools

int16_t toggleup(int16_t lo, int16_t hi, int16_t val ) {
if ( val < hi ) val++;
else val = lo;
return val;
}

int16_t toggledn(int16_t lo, int16_t hi, int16_t val ) {
if ( val > lo ) val--;
else val = hi;
return val;
}




//-------------------------------------------------------------------------------------
// motor control

#define MAXMOTORS 4 // max number of encoder motors at Arduino Uno=2 // Due=6 // Mega=8

// motor 0
#define pinenc0A 22 // enc0A yellow
#define pinenc0B 23 // enc0B blue
#define pinmot0d1 24 // dir0-1 <<
#define pinmot0d2 25 // dir0-2
#define pinmot0pwm 10 // pwm enable0

// motor 1
#define pinenc1A 26 // enc1A yellow
#define pinenc1B 27 // enc1B blue
#define pinmot1d1 28 // dir1-1 <<
#define pinmot1d2 29 // dir1-2
#define pinmot1pwm 9 // pwm enable1


// motor 2
#define pinenc2A 30 // enc2A yellow
#define pinenc2B 31 // enc2B blue
#define pinmot2d1 32 // dir2-1 <<
#define pinmot2d2 33 // dir2-2
#define pinmot2pwm 8 // pwm enable2

// motor 3
#define pinenc3A 34 // enc3A yellow
#define pinenc3B 35 // enc3B blue
#define pinmot3d1 36 // dir3-1 <<
#define pinmot3d2 37 // dir3-2
#define pinmot3pwm 7 // pwm enable3




//-------------------------------------------------------------------------------------
// motor bit patterns
const char COAST[]={0,0,0};
const char BREAK[]={0,0,1};
const char FWSLOW[]={0,1,0};
const char RVSLOW[]={0,1,1};
const char FWMED[]={1,0,0};
const char RVMED[]={1,0,1};
const char FWFAST[]={1,1,0};
const char RVFAST[]={1,1,1};

#define fwslow 20
#define rvslow -20
#define fwmed 60
#define rvslow -60
#define fwfast 100
#define rvfast -100


//================================================== ===================================
// SETUP ()
//================================================== ===================================
void setup() {
char sbuf[128]; // output string

Serial.begin(115200);

pinMode(PIN_ESC,INPUT_PULLUP);
pinMode(PIN_UP, INPUT_PULLUP);
pinMode(PIN_OK, INPUT_PULLUP);
pinMode(PIN_DN, INPUT_PULLUP);
pinMode(PIN_LE, INPUT_PULLUP);
pinMode(PIN_RI, INPUT_PULLUP);


myGLCD.InitLCD();
LCDmaxX=myGLCD.getDisplayXSize();
LCDmaxY=myGLCD.getDisplayYSize();
myGLCD.setFont(SmallFont);
_maxx_ = LCDmaxX / fontwi;
_maxy_ = LCDmaxX / fonthi;

memset(wspace, ' ', _maxx_);
wspace[_maxx_]='\0';
lcdcls();

sprintf(sbuf, "Serial ok, GLCD=%dx%d",LCDmaxX,LCDmaxY);
Serial.println(sbuf);
myGLCD.print (sbuf, 0, 0);

ResetNet();

RSeed = ( ((analogRead(A8)+1017)%100) * (TimerMS()% LRAND_MAX ) % LRAND_MAX );
srand(RSeed);

// # DEBUG
sprintf(sbuf, "Seed= %ld", RSeed);
myGLCD.print (sbuf, 0,10);
sprintf(sbuf, "Rand= %ld", rand() );
myGLCD.print (sbuf, 100,10);



// # DEBUG
memtest(20, "memtest: setup");

SetNetDefaultPatterns();
RefreshInputs(); // polls inputs and stores values to currIn[] array


//***********************************
//************************************************** *****************************
// debug: test different input sets
currIn[1]=1; //currIn[2]=0; currIn[3]=1; //currIn[4]=0; currIn[5]=0; currIn[6]=0; currIn[7]=0;
//************************************************** *****************************
//***********************************


ComputeMatrix(); // applies inputs to net and computes outputs to currOut[] array
TrainNet(); // basic training


}
//================================================== ===================================
//================================================== ===================================





//-------------------------------------------------------------------------------------
// analog range bit patterns
// returns 6 bits for ranges -32768...0...32767 or out of bounds (VOID==[32])
float Ana[64][8]={
{0,0,0,0,0,0,0,0}, // 0
{0,1,0,0,0,0,0,1}, // 0...1
{1,2,0,0,0,0,1,0}, // 1...2
{2,3,0,0,0,0,1,1},

{3,4,0,0,0,1,0,0},
{4,5,0,0,0,1,0,1},
{5,6,0,0,0,1,1,0},
{6,8,0,0,0,1,1,1},

{8,10,0,0,1,0,0,0},
{10,13,0,0,1,0,0,1},
{13,16,0,0,1,0,1,0},
{16,20,0,0,1,0,1,1},

{20,26,0,0,1,1,0,0},
{26,32,0,0,1,1,0,1},
{32,40,0,0,1,1,1,0},
{40,48,0,0,1,1,1,1},

{48,56,0,1,0,0,0,0},
{56,64,0,1,0,0,0,1},
{64,74,0,1,0,0,1,0},
{74,85,0,1,0,0,1,1},

{85,97,0,1,0,1,0,0},
{97,110,0,1,0,1,0,1},
{110,128,0,1,0,1,1,0},
{128,192,0,1,0,1,1,1},

{192,256,0,1,1,0,0,0},
{256,420,0,1,1,0,0,1},
{420,512,0,1,1,0,1,0},
{512,650,0,1,1,0,1,1},

{650,800,0,1,1,1,0,0},
{800,1024,0,1,1,1,0,1},
{1024,2048,0,1,1,1,1,0},
{2048,32767,0,1,1,1,1,1}, // <= SHORTMAX

{0,0,1,0,0,0,0,0}, // #32: VOID !
{0,-1,1,0,0,0,0,1}, // 0... -1
{-1,-2,1,0,0,0,1,0}, // -1...-2
{-2,-3,1,0,0,0,1,1},

{-3,-4,1,0,0,1,0,0},
{-4,-5,1,0,0,1,0,1},
{-5,-6,1,0,0,1,1,0},
{-6,-8,1,0,0,1,1,1},

{-8,-10,1,0,1,0,0,0},
{-10,-13,1,0,1,0,0,1},
{-13,-16,1,0,1,0,1,0},
{-16,-20,1,0,1,0,1,1},

{-20,-26,1,0,1,1,0,0},
{-26,-32,1,0,1,1,0,1},
{-32,-40,1,0,1,1,1,0},
{-40,-48,1,0,1,1,1,1},

{-48,-56,1,1,0,0,0,0},
{-56,-64,1,1,0,0,0,1},
{-64,-74,1,1,0,0,1,0},
{-74,-85,1,1,0,0,1,1},

{-85,-97,1,1,0,1,0,0},
{-97,-110,1,1,0,1,0,1},
{-110,-128,1,1,0,1,1,0},
{-128,-192,1,1,0,1,1,1},

{-192,-256,1,1,1,0,0,0},
{-256,-420,1,1,1,0,0,1},
{-420,-512,1,1,1,0,1,0},
{-512,-650,1,1,1,0,1,1},

{-650,-800,1,1,1,1,0,0},
{-800,-1024,1,1,1,1,0,1},
{-1024,-2048,1,1,1,1,1,0},
{-2048,-32768,1,1,1,1,1,1} // >= -SHORTMAX

};

//-------------------------------------------------------------------------------------

int16_t ana2bits(int16_t aval) { // return array index
int16_t i,j;
if(aval == 0) return 0;
else
if( aval > 32767 ) return 32; // VOID
else
if( aval < -32768 ) return 32; // VOID
else {
for (i=1; i<32; ++i) {
if ( (aval>Ana[0][i]) && (aval<=Ana[1][i]) ) return i;
}
for (i=32; i<64; ++i) {
if ( (aval<Ana[0][i]) && (aval>=Ana[1][i]) ) return i;
}
}
return 32;
}





//-------------------------------------------------------------------------------------
// mem test
extern char _end;
extern "C" char *sbrk(int i);
char *ramstart=(char *)0x20070000;
char *ramend=(char *)0x20088000;

//================================================== ===================================
void memtest(int ypos, char * str) {
char sbuf[128]; // output string

char *heapend=sbrk(0);
register char * stack_ptr asm ("sp");
struct mallinfo mi=mallinfo();

sprintf(sbuf,str);
Serial.println(); Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos);

sprintf(sbuf, "Dyn.RAM used: %-10ld ", mi.uordblks);
Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+10);

sprintf(sbuf, "Prg.stat.RAM used %-10ld ", & _end - ramstart);
Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+20);

sprintf(sbuf, "Stack RAM used %-10ld ", ramend - stack_ptr);
Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+30);

sprintf(sbuf, "Free mem: %-10ld ", stack_ptr - heapend + mi.fordblks);
Serial.println(sbuf); myGLCD.print(sbuf, 0, ypos+40);
myGLCD.print(wspace, 0, ypos+50);

}















//================================================== ===================================
// net: clear, set, reset, patch
//================================================== ===================================

void clrnetbuf() {
memset(inbuf, 0, sizeof(inbuf) );
memset(currIn, 0, sizeof(currIn) );
memset(outbuf, 0, sizeof(outbuf) );
memset(currOut, 0, sizeof(outbuf) );
}

//================================================== ===================================

void ResetNet(){

memset(Input, 0, sizeof(Input) );
memset(Target, 0, sizeof(Target) );
//memset(Contxt, 0, sizeof(Contxt) );

clrnetbuf();
NumPattern=0;
}









//================================================== ===================================
// set input/target patterns manually
//================================================== ===================================

int16_t setIOpattern(int16_t patt) {
int16_t result;
char sbuf[128]; // output string

if(patt==-1) patt = CheckTestPattern(inbuf); // pattern number if known, if not: -1

if( patt > 0 ) sprintf(sbuf, " PATCH target #%-3d", patt);
else sprintf(sbuf, " NEW target #%-3d", NumPattern+1);


result=menu_setouttargets(sbuf);
if (result == -1) return (result); // break by escape btn

if (patt == -1) { // unknown => add new pattern!
SetNewPattern( inbuf, outbuf );
result=NumPattern;
}
else { // override old pattern
PatchPattern( patt, inbuf, outbuf);
result=patt;
}

return result; // return written pattern number

}













//================================================== ===================================

//================================================== ===================================
// display net inputs and target outputs
//================================================== ===================================
void DisplayNetTrainingIOs(int16_t code) {
int16_t i, o, p;
char sbuf[128]; // output string
char msg[20]="! SUCCESS !" ;
if (code==0) strcpy(msg,"calc.error");
if (code==2) strcpy(msg,"user-break");

/* print network outputs */
Serial.println(); Serial.println();
Serial.println(msg);

sprintf(sbuf, "%-6ld: Err= %9.7f", epoch, Error) ;
Serial.print("Epoch "); Serial.println(sbuf);
myGLCD.print(sbuf, 0, 20);
myGLCD.print(msg, 0, 30);

sprintf(sbuf, "NET TRAINING TIME = %ld sec \n", BPTime/1000); Serial.println(sbuf);

Serial.println();
sprintf(sbuf, "Patt. ") ; Serial.print(sbuf); myGLCD.print(sbuf, 0, 40);
for( i = 1 ; i <= NumInput ; i++ ) {
sprintf(sbuf, "Inp%-3d ", i) ; Serial.print(sbuf);
}
for( o = 1 ; o <= NumOutput ; o++ ) {
sprintf(sbuf, "Targ%-3d Outp%-3d ", o, o); Serial.print(sbuf);
}
for(int p = 1 ; p <= NumPattern ; p++ ) {
Serial.println();
sprintf(sbuf, "%3d ", p) ; Serial.print(sbuf); myGLCD.print(sbuf, 40, 40);
for( i = 1 ; i <= NumInput ; i++ ) {
sprintf(sbuf, "%5.2f ", Input[p][i]) ; Serial.print(sbuf);
}
for( o = 1 ; o <= NumOutput ; o++ ) {
sprintf(sbuf, "%5.2f %5.2f ", Target[p][o], Output[p][o]) ; Serial.print(sbuf);
}
}
Serial.println(); Serial.println();
sprintf(sbuf, "BPtrained, returning to main()...!") ; Serial.print(sbuf);
Serial.println(); Serial.println();

}


//================================================== ===================================


void displayMatrix(int16_t patt) {

int32_t btn=-1;
int16_t i, l, o, ibuf, p, lval=1, hval=NumPattern;
float fbuf;
char msgline[30], sbuf[30];
char valline[30];

p=patt;
if(p==0) p=1;
if(p>NumPattern) p=NumPattern;

do {
strcpy(msgline," 12345678901234567890");
sprintf(sbuf, "%-4d", p);
strinsert(msgline, sbuf, 0);
LCDWhiteRed();
Serial.println(msgline); lcdprintxy(0,0,msgline); curlf();
LCDNormal();

for (i=1; i<=NMAXIN; ++i) {
l=(i-1)/20;
if (i%20==1) {
sprintf(sbuf, "%4d ", i-1);
Serial.print(sbuf); lcdprint(sbuf);
}
ibuf = round(Input[p][i]);
sprintf(sbuf, "%1d", ibuf);
Serial.print(sbuf); lcdprint(sbuf);
if (i%20==0) {
Serial.println();
curlf();
}
}
Serial.println(); curlf();
strcpy(msgline,"TARG 12345678901234567890");
LCDRedBlack();
Serial.println(msgline); lcdprint(msgline); curlf();
LCDNormal();

for (i=1; i<=NMAXOUT; ++i) {
l=(i-1)/20;
if (i%20==1) {
sprintf(sbuf, "%4d ", i-1);
Serial.print(sbuf); lcdprint(sbuf);
}
ibuf = round(Target[p][i]);
sprintf(sbuf, "%1d", ibuf);
Serial.print(sbuf); lcdprint(sbuf);
if (i%20==0) {
Serial.println();
curlf();
}
}
Serial.println();

LCDYellowBlue();
sprintf(msgline, "toggle patt +-1: LEFT/RIGHT");
Serial.println(msgline); lcdprintxy(0, LCDmaxY-20, msgline);
sprintf(msgline, "+-10:UP/DN edit:OK quit:ESC");
Serial.println(msgline); lcdprintxy(0, LCDmaxY-10, msgline);
LCDNormal();

btn=getbtn();
if ( (btn==PIN_RI) || (btn==PIN_LE) ) { // browse displayed pattern
if (btn==PIN_RI) p=toggleup(lval, hval, p);
if (btn==PIN_LE) p=toggledn(lval, hval, p);
}
if ( (btn==PIN_UP) || (btn==PIN_DN) ) { // browse displayed pattern
if (btn==PIN_UP) p=toggleup(lval, hval, p+9);
if (btn==PIN_DN) p=toggledn(lval, hval, p-9);
}
if ( (btn==PIN_OK) ) { // change displayed pattern
setIOpattern(p);
}

} while ( (btn!=PIN_ESC ) );
}

//================================================== ===================================

int16_t RefreshInputs() { // polls inputs and stores values to currIn[] array

// poll digital touch values and store directly (1 Dpin = 1 input) 16 DPins == 16
// poll analog sensor values and store bit pattern for ranges (1 Apin = 6 inputs) 8 A10bit == 48
// poll motor speed and store bit pattern for speed ranges (1 Apin = 6 inputs) 4 motors == 24
// Jordan/Elman neural context neurons == feedback inputs (1...NMAXCON) 20 inputs == 20
// =108
int16_t i, cx;

cx = NMAXIN - NMAXOUT +1; // last NMAXCON inputs reserved for context neurons
//for(i=cx; i<= NMAXIN; ++i) { currIn[i] = Contxt[i] ; } //

}


//================================================== ===================================

void ComputeMatrix() { // applies currIn[] inputs to net and computes outputs (outbuf[])
int16_t i, j, o;
float SumH[NMAXHID+1];
float SumO[NMAXOUT+1];
float HidOut[NMAXHID+1];
float SumDOW[NMAXHID+1];
float lambda= 0.5; // context neuron self activation rate

memset(SumH, 0, sizeof(SumH) );
memset(SumO, 0, sizeof(SumO) );
memset(HidOut, 0, sizeof(HidOut) );
memset(SumDOW, 0, sizeof(SumDOW) );

for( j = 1 ; j <= NumHidden ; j++ ) { // compute hidden unit activations
SumH[j] = WeightLIn[0][j] ; // bias neuron
for( i = 1 ; i <= NumInput ; i++ ) {
SumH[j] += currIn[i] * WeightLIn[i][j] ;
}
HidOut[j] = 1.0/(1.0 + exp(-SumH[j])) ; // Sigmoidal Outputs
}

for( o = 1 ; o <= NumOutput ; o++ ) { // compute output unit activations and errors
SumO[o] = WeightLOut[0][o] ; // bias neuron
for( j = 1 ; j <= NumHidden ; j++ ) {
SumO[o] += HidOut[j] * WeightLOut[j][o] ;
}
currOut[o] = 1.0/(1.0 + exp(-SumO[o])) ; // Sigmoidal Outputs
}

//for( o = 1 ; o <= NumOutput ; o++ ) { // compute context neurons
// Contxt[o] = lambda*Contxt[o] + (1-lambda)*currOut[o]; // assign outputs*weight to context neurons
//}

}


//================================================== ===================================
// check for known patterns
//================================================== ===================================
int16_t CheckTestPattern(float * test) {
int16_t i, p;

for( p = 1; p <= NumPattern ; ++p) {
for( i = 1; (i <= NumInput) && ( Input[p][i] == test[i] ); ++i);
if (i > NumInput) {return p; }
}
return -1;
}


//================================================== ===================================
// patch old pattern
//================================================== ===================================
void PatchPattern(int16_t patt, float * _ibuf, float * _obuf ){
int16_t i, o;

if ( (NumPattern <= NMAXPAT) && ( NumPattern > 0) ) {
// # DEBUG
//Serial.print("NumPattern="); Serial.print(NumPattern); Serial.print(" SetNetPattern="); Serial.println(patt);
for(i=1; i<=NMAXIN; ++i) { Input[patt][i] = _ibuf[i]; }
for(o=1; o<=NMAXOUT; ++o) { Target[patt][o] = _obuf[o]; }
}
}


//================================================== ===================================
// add new pattern
//================================================== ===================================
void SetNewPattern(float * _ibuf, float * _obuf ){
int16_t i, o;

if ( (NumPattern < NMAXPAT) && ( NumPattern >= 0) ) {
NumPattern++;
// # DEBUG
//Serial.print("NumPattern="); Serial.print(NumPattern); Serial.print(" SetNetPattern="); Serial.println(patt);
for(i=1; i<=NMAXIN; ++i) { Input[NumPattern][i] = _ibuf[i]; }
for(o=1; o<=NMAXOUT; ++o) { Target[NumPattern][o] = _obuf[o]; }
}
}


// Teil 2 folgt, leider Wartezeit

HaWe
08.09.2018, 17:37
Teil 2



//================================================== ===================================
// set default net patterns
//================================================== ===================================
void SetNetDefaultPatterns(){
float _ibuf[NMAXIN+1], _obuf[NMAXOUT+1];

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=0; _ibuf[2]=0; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=1;
_obuf[1]=1; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=1; _ibuf[2]=0; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
_obuf[1]=0; _obuf[2]=1; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=0; _ibuf[2]=1; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
_obuf[1]=0; _obuf[2]=0; _obuf[3]=1; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=1; _ibuf[2]=1; _ibuf[3]=0; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
_obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=1; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=0; _ibuf[2]=0; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
_obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=1; _obuf[6]=0; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=1; _ibuf[2]=0; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
_obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=1; _obuf[7]=0; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=0; _ibuf[2]=1; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
_obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=1; _obuf[8]=0; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

memset( _ibuf, 0, sizeof(_ibuf) ); memset( _obuf, 0, sizeof(_obuf) );
_ibuf[1]=1; _ibuf[2]=1; _ibuf[3]=1; _ibuf[4]=0; _ibuf[5]=0; _ibuf[6]=0;
_obuf[1]=0; _obuf[2]=0; _obuf[3]=0; _obuf[4]=0; _obuf[5]=0; _obuf[6]=0; _obuf[7]=0; _obuf[8]=1; _obuf[9]=0; _obuf[10]=0;
SetNewPattern( _ibuf, _obuf);

}





//================================================== ===================================
// Backpropagation Learning
//================================================== ===================================
// Backpropagation-C-Implementierung: nn.c 1.0 (C) JOHN BULLINARIA 2004
// verändert und portiert auf Arduino Sketch C: HELMUT WUNDER ("HaWe") 2015
//================================================== ===================================
int16_t TrainNet() {
char sbuf[128]; // output string
int16_t i, j, o, p, np, op, ranpat[NumPattern+1], result=0, ri, rj, ro, rp;
int32_t offset=0;
const float minerr=(1E-4)*(NMAXHID+NMAXOUT);

float SumH[NMAXPAT+1][NMAXHID+1];
float SumO[NMAXPAT+1][NMAXOUT+1];
float HidOut[NMAXPAT+1][NMAXHID+1];
float SumDOW[NMAXHID+1];
float DeltaO[NMAXOUT+1], DeltaH[NMAXHID+1];
float DeltaWeightLIn[NMAXIN+1][NMAXHID+1], DeltaWeightLOut[NMAXHID+1][NMAXOUT+1];

float derror, oerror, oderror,
eta = 0.6, // gradient descent contribution
alpha = 0.8, // 'momentum' term which effectively keeps a moving average
// of the gradient descent weight change contributions...
smallwt = 0.5; // smallwt is the maximum absolute size of your initial weights

/* The weight changes DeltaWeightIH and DeltaWeightHO are each made up of two components.
First, the eta component that is the gradient descent contribution.
Second, the alpha component that is a 'momentum' term which effectively keeps a moving average
of the gradient descent weight change contributions, and thus smoothes out the overall weight changes.
Fixing good values of the learning parameters eta and alpha is usually a matter of trial and error.
Certainly alpha must be in the range 0 to 1, and a non-zero value does usually speed up learning.
Finding a good value for eta will depend on the problem, and also on the value chosen for alpha.
If it is set too low, the training will be unnecessarily slow.
Having it too large will cause the weight changes to oscillate wildly, and can slow down or
even prevent learning altogether.
(I generally start by trying eta = 0.1 and explore the effects of repeatedly doubling or halving it.
*/

// # DEBUG
memtest(70, "memtest: TrainBPNet");
delay(1000);

lcdcls();
Serial.println(); Serial.println();
sprintf(sbuf, "NET TRAINING started") ; Serial.println(sbuf);
Serial.println();
myGLCD.print(sbuf, 0, 10);

uint32_t TimeStamp=TimerMS();

for( j = 1 ; j <= NumHidden ; j++ ) { /* initialize WeightLIn and DeltaWeightLIn */
for( i = 0 ; i <= NumInput ; i++ ) {
DeltaWeightLIn[i][j] = 0.0 ;
WeightLIn[i][j] = 2.0 * ( rando() - 0.5 ) * smallwt ;
}
}
for( o = 1 ; o <= NumOutput ; o ++ ) { /* initialize WeightLOut and DeltaWeightLOut */
for( j = 0 ; j <= NumHidden ; j++ ) {
DeltaWeightLOut[j][o] = 0.0 ;
WeightLOut[j][o] = 2.0 * ( rando() - 0.5 ) * smallwt ;
}
}

for( epoch = 0 ; epoch <= 30000 ; epoch++) { /* iterate weight updates */
for( p = 1 ; p <= NumPattern ; p++ ) { /* randomize order of individuals */
ranpat[p] = p ;
}
for( p = 1 ; p <= NumPattern ; p++) {
np = p + rando() * ( NumPattern + 1 - p ) ;
op = ranpat[p] ; ranpat[p] = ranpat[np] ; ranpat[np] = op ;
}
Error = 0.0 ;
for( np = 1 ; np <= NumPattern ; np++ ) { /* repeat for all the training patterns */
p = ranpat[np];



for( j = 1 ; j <= NumHidden ; j++ ) { /* compute hidden unit activations */
SumH[p][j] = WeightLIn[0][j] ;
for( i = 1 ; i <= NumInput ; i++ ) {
SumH[p][j] += Input[p][i] * WeightLIn[i][j] ;
}
HidOut[p][j] = 1.0/(1.0 + exp(-SumH[p][j])) ;

}



for( o = 1 ; o <= NumOutput ; o++ ) { /* compute output unit activations and errors */
SumO[p][o] = WeightLOut[0][o] ;
for( j = 1 ; j <= NumHidden ; j++ ) {
SumO[p][o] += HidOut[p][j] * WeightLOut[j][o] ;
}
Output[p][o] = 1.0/(1.0 + exp(-SumO[p][o])) ; /* Sigmoidal Outputs */



oerror = Error;
Error += 0.5 * (Target[p][o] - Output[p][o]) * (Target[p][o] - Output[p][o]) ; /* SSE */




oderror = derror; // stalling ?
derror = Error-oerror;
if ( (epoch <= 10000) && (Error>=0.5) && ((epoch-offset)>1000)
&& (abs(derror-oderror)<(minerr/1000) ) ) {
offset=epoch;
for( o = 1 ; o <= NumOutput ; o ++ ) { /* initialize WeightLOut and DeltaWeightLOut */
for( j = 0 ; j <= NumHidden ; j++ ) {
DeltaWeightLOut[j][o] = 0.0 ;
WeightLOut[j][o] = 2.0 * ( rando() - 0.5 ) * smallwt ;
}
}

if( (epoch-offset)%3000==0) {
for( j = 1 ; j <= NumHidden ; j++ ) {
for( i = 0 ; i <= NumInput ; i++ ) {
DeltaWeightLIn[i][j] = 0.0 ;
WeightLIn[i][j] = 2.0 * ( rando() - 0.5 ) * smallwt ;
}
}
}





}
DeltaO[o] = (Target[p][o] - Output[p][o]) * Output[p][o] * (1.0 - Output[p][o]) ; /* Sigmoidal Outputs, SSE */
}
for( j = 1 ; j <= NumHidden ; j++ ) { /* 'back-propagate' errors to hidden layer */
SumDOW[j] = 0.0 ;
for( o = 1 ; o <= NumOutput ; o++ ) {
SumDOW[j] += WeightLOut[j][o] * DeltaO[o] ;
}
DeltaH[j] = SumDOW[j] * HidOut[p][j] * (1.0 - HidOut[p][j]) ;
}
for( j = 1 ; j <= NumHidden ; j++ ) { /* update weights WeightLIn */
DeltaWeightLIn[0][j] = eta * DeltaH[j] + alpha * DeltaWeightLIn[0][j] ;
WeightLIn[0][j] += DeltaWeightLIn[0][j] ;

for( i = 1 ; i <= NumInput ; i++ ) {
DeltaWeightLIn[i][j] = eta * Input[p][i] * DeltaH[j] + alpha * DeltaWeightLIn[i][j];
WeightLIn[i][j] += DeltaWeightLIn[i][j] ;
}
}
for( o = 1 ; o <= NumOutput ; o ++ ) { /* update weights WeightLOut */
DeltaWeightLOut[0][o] = eta * DeltaO[o] + alpha * DeltaWeightLOut[0][o] ;
WeightLOut[0][o] += DeltaWeightLOut[0][o] ;
for( j = 1 ; j <= NumHidden ; j++ ) {
DeltaWeightLOut[j][o] = eta * HidOut[p][j] * DeltaO[o] + alpha * DeltaWeightLOut[j][o] ;
WeightLOut[j][o] += DeltaWeightLOut[j][o] ;
}
}
}
if( epoch % 10 == 0 )
{
sprintf(sbuf, "%-6ld: Err= %9.7f", epoch, Error) ;
Serial.print("Epoch "); Serial.println(sbuf);
myGLCD.print(sbuf, 0, 20);
}

if(Error < minerr) {result=1; break;} // stop learning when 'near enough'
if(pbtn(PIN_ESC)){delay(10); while(pbtn(PIN_ESC)); result=2; break;} // stop after Btn press-and-release
}



BPTime = TimerMS() - TimeStamp;
return result ;
}












//================================================== ===================================
// REPETITIVE LOOP ()
//================================================== ===================================
void loop() {
int16_t result, quit=0;
int32_t choice, btn;
char sbuf[128], spatt[20]; // output string

msg_userctrl();
Serial.println();

while(!quit) {

RefreshInputs(); // polls inputs and stores values to currIn[] array


//***********************************
//************************************************** *****************************
// debug: test different input sets
currIn[1]=1; //currIn[2]=0; currIn[3]=1; //currIn[4]=0; currIn[5]=0; currIn[6]=0; currIn[7]=0;
//************************************************** *****************************
//***********************************


ComputeMatrix(); // applies inputs to net and computes outputs to currOut[] array


curxy(0, LCDmaxY - fonthi*(6+NMAXOUT/20) );
LCDInvers();
lcdprint("12345678901234567890");
LCDNormal();
curlf();
for (int16_t o=1; o<=20; ++o) {
int16_t ibuf = round(currOut[o]);
sprintf(sbuf, "%1d", ibuf);
lcdprint(sbuf);
if (o%20==0) {
curlf();
}
}



result=CheckTestPattern(currIn);
sprintf(spatt,"det.inpatt=%3d", result);
myGLCD.print( spatt, 0, (LCDmaxY)-(3*fonthi) );


choice=0;

// check for btn press

if (btnpressed()) {
btn=getbtn();
}
else btn=-1;

// action for button press

if( btn==PIN_LE ) { // flash current inputs into buffer for processing
memcpy ( inbuf, currIn, sizeof(currIn) );
setIOpattern(-1);
}
else
if( btn==PIN_OK ) { // menu: set net input->target output pattern
choice = menu_setinpattern("Menu: Set Inputs"); // define net input pattern
if (choice != -1) setIOpattern(-1); // set related net target output pattern
}
else
if( btn==PIN_RI ) { // train net
result=TrainNet();
DisplayNetTrainingIOs(result);
msg_userctrl();
}
else
if( btn==PIN_ESC ) clrnetbuf(); // clear buffers

else
if( btn==PIN_UP ) { // main menu
choice = menu_0("menu (N/A)");
}

else
if( btn==PIN_DN ) { // # DEBUG
for (int i=1; i <= NMAXIN; ++i) {
sprintf(sbuf, " %003d", i); Serial.print(sbuf);
}
Serial.println();
for (int i=1; i <= NMAXIN; ++i) {
sprintf(sbuf, "%4.1f", currIn[i]); Serial.print(sbuf);
}
Serial.println(); Serial.println();
for (int o=1; o <= NMAXOUT; ++o) {
sprintf(sbuf, "%4.1f", currOut[o]); Serial.print(sbuf);
}
Serial.println();
Serial.println(spatt);
Serial.println(); Serial.println();
}

if( btn >=0 ) {
Serial.print("choice="); Serial.println(choice); // # DEBUG
msg_userctrl();
}
}

sprintf(sbuf, "\n\nGoodbye!\n\n") ; Serial.print(sbuf);
while(true);

}


// OK: check pattern, add new pattern, patch old pattern
// OK: learn converging and escape stalling (local min)

//================================================== ===================================
//================================================== ===================================


/*


M M EEEEEEEEEEE NN N U U
MM MM E N N N U U
M M M M E N N N U U
M M M M E N N N U U
M M M M E N N N U U
M M M M EEEEEEE N N N U U
M M M E N N N U U
M M E N N N U U
M M E N N N U U
M M E N N N U U
M M EEEEEEEEEEE N NN UUUUUUU


*/

//================================================== ===================================
// bottom line user control menu
//================================================== ===================================
void msg_userctrl() {
char sbuf[128]; // output string

Serial.println();
LCDYellowBlue();
sprintf(sbuf, "Menu:UP clr:ESC learn:RIGHT");
Serial.println(sbuf);
myGLCD.print(sbuf, 0, LCDmaxY-20);

sprintf(sbuf, "inp.patt.set:OK read:LEFT ");
Serial.println(sbuf);
myGLCD.print(sbuf, 0, LCDmaxY-10);

LCDNormal();
}




//================================================== ===================================
// LCD-TFT menu system
//================================================== ===================================

int32_t menu_0(char caption[] ) { // main menu
const int16_t MAXMSIZE = 8; // number of maximum useable menu options
const char LSIZE=20;

char astr[MAXMSIZE][LSIZE+1], // all options by all inscription string
opbuf[LSIZE+1], // option buffer
numbuf[LSIZE+1], // num buffer
last[LSIZE+1] , // end of line buffer
more[LSIZE+1] , // next line buffer
space[LSIZE+1] , // empty line buffer
bobross=0; // if to paint a beautiful new menu by beautiful colors ;)



static int16_t ch=0, maxframe=8, minframe=0; // static for re-entering the menu;
int16_t btn, i, j, lch, MAXVOPT=8;
int16_t val=0, lval=0, hval=3;


memset(last, '-', LSIZE ); last[LSIZE]='\0';
memset(more, '+', LSIZE ); more[LSIZE]='\0';
memset(space, ' ', LSIZE ); space[LSIZE]='\0';

for (i=0; i<MAXMSIZE; ++i) {
strcpy(astr[i], space );
sprintf(opbuf, "%3d", i);
strinsert(astr[i], opbuf, 0);
}


strinsert(astr[ 0], "File load -> 0", 4);
strinsert(astr[ 1], "File safe -> 0", 4);
strinsert(astr[ 2], "show patt. -> 0", 4);
strinsert(astr[ 3], "erase patt.-> 0", 4);
strinsert(astr[ 4], "option e ", 4);
strinsert(astr[ 5], "option f ", 4);
strinsert(astr[ 6], "option g ", 4);
strinsert(astr[ 7], "option h ", 4);

strinsert(astr[MAXMSIZE-1], "option:last ", 4);

if (ch<0) ch=0;
if(MAXVOPT>MAXMSIZE) {maxframe=MAXVOPT=MAXMSIZE; }

lcdcls();
LCDWhiteRed();
myGLCD.print(space, 0, 0);
myGLCD.print(caption, (20-strlen(caption))*8/2, 0);

LCDNormal();
for (i=minframe; i<maxframe; ++i) {
myGLCD.print(astr[i], 0, (i+1-minframe)*10);
}

LCDRedBlack();
if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10);
else myGLCD.print(last, 0, (MAXVOPT+1)*10);

LCDInvers();
myGLCD.print(astr[ch], 0, (ch+1-minframe)*10);
LCDNormal();

do {
lch=ch;
btn=getbtn();

if ( ch < 2 ) { lval=0; hval=3;}
else if ( ch==2) { lval=0; hval=NumPattern;} // 0 == show all
else if ( ch==3) { lval=0; hval=NumPattern;} // 0 == VOID (for safety unerase)
else { lval=0; hval=0;}


if ( (btn==PIN_DN ) || (btn==PIN_UP ) ) {
val=lval;
if (btn==PIN_DN )
{
if(ch<MAXMSIZE-1) ch++;
else {
ch=0;
minframe=0;
maxframe=MAXVOPT;
if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
}
if(ch>maxframe) {maxframe++; minframe++; bobross=1; goto newbob;}
}
else
if (btn==PIN_UP ) {
if (ch > 0) ch--;
else {
ch=MAXMSIZE-1;
maxframe=MAXMSIZE;
minframe=maxframe-MAXVOPT;
if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
}
if(ch<minframe) {maxframe--; minframe--; bobross=1; goto newbob;}
}
newbob:
LCDNormal();
if(bobross) {
for (i=minframe; i<maxframe; ++i) {
myGLCD.print(astr[ch], 0, (i+1-minframe)*10);
}
bobross=0;
}
else
{
myGLCD.print(astr[lch], 0, (lch+1-minframe)*10);
}
LCDRedBlack();
if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10);
else myGLCD.print(last, 0, (MAXVOPT+1)*10);

LCDInvers();
myGLCD.print(astr[ch], 0, (ch+1-minframe)*10);
LCDNormal();
}

if ( (btn==PIN_RI) || (btn==PIN_LE) ) { // change input buffer value

if (ch < 4) { // toggle through sub menu options
if (btn==PIN_RI) val=toggleup(lval, hval, val);
if (btn==PIN_LE) val=toggledn(lval, hval, val);
sprintf(numbuf, "%3d", val);
strcpy(opbuf, astr[ch]);
strinsert(opbuf, numbuf, LSIZE-3);
LCDInvers();
myGLCD.print(opbuf, 0, (ch+1-minframe)*10); // write line buffer = serial number + option
LCDNormal();
}
}

} while (!( (btn== PIN_OK) || (btn== PIN_ESC) )) ;

lcdcls();
if (btn==PIN_ESC) { return -1; }

if (ch==0) { ;} // File load -> val
else
if (ch==1) { ;} // File safe -> val
else
if (ch==2) { displayMatrix(val) ;} // show patt. -> val
else
if (ch==3) { ;} // erase patt.-> val

return val+(ch*10000); // return number of suboption + 10000* option

}


//================================================== ===================================
// menu: set target outputs manually
//================================================== ===================================
int8_t menu_setouttargets(char caption[]) { // set targets
const int16_t MAXMSIZE = NMAXOUT; // number of maximum useable menu options
const char LSIZE=17; // string length of line for option inscriptions

char astr[MAXMSIZE+1][LSIZE+1], // all options by all inscription string
opbuf[LSIZE+1], // option buffer
buf[LSIZE+5] =" ", // line buffer = serial number + option inscription
lbuf[LSIZE+5]="---------------------", // end of line buffer (-> last element)
more[LSIZE+5]="+ + + + + + + + + + +", // next line buffer (-> more elements)
bobross=0; // if to paint a beautiful new menu by beautiful colors ;)


int8_t btn, i, lch, MAXVOPT=10;
int8_t ch=0, maxframe=MAXVOPT, minframe=1; // static for re-entering the menu;


memcpy(outbuf, currOut, sizeof(outbuf) );
for (i=1; i<=MAXMSIZE; ++i) { // initialize all lines in inscription array
sprintf(opbuf, "Output%3d= %.0f ", i, outbuf[i] );
strcpy(astr[i], opbuf ); // inscription = option + outbuf value
}

if (ch<1) ch=1;
if(MAXVOPT>MAXMSIZE) {maxframe=MAXVOPT=MAXMSIZE; }

lcdcls();
LCDWhiteRed();
myGLCD.print(buf, 0, 0);
myGLCD.print(caption, (20-strlen(caption))*8/2, 0);

LCDNormal();
for (i=minframe; i<=maxframe; ++i) {
sprintf(buf, "%3d %s", i, astr[i]); // build line buffer = serial number + inscription
myGLCD.print(buf, 0, (i+1-minframe)*10);
}
LCDRedBlack();
if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (i+1-minframe)*10);
else myGLCD.print(lbuf, 0, (i+1-minframe)*10);

LCDInvers();
sprintf(buf, "%3d %s", ch, astr[ch]);
myGLCD.print(buf, 0, (ch+1-minframe)*10);
LCDNormal();

do {
lch=ch;
btn=getbtn();
if ( (btn==PIN_DN ) || (btn==PIN_UP ) ) { // btn up/dn: dec/inc current option
if (btn==PIN_DN ) {
if(ch < MAXMSIZE) ch++;
else {
ch=1;
minframe=1;
maxframe=MAXVOPT;
if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
}
if(ch>maxframe) {maxframe++; minframe++; bobross=1; goto newbob;} // adjust visible frame
}
else
if (btn==PIN_UP ) {
if (ch > 1) ch--;
else {
ch=MAXMSIZE;
maxframe=MAXMSIZE;
minframe=maxframe-MAXVOPT+1;
if ( minframe != 1) { bobross=1; goto newbob; }
}
if(ch<minframe) {maxframe--; minframe--; bobross=1; goto newbob;} // adjust visible frame
}
newbob: // if frame has changed: move frame, paint anew
LCDNormal();
if(bobross) {
for (i=minframe; i<=maxframe; ++i) {
sprintf(buf, "%3d %s", i, astr[i]);
myGLCD.print(buf, 0, (i+1-minframe)*10); // write all visible complete line buffers
}
bobross=0;
}
else
{
sprintf(buf, "%3d %s", lch, astr[lch]);
myGLCD.print(buf, 0, (lch+1-minframe)*10); // write old line buffer (normal)
}
LCDRedBlack();
if(maxframe<MAXMSIZE) { // write line for "more elements"
myGLCD.print(more, 0, (i+1-minframe)*10);
}
else myGLCD.print(lbuf, 0, (i+1-minframe)*10); // write line "last element"

LCDInvers();
sprintf(buf, "%3d %s", ch, astr[ch]);
myGLCD.print(buf, 0, (ch+1-minframe)*10); // write current line buffer (invers)
LCDNormal();
}
if ( (btn==PIN_RI) || (btn==PIN_LE) ) { // change input buffer value
if (btn==PIN_RI) outbuf[ch]=1;
if (btn==PIN_LE) outbuf[ch]=0;
sprintf(opbuf, "Output%3d= %.0f ", ch, outbuf[ch] );
strcpy(astr[ch], opbuf );
sprintf(buf, "%3d %s", ch, astr[ch]); // update inscription: option + outbuf value
LCDInvers();
myGLCD.print(buf, 0, (ch+1-minframe)*10); // write line buffer = serial number + inscription
LCDNormal();
}

} while (!( (btn== PIN_OK) || (btn== PIN_ESC) )) ;


if (btn==PIN_ESC) { lcdcls(); return -1; }


lcdcls();
return ch;
}




//================================================== ===================================
// menu: set inputs manually
//================================================== ===================================
int16_t menu_setinpattern(char caption[]) { // set inputs
const int16_t MAXMSIZE = NMAXIN; // number of maximum useable menu options
const char LSIZE=17; // string length of line for option inscriptions

char astr[MAXMSIZE+1][LSIZE+1], // all options by all inscription string
opbuf[LSIZE+1], // option buffer
buf[LSIZE+5] =" ", // line buffer = serial number + option inscription
lbuf[LSIZE+5]="---------------------", // end of line buffer (-> last element)
more[LSIZE+5]="+ + + + + + + + + + +", // next line buffer (-> more elements)
bobross=0; // if to paint a beautiful new menu by beautiful colors ;)


int16_t btn, i, lch, MAXVOPT=10;
static int16_t ch=0, maxframe=MAXVOPT, minframe=1; // static for re-entering the menu;

strcpy(astr[0], "static 0" );
for (i=1; i<=MAXMSIZE; ++i) { // initialize all lines in inscription array
sprintf(opbuf, "Input%3d = %.0f ", i, inbuf[i] );
strcpy(astr[i], opbuf ); // inscription = option + inbuf value
}

if (ch<1) ch=1;
if(MAXVOPT>MAXMSIZE) {maxframe=MAXVOPT=MAXMSIZE; }

lcdcls();
LCDWhiteRed();
myGLCD.print(buf, 0, 0);
myGLCD.print(caption, (20-strlen(caption))*8/2, 0);

LCDNormal();
for (i=minframe; i<=maxframe; ++i) {
sprintf(buf, "%3d %s", i, astr[i]); // build line buffer = serial number + inscription
myGLCD.print(buf, 0, (i+1-minframe)*10);
}
LCDRedBlack();
if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10 );
else myGLCD.print(lbuf, 0, (MAXVOPT+1)*10 );

LCDInvers();
sprintf(buf, "%3d %s", ch, astr[ch]);
myGLCD.print(buf, 0, (ch+1-minframe)*10);
LCDNormal();

do {
lch=ch;
btn=getbtn();
if ( (btn==PIN_DN ) || (btn==PIN_UP ) ) { // btn up/dn: dec/inc current option
if (btn==PIN_DN ) {
if(ch < MAXMSIZE) ch++;
else {
ch=1;
minframe=1;
maxframe=MAXVOPT;
if ( maxframe != MAXMSIZE) { bobross=1; goto newbob; }
}
if(ch>maxframe) {maxframe++; minframe++; bobross=1; goto newbob;} // adjust visible frame
}
else
if (btn==PIN_UP ) {
if (ch > 1) ch--;
else {
ch=MAXMSIZE;
maxframe=MAXMSIZE;
minframe=maxframe-MAXVOPT+1;
if ( minframe != 1) { bobross=1; goto newbob; }
}
if(ch<minframe) {maxframe--; minframe--; bobross=1; goto newbob;} // adjust visible frame
}
newbob: // if frame has changed: move frame, paint anew
LCDNormal();
if(bobross) {
for (i=minframe; i<=maxframe; ++i) {
sprintf(buf, "%3d %s", i, astr[i]);
myGLCD.print(buf, 0, (i+1-minframe)*10); // write all visible complete line buffers
}
bobross=0;
}
else
{
sprintf(buf, "%3d %s", lch, astr[lch]);
myGLCD.print(buf, 0, (lch+1-minframe)*10); // write old line buffer (normal)
}
LCDRedBlack();
if(maxframe<MAXMSIZE) myGLCD.print(more, 0, (MAXVOPT+1)*10 );
else myGLCD.print(lbuf, 0, (MAXVOPT+1)*10 );

LCDInvers();
sprintf(buf, "%3d %s", ch, astr[ch]);
myGLCD.print(buf, 0, (ch+1-minframe)*10); // write current line buffer (invers)
LCDNormal();
}
if ( (btn==PIN_RI) || (btn==PIN_LE) ) { // change input buffer value
if (btn==PIN_RI) inbuf[ch]=1;
if (btn==PIN_LE) inbuf[ch]=0;
sprintf(opbuf, "Input%3d = %.0f ", ch, inbuf[ch] );
strcpy(astr[ch], opbuf );
sprintf(buf, "%3d %s", ch, astr[ch]); // update inscription: option + inbuf value
LCDInvers();
myGLCD.print(buf, 0, (ch+1-minframe)*10); // write line buffer = serial number + inscription
LCDNormal();
}

} while (!( (btn== PIN_OK) || (btn== PIN_ESC) )) ;

lcdcls();
if (btn==PIN_ESC) { return -1; }
return ch;
}


//================================================== ===================================
//================================================== ===================================




// end of file





- - - Aktualisiert - - -

PS,
der Code aus dem RobotC Forum stammt auch von mir, allerdings war RobotC damals dermaßen unglaublich verbugged (und dann auch noch recht teuer), dass ich anschließend zu NXC gewechselt bin.