Trovato il nuovo valore del campo "delta" per ogni sinapsi, basterà ciclare in tutta la rete e per ogni sinapsi applicare quel delta sul peso:
//STEP 6:Update all weights commit_weight_changes(net->output_layer); commit_weight_changes(net->hidden_layer);[...]
//COMMIT_WEIGHT_CHANGES
void commit_weight_changes(layer* lPtr){
int i,j;
neurodo* nPtr;
sinapsi* sPtr;
for(i=0;i < lPtr->num_elements;i++){
nPtr = lPtr->elements[i];
for(j=0;j < nPtr->num_in_links;j++){
sPtr = nPtr->in_links[j];
sPtr->weight += sPtr->delta;
sPtr->delta = 0;
}
}
}
Per il layer hidden e output, e per ogni neurodo in essi, applichiamo il delta al peso delle sinapsi in entrata al neurodo.
Da notare che dopo questa operazione il valore di "delta" viene resettato.
Forse non ci crederete, ma effettuando queste operazioni più e più volte, ovvero nell'ordine dei 300-400 cicli, la rete avrà imparato ad eseguire le somme con un margine di errore che va da fino a . Non male vero? Ognuno di questi cicli verrà chiamato "epoca".
Riassumiamo perciò tutto in un bel for nel main(), e eseguiamolo per un numero di volte pari a max_epochs (che possiamo variare a nostro piacimento in init_net())
for(j=0;j< net->max_epochs;j++){
//STEP 1:Read input values
for(i=0;i < net->input_layer->num_elements;i++){
if((status = get_data(&temp,fd)) < 0){
fprintf(stderr,"errore irreversibile, closing...\n");
free_memory_nnet(net);
return -1;
}
net->input_layer->elements[i]->prop_value=(_PRECISION)temp;
net->input_layer->elements[i]->actv_value=(_PRECISION)temp;
}
//STEP 2:Propagate values into hidden layer
propagate_into_layer(net->hidden_layer);
//STEP 3:Propagate values into output layer
propagate_into_layer(net->output_layer);
//STEP 4:Compute delta rule for the output layer
if((status = get_data(&des_out,fd)) < 0){
fprintf(stderr,"errore irreversibile, closing...\n");
return -1;
} else {
out_delta = compute_output_delta(net->output_layer->elements[0]->prop_value,des_out);
update_output_weights(net->output_layer,out_delta,net->l_rate);
}
//STEP 5:Compute delta rule for the hidden layer
update_hidden_weights(net->hidden_layer,out_delta,net->l_rate);
//STEP 6:Update all weights
commit_weight_changes(net->output_layer);
commit_weight_changes(net->hidden_layer);
net_output = net->output_layer->elements[0]->prop_value;
printf("DES=%f\tERROR=%f\tOUT=%f\tDELTA=%f\n",des_out,
(des_out-net_output),net_output,out_delta);
} //END MAIN LOOP
Questo è il cuore dell'apprendimento della nostra rete: vengono riassunti i 6 passi fondamentali che ho spiegato prima,
con le varie chiamate alle funzioni da noi già analizzate. In più c'è la stampa di informazioni di debug sul risultato
ottenuto dopo ogni epoca. Quello che voi dovreste vedere eseguendo il programma è che dopo un pò il valore di ERROR
assume valori sempre più piccoli tendendo (si spera) a qualcosa di simile allo 0.