PDA

View Full Version : [C++] Rete neurale, backpropagation - Uso del peso bias


Teo@Unix
27-08-2010, 14:51
Buondì.

In ottica di poter riutilizzare le reti neurali, stò scrivendo una libreria in C++. Le funzioni per l'utilizzo del percettrone fanno il loro dovere, ho invece un problema quando vengono aggiunti uno o più layer nascosti. Per allenare una rete di questo tipo utilizzo backpropagation, ma ho innanzi tutto dei dubbi sull'utilizzo del peso bias per ogni neurone.

Quello che faccio è aggiungere un neurone fittizio in tutti i layer. Questo varrà sempre 1 e trasferirà sempre uno, mente il suo peso di connessione varia come gli altri.
Non so se l'errore che ho dipende dall'uso errato che faccio del bias, o se è un'altro tipo di problema.

Non so se postare il codice può essere utile, comunque dovrebbe essere abbastanza chiaro dato il linguaggio utilizzato, il seguente è il metodo di addestramento backpropagation:

int NeuralNet::Train_BackPropagation(vector<_PRECISION> des_out) {
/* Backpropagation case */

// Verifiy that the hidden layer exists
if(des_out.size() != numOutputNeurons || numHiddenLayers <= 0 || numHiddenNeuronsPerLayer <= 0) return -1;

_PRECISION error, delta_weight, prev_bp_err = 0, cur_bp_err = 0;

for(u_int32_t l = layers.size()-1; l >= 0; l--) { // For each layer, begin from output
prev_bp_err = cur_bp_err;
cur_bp_err = 0;
if(!l) break; // Input layer has no weights
if(l==layers.size()-1) {// Output layer
for(u_int32_t n = 0;n < layers[l]->getNeuronNum();n++) { // For each neuron
// Calculate delta error, dk = (rk - ok)*f'(netk)

if(n==layers[l]->getNeuronNum()-1 && BIAS){ // for only bias neuron
error =
(des_out[n-1] - layers[l]->getNeuron(n)->getPotential())*
layers[l]->getNeuron(n)->trans_func_derivate(layers[l]->getNeuron(n)->getPotential());
} else {
error =
(des_out[n] - layers[l]->getNeuron(n)->getPotential())*
layers[l]->getNeuron(n)->trans_func_derivate(layers[l]->getNeuron(n)->getPotential());
}

for(u_int32_t w = 0;w < layers[l]->getNeuron(n)->getWeightsNum(); w++) {// For each weight
// Calculate delta weight, Dw = Wjk + n*dk*oj
delta_weight = layers[l]->getNeuron(n)->getWeight(w) + l_rate*error*layers[l-1]->getNeuron(w)->getPotential();
// Update weight
layers[l]->getNeuron(n)->setWeight(w,delta_weight);
// Product smmation of current error and current weight
cur_bp_err += layers[l]->getNeuron(n)->getWeight(w)*error;
}
}
} else { // Hidden layers and input
for(u_int32_t n = 0;n < layers[l]->getNeuronNum(); n++) {// For each neuron
// Calculate hidden layer error, remembering the previous propagated error
error = layers[l]->getNeuron(n)->trans_func_derivate(layers[l]->getNeuron(n)->getPotential())*prev_bp_err;
for(u_int32_t w = 0;w < layers[l]->getNeuron(n)->getWeightsNum(); w++) {// For each weight
// Calculate delta weight, Dw = W + n*d*o
delta_weight = layers[l]->getNeuron(n)->getWeight(w) + l_rate*error*layers[l]->getNeuron(n)->getPotential();
// Update weight
layers[l]->getNeuron(n)->setWeight(w,delta_weight);
// Product smmation of current error and current weight
cur_bp_err += layers[l]->getNeuron(n)->getWeight(w)*error;
}
}
}
}
return 0;
}

Ho visto in molti esempi che vengono utilizzate matrici per lavorare con neuroni e rispettivi pesi di connessione, io ho preferito utilizzare questo stile perchè mi sembra più chiaro.

In questo momento stò cercando invano di addestrare la rete per eseguire l'operazione XOR.

Grazie per l'aiuto.

marco.r
27-08-2010, 15:21
Buondì.

Ho visto in molti esempi che vengono utilizzate matrici per lavorare con neuroni e rispettivi pesi di connessione, io ho preferito utilizzare questo stile perchè mi sembra più chiaro.

Grazie per l'aiuto.

Ciao, sulla questione del bias cerchero' di risponderti con calma stasera, intanto una mio opinione sul metodo di rappresentazione: meglio se usi le matrici, il codice diventa molto piu' compatto, piu' comprensibile (secondo me) e [b]molto[b] piu' efficiente.

La fase in avanti ad esempio la puoi implementare nel seguente modo:

std::vector<Matrix> W(nLayers);
std::vector<Vector> input(nLayers+1);
/* ... */
for ( size_t i=0 ; i< W.size() ; ++i )
{
input[i+1] = f( W*input[i] );
}

