cerca
Sistemi Intelligenti - Appunti del 21 Ottobre
modifica cronologia stampa login logout

Wiki

UniCrema


Materie per semestre

Materie per anno

Materie per laurea


Help

Sistemi Intelligenti - Appunti del 21 Ottobre

Torna alla pagina di Sistemi Intelligenti


 :: Sistemi Intelligenti - Appunti del 21 Ottobre ::

La lezione di oggi è stata tenuta in laboratorio dal prof Ferrari.

Oggi si lavora un po' su Matlab. Per chi avesse bisogno di un ripassone sull'ambiente e sul linguaggio, su Swappa trovate una guida: Introduzione al Matlab.
Useremo in particolare il toolbox "Neural Network Toolbox".

Primo programma

Con il primo programma cercheremo di approssimare con una funzione il profilo di una persona. Nel dataset che ci viene messo a disposizione avremo un elenco di coordinate cartesiane (ingresso, uscita) che rappresentano i valori noti della nostra funzione.

Il materiale di riferimento è scaricabile da: http://www.dti.unimi.it/~ferrari/reti_neurali/toolbox_nn/

Copiate i file in una cartella e selezionate quest'ultima come "Current Directory" in Matlab. Durante la lezione è saltato fuori che il programma prova_ff.m aveva numerosi comandi ridondanti, che con la versione nuova del toolbox non erano più necessari (si trattava di accorgimenti per mappare gli spazi degli ingressi e delle uscite).
Di seguito pubblicherò prima il programma prova_ff.m originale commentato, poi quello che useremo in realtà.

%prova_ff.m - ORIGINALE, COMMENTATO

load prof1; %carica i dati contenuti nel file prof1.mat

p = X';
t = Y';

%'mapminmax' prende un insieme di dati (p) e li rimappa sull'intervallo dato,
%che in questo caso che va da 0 a 1. Questa procedura è utile per normalizzare
%gli input. Particolarmente utile nelle RBF quando i dati di input sono
%unidimensionali e le grandezze non sono tra loro confrontabili. La
%risposta di mapminmax sono i nuovi valori rimappati (p2) e le informazioni
%necessarie (ps) per invertirlo più avanti verso la fine del codice

%Usiamo quindi mapminmax, rimappando sia gli ingressi..
[p2,ps] = mapminmax(p, 0, 1);
%..che le uscite. Operazione questa particolarmente necessaria dato che la 
%funzione 'tansig' che useremo darà come risposta valori tra -1 e 1 (e non come
%vogliamo, da 1 a 0)
[t2,ts] = mapminmax(t, 0, 1);

%'dividevec' prende in ingresso un dataset (p2,t2) (ingresso e uscita), e poi 
%le percentuali di dataset che andranno a costituire il dataset di 
%validazione e quello di testing. Quello che produce sono i dati che saranno
%utilizzati per il training
[trainV,val,test] = dividevec(p2, t2, 0.20, 0.20);

%'newff' crea una nuova rete feed-forward e mette il risultato nella
%variabile net.
%Argomenti di newff:
%1. stabilisce l'intervallo di funzionamento della rete, in cui cadranno 
%   gli input. "minmax(p2)" equivale a dire "[min(p2) max(p2)]". Serve 
%   quindi per l'inizializzazione dei parametri interni. 
%2. dice che ci sono due strati, nel nostro caso uno di venti unità e l'altro
%%   di 1
%3. identificano il tipo di neurone degli strati indicati precedentemente.
%   'Tansig' è infatti un tipo di funzione di attivazione
net = newff(minmax(p2), [20 1], {'tansig', 'tansig'});

%net non è solo una matrice, ma è anche una struttura. Uno dei campi più 
%importanti di net.trainParam è ''epochs'', che permette di configurare il
%numero di iterazioni che andranno fatte sulla rete net durante l'addestramento
net.trainParam.epochs = 20;

%'train' fa partire l'addestramento e restituisce la rete addestrata.
%Argomenti di train che useremo:
%1. la rete
%2. il valore di ingresso per l'addestramento
%3. il valore di uscita per l'addestramento
%4-5. lasciati vuoti
%6. i dati che saranno utilizzati per l'addestramento (che serviranno a stimare 
%   se stiamo procedendo nella direzione desiderata)
%7. per stimare alla fine dell'addestramento quanto bene la rete è riuscita
%   ad approssimare i dati in ingresso
[net,tr]=train(net, trainV.P, trainV.T, [], [], val, test);

