Go Down

Topic: Semplice rete neurale per Arduino 2 (Read 15761 times) previous topic - next topic

lesto

Quote
l tuo sketch poi è sbagliato visto che usi sin(x) che è proprio la funzione che sto tentando di approsimare partendo dai set in ingresso

lo faccio solo per avere lo stesso identico set per fare l'addestrameto e poi il check. Se non funziona c'è qualche bug nella libreria. Se funziona il bug è nella funzione di input.
Tu stai pensando all'utilizzo, io al debug, e procedo per gradi.

Quote
Quando faccio Serial.parseFloat()/360 è proprio perchè voglio dividerlo per 360 cioè far rientrare l'angolo tra 0 ed 1. Il % cioè il resto non c'entra niente.

mi sono perso questa normalizzazione dell'uso dei gradi. Sapevo che l'output deve essere un valore tra -1 e 1 però, cosa che /360 fà se metti angoli negativi.

Quote
rete ha solo un ingresso ed una uscita allora passo l'indirizzo della variabile (o della cella dell'array). È la rete che poi gestisce in automatico il numero di ingressi (uso la magia dei puntatori in poche parole  smiley-mr-green).


ora mi è chiaro, quindi nel mio codice c'è da cambiare

Code: [Select]
net.backPropagation(i, sin(i),LR);
in
Code: [Select]
net.backPropagation(&i, &(sin(i)),LR);

e

Code: [Select]
Serial.println( sin(i)-net.thinkNet(i) );
in
Code: [Select]
Serial.println( sin(i)-(*net.thinkNet(&i)) );

Quote
Il tuo post è completamente sbagliato o quasi.

dai non era così pessimo :)
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

leo72

Ma sin() già non restituisce un valore compreso tra 1 e -1?
Sin 0 = 0
Sin 90 = 1
Sin 180 = 0
Sin 270 = -1
Sin 360 = 0

yoshi93

#77
May 09, 2013, 11:23 pm Last Edit: May 09, 2013, 11:30 pm by yoshi93 Reason: 1
@lesto:
Ok, se lo si guarda da un punto di vista del debug ci può stare sin(x)  :). Completamente sbagliato no, l'ho detto per evitare che fosse troppo fuorviante per chi sta leggendo la discussione e non sa nulla sulle reti neurali.
Per quanto riguarda il debug sono sicuro che la libreria funzioni perchè l'ho passata su code::blocks e funziona senza quasi modifiche (che ricordo coinvolgono l'importazione di cmath.h per usare exp() e la modifica di random() in rand()). I training sets non sono neppure quelli perchè li uso senza problemi e nemmeno la firma di thinkNet(). L'unica cosa che posso pensare appunto è lo sketch di prova che verificava continuamente il pin4 per l'addestramento e aveva qualcosa che non andava(non so cosa) oppure i settaggi iniziali della rete.

@leo72
Non ho capito cosa intendi.

lesto


Ma sin() già non restituisce un valore compreso tra 1 e -1?
Sin 0 = 0
Sin 90 = 1
Sin 180 = 0
Sin 270 = -1
Sin 360 = 0



attento che lavora in radianti. quindi 180° sono PI (~3.14), 360° sono 2PI (~6.28) etc..

Quote
Scrivere:
Code:

(rand()%100)/1000.0

è uguale a:
Code:

random(100)/1000.0

vero?


sì, se può essere utile: http://arduino.cc/en/Reference/HomePage

attento che rand()%100 è "sbagliato", rovini la distribuzione dei numeri casuali, di solito nulla di che, ma se usi la rand() spesso può dare problemi http://www.azillionmonkeys.com/qed/random.html
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

yoshi93

@lesto:
Non ho capito a chi ti riferisci quando dici
Quote
attento che lavora in radianti
.
Per la rand() invece il problema è che lei funziona perfettamente su pc e il mio dubbio era la random() di arduino.
Ci vorrebbero altre prove con i valori dello sketch modificati per vedere come va.

lesto

per la storia dei radianti parlavo con leo, che ha fatto un esempio della sin() usando i gradi.  :smiley-mr-green:
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

zoomx


Ma sin() già non restituisce un valore compreso tra 1 e -1?


Se non ricordo male vanno normalizzati sia gli ingressi che le uscite sia nell'addestramento che poi nell'uso.



leo72

@yoshi e lesto
mi riferivo a questo pezzo di yoshi:

Gli angoli non sono in radianti ma bensì in gradi normalizzati tra 0 ed 1 come già detto e il seno è trasformato secondo quella formula per far coincidere lo della funzione con il valore 0.5 della funzione sigmoide usata dai neuroni.
In pratica, il neurone di uscita ha una funzione sigmoide(come tutti gli altri) e il sin(0)=sin(360)=0. 0 e 360 sono presenti nei set di addestramento due volte percui la rete tenderà a convergere con maggiore precisione sullo 0 ma poichè ha funzione sigmoide sullo 0 non ci potrà mai andare visto che ha un andamento asintotico per -infinito percui lo 0 (normalizzato a 0) e 360(normalizzato a 1) hanno valori di uscita dalla rete di 0.5 che equivale a sigmoid(0) per avere la massima precisione possibile proprio intorno a quel punto.


Estratto dal Reference:
Quote
Description
Calculates the sine of an angle (in radians). The result will be between -1 and 1.