input.back() contiene l'output effettivo
Il feedback si scrive in modo parecchio simile.
f e' la versione vettoriale della funzione di attivazione (usarne una specifica per strato compila le cose un po' ma non molto).

shinya
27-08-2010, 15:39
[...]usarne una specifica per strato compila le cose un po' ma non molto.
Pun intended?? LOL :D

marco.r
27-08-2010, 16:47
Pun intended?? LOL :D

Direi lapsus freudiano... come quando scrivo server invece di serve :P

Teo@Unix
29-08-2010, 16:37
Il problema che ho durante l'addestramento per eseguire la XOR è che ho un output del genere, giusto in parte:

BIT_1 BIT_2 XOR NET_OUT DELTA
.....
1.000 1.000 0.000 1.048 -1.048
0.000 0.000 0.000 0.970 -0.970
0.000 1.000 1.000 1.018 -0.018
1.000 0.000 1.000 1.022 -0.022
1.000 1.000 0.000 1.045 -1.045
0.000 0.000 0.000 0.972 -0.972
0.000 1.000 1.000 1.017 -0.017
1.000 0.000 1.000 1.021 -0.021
1.000 1.000 0.000 1.042 -1.042
0.000 0.000 0.000 0.974 -0.974
0.000 1.000 1.000 1.016 -0.016
1.000 0.000 1.000 1.020 -0.020
1.000 1.000 0.000 1.040 -1.040
0.000 0.000 0.000 0.976 -0.976
0.000 1.000 1.000 1.016 -0.016
1.000 0.000 1.000 1.019 -0.019
1.000 1.000 0.000 1.037 -1.037
0.000 0.000 0.000 0.978 -0.978
....

mi da praticamente sempre uno...

Il codice è ora questo:

int NeuralNet::Train_BackPropagation(vector<_PRECISION> des_out) {
/* Backpropagation case */

// Verifiy that the hidden layer exists
if(des_out.size() != numOutputNeurons || numHiddenLayers <= 0 || numHiddenNeuronsPerLayer <= 0) return -1;

_PRECISION error, delta_weight, prev_bp_err = 0, cur_bp_err = 0;

for(u_int32_t l = layers.size()-1; l >= 0; l--) { // For each layer, begin from output
prev_bp_err = cur_bp_err;
cur_bp_err = 0;
if(!l) break; // Input layer has no weights
if(l==layers.size()-1) {// Output layer
for(u_int32_t n = 0;n < layers[l]->getNeuronNum();n++) { // For each neuron
// Calculate delta error, dk = (rk - ok)*f'(netk)

if(n==layers[l]->getNeuronNum()-1 && BIAS){ // for only bias neuron
error =
(des_out[n-1] - layers[l]->getNeuron(n)->getValue())*
layers[l]->getNeuron(n)->trans_func_derivate(layers[l]->getNeuron(n)->getPotential());
} else {
error =
(des_out[n] - layers[l]->getNeuron(n)->getValue())*
layers[l]->getNeuron(n)->trans_func_derivate(layers[l]->getNeuron(n)->getPotential());
}

for(u_int32_t w = 0;w < layers[l]->getNeuron(n)->getWeightsNum(); w++) {// For each weight
// Calculate delta weight, Dw = Wjk + -(n*dk*oj)
delta_weight = layers[l]->getNeuron(n)->getWeight(w) + -(l_rate*error*layers[l-1]->getNeuron(w)->getValue());
// Product smmation of current error and current weight
cur_bp_err += layers[l]->getNeuron(n)->getWeight(w)*error;
// Update weight
layers[l]->getNeuron(n)->setWeight(w,delta_weight);
}
}
} else { // Hidden layers and input
for(u_int32_t n = 0;n < layers[l]->getNeuronNum(); n++) {// For each neuron
// Calculate hidden layer error, remembering the previous propagated error
error = layers[l]->getNeuron(n)->trans_func_derivate(layers[l]->getNeuron(n)->getPotential())*prev_bp_err;
for(u_int32_t w = 0;w < layers[l]->getNeuron(n)->getWeightsNum(); w++) {// For each weight
// Calculate delta weight, Dw = W + -(n*d*o)
delta_weight = layers[l]->getNeuron(n)->getWeight(w) + -(l_rate*error*layers[l-1]->getNeuron(w)->getValue());
// Product smmation of current error and current weight
cur_bp_err += layers[l]->getNeuron(n)->getWeight(w)*error;
// Update weight
layers[l]->getNeuron(n)->setWeight(w,delta_weight);
}
}
}
}
return 0;
}

@marco.r
ora mantegno questa struttura solo per non dover riscrivere tutto, credo che poi proverò ad utilizzare le matrici.

Nella prova che ho fatto con XOR, il bias non lo ho utilizzato, quindi nel codice la var. "BIAS" vale 0.

Non ho capito l'errore che faccio. :confused:

