GUIDA ALLE RETI NEURALI (brevissima introduzione) Prima di tutto è necessario caricare i seguenti pacchetti (MASS, kernlab, neuralnet, nnet, caret). In questa guida verrà utilizzato un dataset già presente in R (biopsy), perchè si presta come struttura, all’utilizzo in una rete neurale. Presenta 11 colonne, la prima inutilizzabile perché è un indicatore (ID); l'ultima contiene i dati in output. library(MASS); library(kernlab); library(neuralnet); library(nnet); library(caret); data(biopsy); head(biopsy) dataBio<-biopsy[,2:11] #escludiamo la colonna 1 perché non è una variabile predittiva A questo punto trasformiamo in numerico il contenuto della colonna di output, facendo corrispondere 1 benigno, 2 a maligno). dataBio$class<-as.numeric(dataBio$class) In questo dataset esistono valori nulli in qualche colonna, quindi consideriamo solo le righe dove sono presenti tutti i dati. good<-complete.cases(dataBio) GBio<-dataBio[good,] # estraiamo dal dataset dataBio, solo le righe "good". Da qui, trasferiremo ulteriormente i nostri output, da numerico a binario. 0 corrisponderà a benigno, 1 a maligno. for(i in 1:nrow(GBio)){ if (GBio[i,10] == 1) { GBio[i,10]<-0 } else { GBio[i,10]<-1 } } In seguito, suddividiamo il nostro dataset in 2 partizioni: la prima servirà per allenare la rete neurale, mentre la seconda servirà per testare la sua attendibilità. inTrain<-createDataPartition(y=GBio$class,p=0.75,list=FALSE) training<-GBio[inTrain,] testing<-GBio[-inTrain,] tsld sta per threshold, ed è il vettore contenente i possibili valori soglia che vogliamo utilizzare Per calibrare la nostra rete neurale, si utilizzeranno i valori presenti nel vettore in differenti cicli e si osserverà come l'attendibilità della rete cambia al modificarsi delle soglie utilizzate. tsld<-c(0.20,0.15,0.1,0.020,0.015,0.010,0.0015,0.001,0.0001) Le soglie possono essere impostate arbitrariamente. nNascosti sta per hidden, cioè la variabile utilizzata dalla rete neurale come numerosità dei neuroni nascosti da utilizzare. Questo è un vettore numerico e come per tsld, verrà utilizzato in differenti cicli in cui si osserverà il variare dell'attendibilità della rete al cambiare dei neuroni nascosti utilizzati. nNascosti<-c(5,6,7,8,9,10) Ciò che segue è un vettore che conterrà un elemento della tabella riassuntiva finale. Neuroni sarà la colonna di lunghezza 6 (6 elementi del vettore nNascosti) X 9 (9 elementi del vettore tsld) = 56. Ripete semplicemente (comando rep) tutti gli elementi della colonna nascosti per il numero di elementi del vettore tsld. La rete neurale verrà testata con il primo elemento del vettore nNascosti e con tutti gli elementi del vettore tsld, successivamente con il secondo elemento del vettore nNascosti e di nuovo per tutti gli elementi del vettore tsld e così via. neuroni<-c() #vettore delle possibili combinazioni del numero di neuroni #nascosti for(i in 1:length(nNascosti)){ neuroni<-c(neuroni,rep(nNascosti[i],length(tsld))) } Thresholds sarà il vettore contenente il vettore tsld ripetuto per il numero di elementi presenti nel vettore nNascosti. Sia thresholds che neuroni, serviranno solo in sede di osservazione dei valori di attendibilità della rete neurale. thresholds<-rep(tsld,length(nNascosti)) Le righe che seguiranno sono la rete neurale vera e propria. Le variabili errori ed Err sono degli accumulatori, ossia estraggono il valore di errore e lo conservano ad ogni giro dei differenti cicli a cui è sottoposta la rete. errori<-c(); Err<-c() nc<-99 #valore da aggiungere nel ciclo se la rete non converge Il valore rp è il numero di ripetizioni che si chiede alla rete di fare, ossia la rete ripeterà la stessa struttura, cioè lo stesso numero di neuroni, lo stesso numero di soglia per il valore attribuito rp. In seguito verranno calcolate la media e la varianza degli errori commessi dei differenti gruppi di valori corrispondenti alle differenti combinazioni. rp<-6 #numero di ripetizioni for(u in 1:length(nNascosti)){ #questo ciclo testa la rete al cambiare del numero di #neuroni nascosti errori<-c() for (i in 1:length(tsld)){ #questo ciclo testa la rete al variare del valore soglia Bionet<-neuralnet(training[,10] ~ training[,1] + training[,2] + training[,3] + training[,4] + training[,5] + training[,6] + training[,7] + training[,8] + training[,9], data=training, hidden=nNascosti[u], lifesign="minimal", linear.output=FALSE, rep=rp,threshold=tsld[i]) a<-Bionet$result.matrix[1,] #a è il vettore contenente i valori di errore #nelle differenti ripetizioni. if(length(a)!=6){ #se la rete non converge, il numero di elementi di a #diminuisce m<-rp-length(a) a<-c(a,rep(nc,m)) #se la rete non converge ad una certa #combinazione/ripetizione } #verrà attribuito un valore arbitrario elevato (in questo caso 99) al errore errori<-rbind(errori,a) #accumulatore degli errori } Err<-rbind(Err,errori) } Successivamente verranno calcolati l'errore medio e la varianza media degli errori nelle differenti ripetizioni. ErrMedio<-apply(Err,1,mean) VarMedia<-apply(Err,1,var) La tabella riassunto combina tutti gli elementi, permettendoci di poter osservare a quale combinazione corrispondono i differenti valori di errore, in modo da poterci suggerire quale combinazione sia la più adeguata riassunto<-cbind(neuroni,thresholds,ErrMedio,VarMedia) riassunto<-riassunto[order(riassunto[,3]),] #con questo comando ordiniamo la #tabella riassunto in ordine crescente d'errore Chiameremo best il vettore che contiene la miglior combinazione di elementi, che minimizza in media l'errore di previsione della rete neurale. best<-subset(riassunto,riassunto[,3]==min(riassunto[,3])) Lanciamo nuovamente la nostra rete neurale, ma questa volta con gli elementi del vettore best, per una ripetizione. Bionet<-neuralnet(training[,10] ~ training[,1] + training[,2] + training[,3] + training[,4] + training[,5] + training[,6] + training[,7] + training[,8] + training[,9], data=training, hidden=best[1], lifesign="minimal", linear.output=FALSE, rep=1, threshold=best[2]) Una volta pronta la nostra rete neurale, settata con i valori migliori in media, non resta che testarne attendibilità con i dati del dataset che erano stati inizialmente separati tramite createDataPartition. La nostra rete neurale Bionet ha 9 neuroni di input, corrispondenti alle 9 variabili utilizzate nel suo apprendimento. È necessario quindi, che anche il dataset su cui andrà testata contenga solo 9 colonne. Creeremo un nuovo dataset testing2, che contiene solo le prime 9 colonne (essendo la decima quella di output). testing2<-testing[,1:9] La variabile result contiene il risultato della elaborazione dei dati di testing2 con la rete neurale Bionet result<-compute(Bionet,testing2) Arrotondiamo i risultati (round) della previsione. previsione<-round(result$net.result) A questo punto mettiamo assieme i dati reali di output, la decima colonna della variabile testing, e i dati della previsione ottenuti con la rete neurale. confronto<-cbind(testing[,10],previsione) Per sapere quante volte la rete non ha trovato il valore reale di output si utilizzi il seguente comando: length((tf<-testing[,10]==previsione)[which(tf==FALSE)]) Nell’esempio appena presentato, la componente “algorithm” al interno della rete neurale non è stata inserita, in questo caso neuralnet utilizza l’algoritmo “resilient back propagation(rprop+)” con l’attribuzione dei pesi a ritroso “weight backtracking”: questo algoritmo si basa sul tradizionale algoritmo di back propagation, che modifica il peso della rete neurale per modificare l’errore quadratico medio tra gli output desiderati e quelli ottenuti. In altre parole, si sottopone più volte il training-set alla rete, aggiustando i pesi per minimizzare l’errore. Il pacchetto neuralnet, mostrato nell’esempio, permette di utilizzare i seguenti algoritmi: “backprop”, “rprop+”, “rprop-“, “sag”, o “slr” attraverso l’aggiunta della voce algorithm=”…”, sostituendo ai puntini, uno degli algoritmi precedentemente elencati. Nel rprop+ (resilient back propagation) utilizzato nell’esempio, la variazione dei pesi avviene solo dopo aver elaborato tutti gli esempi dell’insieme di apprendimento. Gli algoritmi “sag” e “slr”, sono basati, il primo sul tasso di apprendimento associato al minor gradiente assoluto, mentre il secondo sul tasso di apprendimento più piccolo. Un ulteriore metodo di apprendimento supervisionato di una rete neurale è l’algoritmo di feed forward (pacchetto nnet); elaborato da McCulloch e Pitts, l’algoritmo feed forward è il metodo più diretto e “semplice” di costruire una rete neurale. In questo modello, l’informazione si muove in avanti (forward), dai neuroni di input passa attraverso i neuroni nascosti, per arrivare ai nodi di output. I singoli ingressi vengono moltiplicati per un valore, detto peso: il risultato delle operazioni viene sommato e se la somma supera un certo valore soglia, il neurone si attiva, facendo partire l’informazione. Il peso è fondamentale per quantificare l’importanza di un ingresso (un nodo di input molto importante avrà un peso elevato, mentre un altro ingresso poco utilizzato avrà un peso minore); teoricamente, se durante l’addestramento della rete, due neuroni comunicano fra loro utilizzando maggiormente alcune connessioni, queste ultime avranno un peso maggiore, in modo da costituire dei percorsi preferenziali, che si svilupperanno tenendo sempre attive tutte le combinazioni tra i vari nodi a seconda del loro peso. La differenza tra i due metodi sta nel processo di attribuzione dei pesi, uno li attribuisce “in avanti” dallo strato di input a quello di output, e l’altro “a ritroso” dallo strato di output a quello di input. COME COSTRUIRE UNA RETE NEURALE (con nnet). La struttura della funzione nnet è simile a quella utilizzata in neuralnet. Carichiamo il dataset “biopsy”, prendiamo in considerazione solo le colonne dalla 1 alla 11, trasformiamo l’ultima colonna in numerico e poi in binario e filtriamo le righe che hanno valori nulli, prendendo in considerazione solo i casi completi. data(biopsy); dataBio<-biopsy[,2:11]; dataBio[,10]<-as.numeric(dataBio[,10]) for(i in 1:nrow(dataBio)){ if(dataBio[i,10]==1){ dataBio[i,10]<-0}else{dataBio[i,10]<-1}} complete<-complete.cases(dataBio) dataBio<-dataBio[complete,] Il nuovo dataset comprende ora solo 683 righe. Con il seguente comando, si sceglieranno 483 numeri casuali da 1 a 683 e si utilizzeranno questi numeri per estrarre dal dataset completo sia la partizione di training che la partizione di testing. In questa occasione gli output verranno separati dagli input, creando trainBio (tabella con 483 righe contenente solo gli input) e targetBio (tabella contenente gli output delle 483 righe selezionate per il training). sampTrain<-sample(1:683,483) # scegli 483 numeri casuali da 1 a 683 trainBio<-dataBio[sampTrain,1:9]; trainBio<-as.matrix(trainBio) targetBio<-dataBio[sampTrain,10]; targetBio<-as.matrix(targetBio) Le 200 righe rimaste fuori dal training andranno a comporre il dataset di controllo; anche questo dovrà essere suddiviso in dati in input (testBio) e dati in output (testBioY). testBio<-dataBio[-sampTrain,1:9]; trainBio<-as.matrix(trainBio) testBioY<-dataBio[-sampTrain,10]; testBioY<-as.matrix(testBioY) La rete neurale con nnet è la seguente: Bionet<-nnet(trainBio, targetBio,size=10,rang=0.1,decay=5e-4, maxit=200) VF<-round(predict(Bionet,testBio))==testBioY; VF<-as.data.frame(VF) result<-cbind(stima<predict(Bionet,testBio),round(predict(Bionet,testBio)),testBioY,VF); result<-as.data.frame(result); names(result)<c("stima","stimaArrotondata","reale", "VF") result Rang definisce l’intervallo di variazione entro cui i pesi saranno scelti casualmente [-rang; +rang]. Decay (opzionale, se assente nnet lo imposterà a 0) è il parametro che indica il peso del decadimento. Maxit(opzionale, se assente nnet lo imposterà a 100) è il massimo numero di iterazioni. Il plottaggio della rete neurale in nnet purtroppo non è possibile con il comando plot(). Esiste però una funzione creata apposta: https://gist.githubusercontent.com/fawda123/7471137/raw/466c1474d0a505ff 044412703516c34f1a4684a5/nnet_plot_update.r Il link qui sopra vi porta alla pagina dove è caricata la funzione. Questa dovrà essere selezionata tutta, copiata ed incollata cosi come si trova nel terminale di R, in questo modo si potrà creare la funzione plot.nnet(). Per avere la visuale grafica della vostra rete basterà quindi eseguire plot.nnet(vostrarete).
© Copyright 2024 ExpyDoc