%'sim' fa la simulazione a partire dalla rete data e dai dati di input.
%Gli passeremo la rete già inizializzata ed i valori di ingresso con i quali
%vogliamo calcolare l'uscita. 
%a2 è la variabile che conterrà la risposta della rete
a2 = sim(net, p2);

%applichiamo ad a2 la trasformazione inversa che avevamo applicato ai dati
%di ingresso della rete (quando abbiamo fatto i mappaggi), così da ottenere 
%un nuovo vettore a. Questo potrà essere confrontato con la parte dei dati che
%rappresentavano le uscite desiderate
a = mapminmax('reverse', a2, ts);

%'postreg' dà una stima della rete di regressione tra i dati di uscita
%ottenuti e quelli desiderati. Sostanzialmente ci dice quanto è stata brava
%la rete a stimare le uscite
[m,b,r] = postreg(a, t);

%ed ora stampo a video i risultati
figure;
axis equal;
hold on
plot(p,t, '.', 'MarkerSize', 5);
plot(p,a,'r-', 'LineWidth', 2);

Ricapitolando, i tre comandi fondamentali della toolbox che abbiamo usato sono: newff, train e sim.

Come già detto, la versione attuale di "Neural Network Toolbox" rende superflui e incasinanti i vari accorgimenti sul rimappaggio dei dataset: tutto ciò che chiede sono gli ingressi e le uscite, poi se la vede lui. Ecco quindi il listato del programma modificato e funzionante.

%prova2_ff.m

load prof1; %carica i dati contenuti nel file prof1.mat

p = X';
t = Y';

%'newff' crea una nuova rete feed-forward e mette il risultato nella
%variabile net.
%Argomenti di newff:
%1-2. stabiliscono l'intervallo di funzionamento della rete, in cui cadranno 
%     input e output. Servono all'inizializzazione dei parametri interni. 
%3. dice che ci sono due strati, nel nostro caso uno di venti unità e l'altro
%   di 1
%4. identificano il tipo di neurone degli strati indicati precedentemente.
%   'Tansig' è infatti un tipo di funzione di attivazione
net = newff(p, t, [20 1], {'tansig', 'tansig'});

%net non è solo una matrice, ma è anche una struttura. Uno dei campi più 
%importanti di net.trainParam è ''epochs'', che permette di configurare il
%numero di iterazioni che andranno fatte sulla rete net durante l'addestramento
net.trainParam.epochs = 20;

%'train' fa partire l'addestramento e restituisce la rete addestrata.
%Argomenti di train:
%1. la rete
%2. i valori di ingresso per l'addestramento
%3. i valori di uscita per l'addestramento
[net,tr]=train(net, p, t);

%'sim' fa la simulazione a partire dalla rete data e dai dati di input.
%Gli passeremo la rete già inizializzata ed i valori di ingresso con i quali
%vogliamo calcolare l'uscita. La variabile a contiene la risposta della rete
a = sim(net, p);

%'postreg' dà una stima della rete di regressione tra i dati di uscita
%ottenuti e quelli desiderati. Sostanzialmente ci dice quanto è stata brava
%la rete a stimare le uscite
[m,b,r] = postreg(a, t);

%ed ora stampo a video i risultati
figure;
axis equal;
hold on
plot(p,t, '.', 'MarkerSize', 5);
plot(p,a,'r-', 'LineWidth', 2);

Bene, una volta salvato il programma lo lanciamo nella command window scrivendo il suo nome e premendo INVIO.

Ci apparirà la finestra accanto, che contiene informazioni sull'apprendimento della nostra rete. In particolare notiamo che non è stato fatto con la backpropagation, ma con il metodo Levenberg-Marquardt ; se infatti forzassimo la rete ad utilizzare la backpropagation, i risultati peggiorerebbero in modo imbarazzante.

Dei tre pulsanti che appaiono in questa finestra citiamo in particolare:

  • Performance, permette di ottenere il grafico degli errori (di apprendimento, validazione e test). In particolare, se vediamo che l'errore di training sta sotto quello di validazione potrebbe dire che la rete sta overfittando, oppure che l'insieme di validazione è troppo piccolo. Dal grafico delle performance scopriamo quindi qual è un buon punto in cui fermare l'addestramento per evitare l'overfitting
  • Regression, che mostra il rapporto tra risultato ottenuto dalla rete e risultato atteso. I risultati sono divisi in funzione della destinazione degli esempi utilizzati (apprendimento, validazione e test), più un ulteriore caso in cui vengono considerati insieme tutti gli aspetti. In tutti i casi, se il valore di R risulta abbastanza vicino a 1 significa che abbiamo ottenuto una buona stima. In particolare, se nel grafico del training vedessimo molti punti fuori dalla retta (e quindi basso valore di R), otterremo sicuramente una pessima ricostruzione della funzione