sin lavora in radianti ma il suo risultato è sempre compreso fra -1 e 1.

leo72

Nuove prove con l'ultima versione della lib e l'ultima versione dello sketch:

sin 0 = 1.30
sin 45 = 1.08
sin 90 = 0.88
sin 135 = 0.69
sin 180 = -0.01
sin 225 = -0.62
sin 270 = -0.65
sin 315 = -0.65
sin 360 = -0.65

lesto

ok, verifichiamo che ogni tot di fase di addestramento l'errore diminuisca: (ripropongo il mio codice rivisto e corretto, spero)

Code: [Select]
#include <StaticNeuron.h>
#include <ArdFeedForward.h>

const float LR=0.2;
const unsigned int TRAINING_CYCLES=1000;
unsigned int ciclo=0;

ArdFeedForward net(1,1,2,2);

void setup()
{
Serial.begin(9600);
delay(1000);
}

void loop(){
ciclo++;
Serial.print("Inizio addestramento ");
Serial.print(ciclo);
Serial.print(" di ");
Serial.print( TRAINING_CYCLES );
Serial.print(" cicli ");
Serial.println(); //a capo

//fase di training
for(int j=0;j<TRAINING_CYCLES;j++){
for(int i=0;i<17;i++){
net.backPropagation(&i, &(sin(i)),LR);
}
}

float sumErrore =0; //ci aspettiamo che ogni ciclo questo valore diminuisca
for(int i=0;i<30;i++){
sumErrore += abs( sin(i)-(*net.thinkNet(&i)) ); //somma il modulo dell'errore, per evitare che errori negativi apiattiscano erroneamente la soimma dell'errore
if (ciclo%40==0){
Serial.print("Per il seno di ");
Serial.print(i);
Serial.print(" l'errore è ");
Serial.print( sin(i)-(*net.thinkNet(&i)) );
Serial.println(); //a capo
}
}
Serial.print("La somma del modulo dell'errore è ");
Serial.print(sumErrore);
Serial.println(); //a capo
}
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

yoshi93

Mi stavo chiedendo, potrebbe essere un problema del compilatore? Il mio progetto fa un uso smodato di puntatori quindi non è che magari l'arduino va in errore per qualche errore interno?

lesto

no, la due è un ARM, architettura molto più diffusadegli AVR. Sarebbe un signor bug  :smiley-mr-green:
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

yoshi93

Oppure più semplicemente sforo con la ram :smiley-roll-sweat:. Comunque devo ammettere che il porting da pc non è stata una buona idea, la rete così strutturata è troppo pesante e capire dove siano i problemi è piuttosto difficoltoso. Questo post mi ha fornito molte informazioni riguardo l'ottimizzazione che potrei fare. Credo che nella prossima versione non userò più la StaticNeuron per risparmiare spazio (rimane comunque a disposizione per eventuali prove).
Se leo è d'accordo dovrei avere anche un nuovo post pulito per lavorare anche sull'ordine della discussione.

ratzeni

Buonasera a tutti i partecipanti alla discussione.

@Yoshi93, innanzi tutto grazie per aver aperto la discussione, sebbene è un argomento un po' ostico, credo che potrebbe consentirci interessanti applicazioni sulla piattaforma Arduino.
Mi viene in mente per esempio la possibilità di prendere una decisione sul valore di più sensori, come farebbe un esperto.
Sono riuscito a far funzionare il codice, senza modificare la tua libreria ma solo modificando il tuo sketch.

Ho caricato sul mio Arduino Due la tua libreria e lo sketch che avevi postato qualche giorno fa e ho utilizzato LR = 0.5 come suggerito sul sito http://stor.altervista.org/informatica/nn/nn.htm

Dopo aver eseguito molti test, inserendo qualche traccia su input ed output mi sono reso conto che la comunicazione seriale non lavorava correttamente. La Serial.ParseFloat() alla prima lettura leggeva l'angolo correttamente e infatti il primo risultato era corretto, alle letture successive invece non leggeva il primo carattere, quindi se immettevi 30, 60, 70 ecc, restituiva sempre 0.1 perchè leggeva zero e comunque valori molto bassi se si provavano .
Il valore del seno dell'angolo è calcolato con l'approssimazione di 0.01, ma l'esempio ci assicura che il tuo codice è affidabile, dato che non è la precisione matematica lo scopo della cosa.

Ho pensato quindi di costruirmi una funzione per fare il parsing dell'input dell'angolo, in modo da leggere valori positivi e negativi e ho inserito come delimitatore il carattere ";".

Ho anche semplificato il tuo sketch mettendo la fase di Addestramento nella sezione setup. L'addestramento dura circa 6 minuti, ho inserito due chiamate, sebbene dopo la prima mi pare che i risultati sono già buoni.
Inserisco il codice così se quancuno se vuole può provare a ripetere la verifica.
Spero si possa proseguire nel migliorare  per arrivare ad addestrare la rete con input provenienti da sensori.
Non so se in questo Yoshi93 può darci qualche idea riguardo la definizione dei dati di addestramento.
ciao a tutti

leo72


Se leo è d'accordo dovrei avere anche un nuovo post pulito per lavorare anche sull'ordine della discussione.

Risposto in PM.

Go Up