TP 4 : Les cartes de Kohonen

Contents

Outils

Lors de ce TP , nous utiliserons une boîte à outils dédiée aux Cartes de Kohonen (disponible ici).

clear all;
close all;
addpath('./Toolbox/somtoolbox');

Présentation des cartes de Kohonen

Les cartes de Kohonen, aussi appelées carte auto-organisatrices (Self Organizing Maps : SOM), sont une forme de réseau de neurones. Dans ce type de réseau, les neurones sont connectés entre eux selon une notion de voisinage et non selon une notion de couche.

figure;
som_cplane('hexa',[10 15],'none');
title('Grille SOM hexagonale : chaque neurone est connecté à 6 voisins');

figure;
som_cplane('rect',[10 15],'none');
title('Grille SOM rectangulaire : chaque neurone est connecté à 4 voisins');

Extrait de la documentation de la toolbox SOM

SELF-ORGANIZING MAP (SOM):

% * A self-organized map (SOM) is a "map" of the training data,
% dense where there is a lot of data and thin where the data
% density is low.
% * The map constitutes of neurons located on a regular map grid.
% * The lattice of the grid can be either hexagonal or rectangular.
% * Each neuron (hexagon on the left, rectangle on the right) has an
% associated prototype vector. After training, neighboring neurons
% have similar prototype vectors.
% * The SOM can be used for data visualization, clustering (or
%  classification), estimation and a variety of other purposes.

Initialisation et apprentissage d'une carte

Dans un premier temps, nous générons 600 points selon deux gaussiennes distinctes dans un espace en 2 dimension.

D = [0.3*randn(300,2)-0.5;0.1*randn(300,2)+0.4];
sData = som_data_struct(D,'name','gausians','comp_names',{'x','y'});

Les étiquettes peuvent être renseignées (toutefois les cartes SOM sont des méthodes non supervisées, c'est-à-dire que les étiquettes ne sont pas utilisées pour l'apprentisssage)