Vediamo ora le altre due finestre che sono apparse con quella appena descritta:

Figure 1
Si tratta dello stesso grafico che abbiamo visto nel quarto riquadro della finestra "Regression", ed è infatti la rappresentazione grafica del rapporto tra il risultato ottenuto dalla rete (i cerchietti) e il risultato atteso (i punti della retta rossa).
Come si può vedere, nel nostro caso abbiamo ottenuto un buon risultato.

Figure 2
La linea spezzata rossa rappresenta l'approssimazione dei dati di esempio (i puntini blu). Avevamo detto che il dataset conteneva informazioni per ottenere il profilo di una persona, e a giudicare dal risultato direi che l'abbiamo approssimato per bene.

I risultati migliori si possono migliorare andando a giochicchiare coi vari parametri, ovvero:

  • aumentare o diminuire il numero di epoche. In generale possiamo affermare che maggiore è il numero di epoche e migliori sono i risultati
  • cambiare il numero di neuroni del primo strato. In questo caso non è detto che aumentando il loro numero il risultato migliori sempre; possiamo però affermare che se lo diminuiamo aumentiamo la capacità di generalizzazione della rete
  • cambiare il tipo di neuroni utilizzati. Finora abbiamo usato sempre quelli con funzione di attivazione "tansig", ma potremmo utilizzare quelli "logsig" (per i dettagli e le caratteristiche conviene dare un occhio al manuale della Neural Network Toolbox)
  • cambiare l'algoritmo di apprendimento. Ad esempio per forzare a utilizzare la backpropagation dovremo scrivere:
    net = newff(p,t,[20 1], {'tansig', 'tansig'}, 'traingd');

Secondo programma

Nel secondo e ultimo programma cercheremo di approssimare con una funzione il volto in tre dimensioni di un bambolotto. Nel dataset che ci viene messo a disposizione avremo un elenco di coordinate, ricavate da uno scanner 3D.

Il dataset è contenuto nel file di testo doll.txt scaricabile da questa pagina: http://www.dti.unimi.it/~ferrari/reti_neurali/data/
Copiatelo in una cartella e selezionate quest'ultima come "Current Directory" in Matlab. A questo punto scriviamo il programma (con i commenti ridotti al minimo, poiché valgono le stesse considerazioni fatte in precedenza):

%prova_doll.m

load doll.txt;

%creiamo tre vettori, uno per i valori di ogni dimensione
X = doll(:,1);
Y = doll(:,2);
Z = doll(:,3);

p = [X'; Y'];
t = Z';

%'newff' crea una nuova rete feed-forward e mette il risultato nella
%variabile net.
net = newff(p,t,[40 1], {'tansig', 'tansig'});

%impostiamo le epoche
net.trainParam.epochs = 200;

%'train' fa partire l'addestramento e restituisce la rete addestrata.
[net,tr]=train(net,p,t);

%'sim' fa la simulazione a partire dalla rete data e dai dati di input.
a = sim(net,p);

%'postreg' dà una stima della rete di regressione tra i dati di uscita
[m,b,r] = postreg(a,t);

%ed ora posso decidere se stampare a video i risultati:
%1. come un insieme di punti (in caso, decommentate)
%figure;
%axis equal;
%hold on
%plot3(p(1,:),p(2,:),t, '.', 'MarkerSize', 1);
%plot3(p(1,:),p(2,:),a, 'r.', 'MarkerSize', 1);

%2. come una superficie
figure;
axis equal;
hold on
plot3(p(1,:),p(2,:),t, '.', 'MarkerSize', 1);
plot3(p(1,:),p(2,:),a, 'r.', 'MarkerSize', 1);

xs = min(X):max(X);
ys = min(Y):max(Y);
[mx my] = meshgrid(xs,ys);

a = sim(net,[reshape(mx,1,numel(mx)); reshape(my,1,numel(my));]);
ma = reshape(a, size(mx,1), size(mx,2));
surfl(mx,my,ma);
shading interp;
colormap pink;
rotate3d

Salvate il programma e lanciatelo nella command window scrivendo il suo nome e premendo INVIO. Ecco la Figura 2 ottenuta:

Si noti che dove non ci sono i dati (come in alto a destra), la rete fa quello che vuole.


Torna alla pagina di Sistemi Intelligenti