Newsgroup: it.comp.ia
Titolo: Problemino con algoritmo di BackPropagation

Salve a tutti...
Da un paio di giorni sto diventando matto (cioe' non che non lo
fossi gia prima, ma ora sto degenerando) perche' ho un problema
con l'algoritmo di BP.. Avevo disegnato una rete con due
neuroni in input, 10 nell'hidden layer e 1 di output... Ho cercato
di insegnarle la semplice operazione di addizione.. Senza alcun
successo.. Allora ho pensato di modificarla un pochetto per farle
imparare prima lo xor, tanto per vedere se apprendeva.... Ma
non impara nulla ne dopo 1000, 2000, fino a 200.000 epoche...
Niente di niente, i pesi variano in maniera percettibile che all'occhio
umano sembra bene.. Ma bene non e' perche' non impara e non so
davvero a chi chiedere una mano a questo punto :((( vi pasto il sorgente
qui sotto, sono poche righe commentate e di facile comprensione...
w[] e' l'array dei pesi
error[] l'errore commesso da ogni neurone
delta[] la variazione da applicare ai pesi
out[] l'uscita di ogni neurone
Una cosa non mi e' chiara... Se assumo il bias = 1.0, il relativo peso
va messo a 1.0 o va variato come tutti gli altri pesi? Perche' io nella
mia rete lo assumo come fisso, ma non so se sia corretto o meno :).
Ringrazio chiunque perdera' 10 minuti del proprio tempo per aiutarmi
a capire dove sta l'errore... Renderete un pazzo felice quando questa
rete avra' imparato l'allegro xor :)))))))) grazie tante a tutti.
(i pesi li inizializzo da -1.0 a 1.0, avevo provato nel range 10, -10 ma
il neurone di output otteneva una somma pesata elevatissima che
corrispondeva a valori piccolissimi della sigmoide che andavano oltre
la scala di precisione di un modesto `double`).
Source:
#define HIDDEN 10 // Neuroni nello strato nascosto
double w[HIDDEN*3], uscita[HIDDEN+1], learning = 0.6, bias = 1.0;
int main(int argc, char **argv){
int f_add, s_add;
double f, s, error[HIDDEN+1], delta[HIDDEN*3], out[HIDDEN+1], exp,
net_output = 0.0;
srand((unsigned int)time(NULL));
for(int i=0; i<HIDDEN*3; i++)
// Inizializza i pesi con un qualunque valore tra -1.0 e +1.0
w[i]=((rand()%20000/10000.0)-1.0)+(rand()%10000/100000000.0f);
 for(;;){
  // Acquisisci i membri
  printf("\nNum 1: "); scanf("%d", &f_add);
  printf("Numo 2: "); scanf("%d", &s_add);
  printf("Expected: %d\n", f_add^s_add);
  f = f_add;
  s = s_add;
  // Calcola il risultato esatto
  exp = (int)f^(int)s;
  // Calcola le uscite dello strato nascosto
  for(int j=0; j<HIDDEN; j++)
     out[j] = uscita[j] = normalizza(f*w[j]+s*w[j+HIDDEN]+(1*bias));
  // Calcola la somma pesata sul neurone di output
  for(int i=0; i<HIDDEN; i++)
     net_output += w[HIDDEN*2+i] * uscita[i];
  // Salva l'uscita del neurone di output
  out[HIDDEN] = uscita[HIDDEN] = normalizza(net_output+(1*bias));
  net_output = 0.0;
  printf("Risultato: %f\n", out[HIDDEN]);
  // Calcoliamo l'errore commesso dallo strato di output
  error[0] = (exp-out[HIDDEN])*out[HIDDEN]*(1-out[HIDDEN]);
  // Calcoliamo quindi la variazione delta dei pesi che dallo
  // strato nascosto vanno verso l'output
  for(int i=0; i<HIDDEN; i++)
   delta[HIDDEN*2+i] = w[HIDDEN*2+i] + learning * error[0] * out[HIDDEN];
  // Calcoliamo ora l'errore dei neuroni dello strato nascosto
  for(int i=0; i<HIDDEN; i++)
   error[i+1] = out[i] * (1-out[i]) * error[0] * w[HIDDEN*2+i];
  // Calcoliamo la variazione delta dei pesi dallo strato nascosto verso
l'input
  for(int i=HIDDEN; i<HIDDEN*2; i++)
   delta[i] = w[i] + learning * error[i-HIDDEN] * s;
  for(int i=0; i<HIDDEN; i++)
   delta[i] = w[i] + learning * error[i] * f;
  // Quindi variamo i pesi
  for(int i=0; i<HIDDEN*3; i++)
   w[i] = delta[i];
 }
return 0;
}
double normalizza(double n)
{
 return(1/(1+exp(-bias*n)));
}