Teo@Unix
01-09-2010, 19:41
:(

marco.r
01-09-2010, 21:12
Il problema che ho durante l'addestramento per eseguire la XOR è che ho un output del genere, giusto in parte:

Per quante iterazioni fai andare avanti l'addestramento ?
E che coefficiente di apprendimento usi ? (Di solito l'errore calcolato non lo si scala tutto dal peso, ma solo una piccola parte, tipo l'1%).

BIT_1 BIT_2 XOR NET_OUT DELTA
0.000 0.000 0.000 0.970 -0.970


Aspe', dici che non usi il vettore di bias ? :mbe:
Che funzione di attivazione (schiacciamento) stai usando ?

Teo@Unix
01-09-2010, 23:59
Per quante iterazioni fai andare avanti l'addestramento ?
E che coefficiente di apprendimento usi ? (Di solito l'errore calcolato non lo si scala tutto dal peso, ma solo una piccola parte, tipo l'1%).

ma..
se l'ascio andare l'esecuzione il valore delta assume valori periodici... quindi non si arriva ma all'addestramento...
per quanto riguarda l'errore che calcolo, non ho capito bene, la riga dove calcolo l'errore del layer nascosto ad esempio è:
error = layers[l]->getNeuron(n)->trans_func_derivate(layers[l]->getNeuron(n)->getPotential())*prev_bp_err;
quindi moltiplico il risultato della derivata con x uguale all' uscita del neurone corrente. (qui è giusto che utilizzo il potenziale e non il val. di trasf.?)

calcolo delta e aggiorno:
// Calculate delta weight, Dw = W + -(n*d*o)
delta_weight = layers[l]->getNeuron(n)->getWeight(w) + -(l_rate*error*layers[l-1]->getNeuron(w)->getValue())
layers[l]->getNeuron(n)->setWeight(w,delta_weight);

l'1% di "error" intendi?


Aspe', dici che non usi il vettore di bias ? :mbe:
Che funzione di attivazione (schiacciamento) stai usando ?

no, nell'esempio non ho utilizzato il bias.
tutto con funzione sigmoide.

c'è qualche erroraccio da qualche parte credo....
thanks.:)

marco.r
02-09-2010, 01:38
l'1% di "error" intendi?


no di delta. Non devi sommare direttamente il delta che trovi ma prima moltiplicarlo per un coefficiente relativamente basso, tipo 0.01 o 0.001 inm modo che il cambiamento dei pesi avventa molto lentamente.
Dal punto di vista matematico la backpropagation non e'altro che un metodo di ottimizzazione dove tu vuoi minimizzare la differenza tra output voluto e ottenuto.
La backpropagation lo fa con un metodo a discesa di gradiende ovveo, considera l'errore nel punto attuale (nello spazio dei pesi) e cerca di muoversi verso punti con errore piu'basso. Nel farlo pero'devi muoverti con calma, altrimenti rischi di impantanarti
Tu immagina di essere in mezzo ai monti, e il tuo errore e'la tua altitudine. Per minimizzarlo cosa fai ? Ti sposti verso dove la montagna scende, un passo alla volta.
Olra, se il passo e'piccolo funziona bene, ma se sei il gatto con gli stivali e fai salti da 500 metri puo' accadere che salti da una parte all'altra della valle, senza scendere di un cm, e poi tornare indietro al punto di prima, e cosi'via.
il discorso e'analogo

marco.r
02-09-2010, 01:40
no, nell'esempio non ho utilizzato il bias.
tutto con funzione sigmoide.

Intervallo [0,1] o [-1,1] ?

Teo@Unix
02-09-2010, 14:17
Intervallo [0,1] o [-1,1] ?

il mio intervallo dei pesi è [-1, 1].

Non posso provare subito ora, appena riesco faccio questa prova.

grazie :).

marco.r
02-09-2010, 14:22
il mio intervallo dei pesi è [-1, 1].

Non posso provare subito ora, appena riesco faccio questa prova.

grazie :).

Se l'intervallo dei pesi' e' [-1,1], allora la funzione in 0 vale zero. Il che vuol dire che con un input di [0,0] per la funzione XOR il tuo output dovrebbe essere sempre zero. E' anche per questo che si introduce la funzione di bias. Se ottieni per l'input nullo un output non nullo probabilmente c'e' un errore gia' nella fase in avanti (se non usi il bias)

Teo@Unix
02-09-2010, 14:27
Se l'intervallo dei pesi' e' [-1,1], allora la funzione in 0 vale zero. Il che vuol dire che con un input di [0,0] per la funzione XOR il tuo output dovrebbe essere sempre zero. E' anche per questo che si introduce la funzione di bias. Se ottieni per l'input nullo un output non nullo probabilmente c'e' un errore gia' nella fase in avanti (se non usi il bias)

Ok! Rivedrò le cose. Vediamo se vengo a capo del problema.
Farò sapere.