int fann_train_outputs(struct fann *ann, struct fann_train_data *data, float desired_error) { float error, initial_error, error_improvement; float target_improvement = 0.0; float backslide_improvement = -1.0e20f; unsigned int i; unsigned int max_epochs = ann->cascade_max_out_epochs; unsigned int min_epochs = ann->cascade_min_out_epochs; unsigned int stagnation = max_epochs; /* TODO should perhaps not clear all arrays */ fann_clear_train_arrays(ann); /* run an initial epoch to set the initital error */ initial_error = fann_train_outputs_epoch(ann, data); if(fann_desired_error_reached(ann, desired_error) == 0) return 1; for(i = 1; i < max_epochs; i++) { error = fann_train_outputs_epoch(ann, data); /*printf("Epoch %6d. Current error: %.6f. Bit fail %d.\n", i, error, ann->num_bit_fail); */ if(fann_desired_error_reached(ann, desired_error) == 0) { #ifdef CASCADE_DEBUG printf("Error %f < %f\n", error, desired_error); #endif return i + 1; } /* Improvement since start of train */ error_improvement = initial_error - error; /* After any significant change, set a new goal and * allow a new quota of epochs to reach it */ if((target_improvement >= 0 && (error_improvement > target_improvement || error_improvement < backslide_improvement)) || (target_improvement < 0 && (error_improvement < target_improvement || error_improvement > backslide_improvement))) { /*printf("error_improvement=%f, target_improvement=%f, backslide_improvement=%f, stagnation=%d\n", error_improvement, target_improvement, backslide_improvement, stagnation); */ target_improvement = error_improvement * (1.0f + ann->cascade_output_change_fraction); backslide_improvement = error_improvement * (1.0f - ann->cascade_output_change_fraction); stagnation = i + ann->cascade_output_stagnation_epochs; } /* No improvement in allotted period, so quit */ if(i >= stagnation && i >= min_epochs) { return i + 1; } } return max_epochs; }
FANN_EXTERNAL void FANN_API fann_train_on_data(struct fann *ann, struct fann_train_data *data, unsigned int max_epochs, unsigned int epochs_between_reports, float desired_error) { float error; unsigned int i; int desired_error_reached; #ifdef DEBUG printf("Training with %s\n", FANN_TRAIN_NAMES[ann->training_algorithm]); #endif if(epochs_between_reports && ann->callback == NULL) { printf("Max epochs %8d. Desired error: %.10f.\n", max_epochs, desired_error); } for(i = 1; i <= max_epochs; i++) { /* * train */ error = fann_train_epoch(ann, data); desired_error_reached = fann_desired_error_reached(ann, desired_error); /* * print current output */ if(epochs_between_reports && (i % epochs_between_reports == 0 || i == max_epochs || i == 1 || desired_error_reached == 0)) { if(ann->callback == NULL) { printf("Epochs %8d. Current error: %.10f. Bit fail %d.\n", i, error, ann->num_bit_fail); } else if(((*ann->callback)(ann, data, max_epochs, epochs_between_reports, desired_error, i)) == -1) { /* * you can break the training by returning -1 */ break; } } if(desired_error_reached == 0) break; } }
/* Cascade training directly on the training data. The connected_neurons pointers are not valid during training, but they will be again after training. */ FANN_EXTERNAL void FANN_API fann_cascadetrain_on_data(struct fann *ann, struct fann_train_data *data, unsigned int max_neurons, unsigned int neurons_between_reports, float desired_error) { float error; unsigned int i; unsigned int total_epochs = 0; int desired_error_reached; if(neurons_between_reports && ann->callback == NULL) { printf("Max neurons %3d. Desired error: %.6f\n", max_neurons, desired_error); } for(i = 1; i <= max_neurons; i++) { /* train output neurons */ total_epochs += fann_train_outputs(ann, data, desired_error); error = fann_get_MSE(ann); desired_error_reached = fann_desired_error_reached(ann, desired_error); /* print current error */ if(neurons_between_reports && (i % neurons_between_reports == 0 || i == max_neurons || i == 1 || desired_error_reached == 0)) { if(ann->callback == NULL) { printf ("Neurons %3d. Current error: %.6f. Total error:%8.4f. Epochs %5d. Bit fail %3d", i-1, error, ann->MSE_value, total_epochs, ann->num_bit_fail); if((ann->last_layer-2) != ann->first_layer) { printf(". candidate steepness %.2f. function %s", (ann->last_layer-2)->first_neuron->activation_steepness, FANN_ACTIVATIONFUNC_NAMES[(ann->last_layer-2)->first_neuron->activation_function]); } printf("\n"); } else if((*ann->callback) (ann, data, max_neurons, neurons_between_reports, desired_error, total_epochs) == -1) { /* you can break the training by returning -1 */ break; } } if(desired_error_reached == 0) break; if(fann_initialize_candidates(ann) == -1) { /* Unable to initialize room for candidates */ break; } /* train new candidates */ total_epochs += fann_train_candidates(ann, data); /* this installs the best candidate */ fann_install_candidate(ann); } /* Train outputs one last time but without any desired error */ total_epochs += fann_train_outputs(ann, data, 0.0); if(neurons_between_reports && ann->callback == NULL) { printf("Train outputs Current error: %.6f. Epochs %6d\n", fann_get_MSE(ann), total_epochs); } /* Set pointers in connected_neurons * This is ONLY done in the end of cascade training, * since there is no need for them during training. */ fann_set_shortcut_connections(ann); }