3.3 Librerie Usate
4.1.1 Utilizzo della Libreria
Questa sezione `e volta ad illustrare l’utilizzo della funzionalit`a offerte dalla libreria felix, e propone una serie di esempi di semplice utilizzo di alcune delle sue funzionalit`a. Come in ogni libreria C++, il primo passo per utilizzare felix consiste nell’includere le componenti necessarie allo scopo. Per evitare problemi di aliasing, tutte le componenti
di felix sono contenute all’interno del namespace felix, il quale sar`a omesso in tutti gli esempi forniti in seguito.
Sebbene l’utilizzo di un descrittore sia suggerito in caso di addestramento, per effettuare un semplice test di un modello preaddestrato su un dataset `e sufficiente istanziare direttamente gli oggetti relativi al dataset e al modello.
Ad esempio, il seguente codice rappresenta un programma completo per testa- re un modello NN4G, il cui path `e passato come primo argomento, su un dataset GraphDataset, il cui path `e il secondo argomento:
Listing 4.1: Esempio di Testing di un Modello try{
/// load the dataset
GraphDataset* dataset=new GraphDataset(argv[2]); /// load the model
NN4G* model2test=new NN4G(argv[1]); /// test model and print the results
result_package* result=Result::testModelOnDataset(model2test,dataset );
cout<<"Test results: "<<result->str()<<endl;
delete result;
delete dataset;
delete model2test;
}catch(runtime_error e){
cerr<<"ERROR: "<<e.what()<<endl; }
La funzione statica testModelOnDataset `e una funzione ausiliaria che permette di ef- fettuare dei semplici test. Il risultato viene stampato a video mediante la funzione polimorfica str di resultpackage, e il suo formato sar`a unicamente dipendente dal tipo
di task del dataset.
Ad esempio, se il dataset ha un task di regressione, verr`a stampato il valore di M aE, M axAbsErr, R ed S (vedere Sez. 2.1), mentre nel caso di classificazione saranno presenti i valori di M aE, M axAbsErr e Acc e, nel caso di classificazione binaria, i valori della matrice di confusione.
Descriveremo ora un esempio di addestramento ex-novo di un modello, mediante il caricamento di un descrittore. Per prima cosa si dichiarano le strutture dati che
4.1 Libreria felix 59
useremo:
Listing 4.2: Dichiarazione delle Strutture Dati
TaskDescriptor* descriptor; iDataset* training_set; iDataset* validation_set; vector<vector<iDataset*> > mainDatasets; iNeuralNet* model; iLearningAlgorithm* learning; Result* final_result;
incluse le abstract factory:
Listing 4.3: Creazione delle Abstract Factory
DatasetFactory dsf; ModelsFactory mfactory;
LearningAlgorithmsFactory lfactory;
adesso `e possibile caricare il descrittore, il cui path nel file system `e assunto essere il primo argomento passato al tool:
Listing 4.4: Caricamento del Descrittore dal File System
descriptor = new TaskDescriptor(argv[1]);
il dataset verr`a caricato in una matrice di istanze di dataset:
Listing 4.5: Caricamento e Separazione del Dataset
mainDatasets = dsf.makeConcreteInstances(descriptor->dataParameters);
la necessit`a di usare una matrice `e dovuto alla necessit`a di trattare separazione di tipo Hold Out e CV.
Nel primo caso, il training e il validation set saranno memorizzati in mainDatase- ts[0][0] e mainDatasets[1][0].
Nel secondo caso, seguendo la notazione usata in Sez. 2.1.1.2, abbiamo il training setDtr(i) conservato in mainDatasets[0][i], mentre il validation set Dval(i) `e conservato in mainDatasets[1][i].
La separazione avviene automaticamente all’interno dell’invocazione di makeCon- creteInstance dell’abstract factory, in base alle informazioni presenti nel descrittore.
Listing 4.6: Recupero del Numero di Folds
unsigned int nFolds = mainDatasets[0].size();
ed `e possibile testarlo per effettuare l’addestramento di tipo Hold Out o CV. Nel primo caso abbiamo:
Listing 4.7: Esecuzione del Training di Tipo Hold Out if(nFolds==1){
training_set = mainDatasets[0][0]; validation_set = mainDatasets[1][0]; /// make the model
model = mfactory.makeConcreteInstance(descriptor->modelParameters, training_set);
/// make the learning algorithm
learning = lfactory.makeConcreteInstance(descriptor->
learningAlgorithmParameters, training_set, validation_set, model) ;
/// perform the training learning->start_training(); /// keep the results
final_result = learning->results; }
Come `e possibile osservare, i passi prevedono:
• la creazione del modello e dell’algoritmo di apprendimento, usando le rispettive abstract factory;
• l’avvio dell’addestramento mediante l’invocazione di start training dell’algoritmo di apprendimento;
• la memorizzazione del risultato, presente nell’istanza dell’algoritmo di apprendi- mento;
Nel caso di separazione CV, abbiamo:
Listing 4.8: Esecuzione del Training di Tipo CV else{
vector<felix::Result*> partial_results;
4.1 Libreria felix 61
/// get the i-th training and validation set training_set = mainDatasets[0][i];
validation_set = mainDatasets[1][i]; /// make the model
model = mfactory.makeConcreteInstance(descriptor->modelParameters, training_set);
/// make the learning algorithm
learning = lfactory.makeConcreteInstance(descriptor->
learningAlgorithmParameters,training_set,validation_set,model); /// perform the training
learning->start_training(); /// save a result’s copy
partial_results.push_back(learning->results); }
final_result = new ResultsCVCollector(partial_results); }
In questo caso, i risultati parziali dell’addestramento sulle diverse fold, vengono con- servati all’interno del vettore partial results, usato a training terminato per generare un’istanza di ResultsCVCollector.
Indipendentemente dal tipo di training usato, il salvataggio e la stampa del risultato finale `e eseguito mediante il seguente codice:
Listing 4.9: Salvataggio e Stampa del Risultato
string training_str, validation_str; training_str = validation_str = "";
final_results->lastResults2str(training_str, validation_str); cout << "Final Results:" << endl
<< "Training: " << training_str << endl << "Validation: " << validation_str << endl;
string resultsPath=final_result->save(descriptor); cout << "Results saved in: " << resultsPath << endl;
L’esempio mostrato tralascia, per ragioni di semplicit`a espositiva, la gestione delle eccezioni e l’eliminazione delle strutture dati create. L’esempio completo, con il trat- tamento di questi aspetti e l’uso di altri piccoli accorgimenti, `e disponibile in App.
Da questo esempio, `e possibile notare come il codice sia indipendente dal tipo di mo- dello e algoritmo di apprendimento usato. Queste informazioni sono contenute all’inter- no del descrittore, e le istanze corrette del modello e dell’algoritmo di apprendimento, con i relativi iperparametri, vengono create mediante le abstract factory.
Sempre nel descrittore, saranno presenti le informazioni relative alla posizione del dataset nel file system, al tipo di separazione da usare, all’eventuale presenza di un seed preimpostato e alla directory dove verr`a salvato il risultato.