Swappa : Uni / Sistemi Intelligenti - Appunti del 21 Ottobre
Creative Commons License

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:


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:

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

(Printable View of http://www.swappa.it/wiki/Uni/SI-21ottobre)