sData = som_label(sData,'add',[1:300]','1');
sData = som_label(sData,'add',[301:600]','2');

Choix des dimensions de la carte, ici en 2 dimensions (si la taille n'est pas définie, elle est choisie automatiquement en fonction des valeurs et vecteurs propres des données)

msize = [10 10];

Initialisation aléatoire des poids du réseau

sMap  = som_randinit(D, 'msize', msize);

En fait, chaque neurone de la carte peut être envisagé selon deux points de vue : * dans l'espace de représentation, selon les coordonnées de la carte * dans l'espace des données, selon leur position par rapport à leur prototype.

figure;
som_grid(sMap)
title('Carte dans l''espace de représentation')
figure;
plot(D(:,1),D(:,2),'+r'), hold on
som_grid(sMap,'Coord',sMap.codebook)
title('Carte dans l''espace des données')

Dans les figures, les points noirs représentent la position de chaque neurone de la carte, les lignes grises montrent les connexions de voisinnage. Puisque la carte est initialisée aléatoirement, les neurones sont complètement désorganisés dans l'espace des données. Au cours de l'apprentissage, la carte s'organise en utilisant la ressemblence entre les données d'apprentissage. (tapez help som_septrain pour plus d'informations sur les options d'apprentissage)

sMap  = som_seqtrain(sMap,D,'radius',[5 1],'trainlen',10);
figure;
som_grid(sMap,'Coord',sMap.codebook)
hold on, plot(D(:,1),D(:,2),'+r')
title('Trained map')
Training:   0/   1 sTraining:   0/   1 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 sTraining:   0/   0 s

Déroulement de l'apprentissage

L'exemple ci-après montre comment la carte se déplie selon les données au cours de l'apprentissage. Pour que la visualisation soit meilleure, on initialise la carte loin des données de départ.

sMap = som_randinit(D,'msize',msize);
sMap.codebook = sMap.codebook + 3;

figure;
som_grid(sMap,'Coord',sMap.codebook)
hold on, plot(D(:,1),D(:,2),'+r'), hold off
title('Data and original map')

L'apprentissage se fait selon 2 principes : * la compétition : le prototype qui ressemble le plus à une donnée d'apprentissage est modifié de manière à lui ressembler encore plus. Ainsi chaque neurone de la carte se spécialise et est de plus en plus représentatif des données. * la coopération : les voisins du neurone dont le prototype est modifié sont également modifiés, dans une moindre mesure, de manière à se rapprocher de l'exemple. C'est ainsi que la carte s'auto-organise.

figure;
o = ones(5,1);
r = (1-[1:60]/60);
for i=1:60,
  sMap = som_seqtrain(sMap,D,'tracking',0,...
		      'trainlen',5,'samples',...
		      'alpha',0.1*o,'radius',(4*r(i)+1)*o);
  som_grid(sMap,'Coord',sMap.codebook)
  hold on, plot(D(:,1),D(:,2),'+r'), hold off
  title(sprintf('%d/300 training steps',5*i))
  drawnow
end
title('Apprentissage itératif après 300 étapes')

Comparaison avec les étiquettes

Il est possible de visualiser la performance de la carte en affichant, pour chaque neurone, l'étiquette la plus représentée par son prototype.

sMap = som_autolabel(sMap,sData,'vote');
figure;
som_cplane(sMap,'none');
hold on;
som_grid(sMap,'Label',sMap.labels,'Labelsize',8,...
	 'Marker','none','Labelcolor','r');

Utilisation de la carte pour faire de la projection de données

Dans cette partie, nous allons utiliser des données en dimension 10, réparties selon 5 classes, chacune générée selon une gaussienne particulière.

D = [0.4*randn(100,10)-ones(100,1)*randn(1,10);0.4*randn(100,10)+ones(100,1)*randn(1,10);...
    0.4*randn(100,10)+ones(100,1)*randn(1,10);0.6*randn(100,10)+ones(100,1)*randn(1,10);...
    0.6*randn(100,10)+ones(100,1)*randn(1,10)];
sData = som_data_struct(D,'name','gausians');
sData = som_label(sData,'add',[1:100]','1');
sData = som_label(sData,'add',[101:200]','2');
sData = som_label(sData,'add',[201:300]','3');
sData = som_label(sData,'add',[301:400]','4');
sData = som_label(sData,'add',[401:500]','5');

La carte est initialisée aléatoirement, le choix de la taille de la grille est automatique.

sMap = som_randinit(D);
sMap  = som_seqtrain(sMap,D,'radius',[2 0.5],'trainlen',20);
Training:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   0/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 sTraining:   1/   1 s

La carte étant en 2 dimension, nous avons automatiquement une réduction de dimension de données...

figure;
som_cplane(sMap,'none')
sMap = som_autolabel(sMap,sData,'vote');
hold on
som_grid(sMap,'Label',sMap.labels,'Labelsize',8,...
	 'Marker','none','Labelcolor','r');
hold off
title('Etiquettes')

Recherche de cluster.

Dans l'apprentissage non supervisé, on recherche généralement des ensembles de données se ressemblant tout en étant différents des autres ensembles, c'est ce que l'on appelle des clusters. Ici on utilise l'algorithme des k-moyennes pour trouver des clusters sur la carte en 2D. On va rechercher au plus 15 cluster, une mesure de qualité des cluster permettra de déterminer automatiquement combien vont être retenus.

figure;
[c,p,err,ind] = kmeans_clusters(sMap, 15);
plot(1:length(ind),ind,'x-')
xlabel('Nombre de clusters')
ylabel('Critère d''évaluation des clusters')
[dummy,i] = min(ind)
cl = p{i};
%subplot(1,3,2)
%som_cplane(sMap,Code,Dm)
%title('Carte représentant la fréquence d''utilisation de chaque neurone')
figure
som_cplane(sMap,cl)
title('Clustering de la carte selon le nombre optimal de clusters')
dummy =

    0.5620


i =

     5

Travail à réaliser

Reprennez les données USPS (les 10 classes) et construisez une carte de Kohonen dédiée. Visualisez la répartition des étiquettes, essayez de faire du clustering, regardez les effets de la taille de la carte (automatique, arbitrairement grande ou petite...). Le compte rendu contiendra la figure représentant les étiquettes d'apprentissage sur la carte. Il fera aussi figurer le taux de bonne classification sur les données de test.

Code à utiliser pour le test...

ypred1 = zeros(size(test_labels));
for i=1:length(test_labels)
   y1 = som_hits(sMap,test_patterns(:,i)');
   ypred1(i) = str2double(sMap.labels{y1==max(y1)});
end
testErr1 = length(find(ypred1==test_labels))/length(test_labels)
somUsps;
Training:   0/   4 sTraining:   0/   5 sTraining:   1/   5 sTraining:   1/   5 sTraining:   1/   5 sTraining:   2/   5 sTraining:   2/   5 sTraining:   2/   5 sTraining:   2/   5 sTraining:   2/   5 sTraining:   3/   5 sTraining:   3/   5 sTraining:   3/   5 sTraining:   3/   5 sTraining:   4/   5 sTraining:   4/   5 sTraining:   4/   5 sTraining:   4/   5 sTraining:   5/   5 sTraining:   5/   5 s

dummy =

    1.4074


i =

    15


bonneClassification =

    0.8984