così, ad una prima occhiata, c'è qualcosa che non va nel bias, che
sneso ha avere un bias fisso?
ti chiarisco il concetto di bias: il bias è come se fosse un altro
neurone, PER OGNI altro neurone esclusi quelli dello strato di input,
il cui valore è sempre a 1... 
dunque mi sembra errata sia la propagazione, cioè sembra che tu
utilizzi un bias uguale per tutti i neuroni dello strato hidden, non
hai un bias per quello di output (che avendo un solo neurone avrebbe
un solo bias) e soprattutto non consideri il bias nel calcolo
dell'errore e nemmeno lo aggiorni con il backprop!
tu consideralo un neurone a tutti gli effetti, solo che il suo valore
è sempre 1 e hai un neurone di bias per OGNI neurone dello strato
nascosto e PER OGNI neurone dello strato di uscita... nel tuo caso
dovresti dunque avere 11 neuroni di bias e quindi 11 "pesi" bias da
utilizzare e aggiornare
un appunto sul resto del programma:
1) consiglio per la leggibilità: così a primo acchitto non è semplice
seguire il programma, per via della struttura dei pesi, utilizzi, se
non ho capito male, il vettore w sia per lo strato di hidden che per
quello di uscita, sommandovi HIDDEN per distinguerli... chi rilegge il
tuo programma diventa pazzo (tra l'altro il dubbio è "perché hai messo
HIDDEN * 3 e HIDDEN + 1 come dimensioni?!?") potevi semplicemente
chiamare i tuoi strati ingresso[INPUT_COUNT], hidden[HIDDEN_COUNT] e
uscita[OUTPUT_COUNT] i tre gruppi di neuroni (i valori), poi i pesi li
avresti semplicemente chiamati, che so,
ing_hid[INPUT_COUNT][HIDDEN_COUNT] e
hid_usc[HIDDEN_COUNT][OUTPUT_COUNT], rispettivamente i pesi dei
collegamenti tra neuroni di input e nascosti e poi tra quelli nasocsti
e quelli di uscita, in questo modo ing_hid[2][3] indica semplicemente
il collegamento tra il TERZO neurone di ingresso e il QUARTO di uscita
2) perché mai DIECI neuroni nello strato nascosto?!? così impiega
molto più tempo a imparare anche uno xor (certo non 200.000 epoche!!),
a occhio userei 3 o 4 neuroni, la tua scelta era motivata o era
casuale?
N.B.: prova a controllare se con il bias modificato funziona,
altrimenti al prossimo post di invio un programmino che fa la stessa
cosa... però il mio funziona!! :-DD
-- 
]\/[ad]\/[age (
www.mindreamz.net
)
"Un Maestro insegue semplicemente la sua visione di Eccellenza in
qualunque cosa sta facendo e lascia agli altri decidere se sta 
lavorando o giocando. A lui sembra sempre di fare entrambe." - Anonimo

Mad ti straringrazio tantissimo per la chiarificazione sul bias...
Allora, i 10 neuroni sono stati messi li perche' pensavo di
addestrare la rete a fare le addizioni... Ma visto che non imparava
ho lasciato invariata la struttura e ho cercato, inutilmente, di farle
imparare lo xor, scusa per il codice, ma e' ancora in fase di
debugging per quello che trovi quegli HIDDEN ;p invece di
un piu normale OUTPUT, HIDDEN etc ;ppp, se hai voglia
di mandarmi il tuo programmino mi farebbe immensamente
piacere, nel frattempo sistemo la mia rete e ti posto sul NG
il risultato, veramente un GRAZIE grande come la piramide
di keope :)))

Grazie mad,
ho corretto i bias ed ora tutto funziona piuttosto
bene, lo xor lo impara benissimo e anche l'addizione.
Il codice ancora non e' riadattato per renderlo piu'
leggibile, ho solo apportato le modifiche ai bias domani
con calma faro' il resto, se qualcuno e' interessato me lo
chieda che lo posto senza problemi.
Un grazie enorme a madmage :)