Introduction à l'apprentissage automatique: TP3 - Exercice 2


Reconnaissance de chiffres manuscrits


La cellule ci-dessous permet de charger 10000 images de chiffres manuscrits extraits de la célèbre base de données MNIST décrite ici. La base originale contient 70000 images de taille 28x28 pixels, mais on restreint le nombre d'images afin de garder des temps de calcul raisonnables dans ce TD. On utilise 9000 observations comme base d'apprentissage, et on réserve 1000 observations comme base de test.

Les 28x28=784 caractéristiques sont les niveaux de gris en chaque pixel. Les caractéristiques seront normalisées à des valeurs entre 0 et 1.

On reviendra sur cette base dans les TP suivants, le but aujourd'hui est d'établir les performances des méthodes de classification vues jusqu'à présent pour les comparer à celles que nous verrons dans les semaines prochaines.

In [ ]:
from sklearn import datasets, neighbors, linear_model, metrics
%matplotlib inline 

# dataset natif sklearn (ce n'est pas MNIST): (lignes suivantes à "décommenter" pour utiliser ce jeu de données)
# size_images=(8,8)
# digits = datasets.load_digits()
# X_digits = digits.data
# y_digits = digits.target

# Mnist database: (il faut quelques dizaines de secondes pour charger la base)
# les données sont décrites ici: https://www.openml.org/d/554
size_images=(28,28)
X_digits, y_digits = datasets.fetch_openml('mnist_784', version=1, return_X_y=True)
X_digits=X_digits[:10000,:]/255. # on normalise le niveau de gris 8 bits entre 0 et 1
y_digits=y_digits[:10000]

n_samples = len(X_digits)
print("nombre total d'observations (apprentissage + test): %d" % n_samples)

n_features = len(X_digits[0])
print("nombre de caractéristiques par observation: %d" % n_features)

X_train = X_digits[: 9000]
y_train = y_digits[: 9000]
X_test = X_digits[9000 :]
y_test = y_digits[9000 :]
print("nombre d'observations dans la base d'apprentissage: %d" %len(X_train))
print("nombre d'observations dans la base de test: %d" %len(X_test))

La cellule suivante définit une fonction qui permet d'afficher les 150 premières images de la base de test, ainsi que la classe véritable et la classe déterminée par l'algorithme de classification. Nous nous servirons de cette fonction plus tard.

In [ ]:
import numpy as np
import matplotlib.pyplot as plt

def affichage_150_images(X_test,y_test,y_pred):
    plt.figure(figsize=[15,12])   
    for n in range(150):
        plt.subplot(10,15,n+1,xticks=[],yticks=[])
        plt.imshow(np.reshape(X_test[n,:],size_images),cmap='gray_r')
        if y_pred[n]==y_test[n]:
            plt.text(0.1,0.1,str(y_pred[n])+' / '+str(y_test[n]),fontsize=6,bbox=dict(facecolor='white', alpha=1))    
        else:
            plt.text(0.1,0.1,str(y_pred[n])+' / '+str(y_test[n]),fontsize=6,bbox=dict(facecolor='red', alpha=1))    
    plt.suptitle('classe predite / classe réelle')
    plt.show();

La cellule suivante effectue une classification au plus proche voisin (n_neighbors=1) de la base des chiffres manuscrits extraite de MNIST, et affiche le résultat de la classification de 150 images.

Question 1. A quoi correspondent les temps de calcul affichés? Les erreurs vous semblent-elles qualitativement explicables? Notez le score de précision (proportion d'observations correctement classées).

In [ ]:
# classification au plus proche voisin et affichage
knn = neighbors.KNeighborsClassifier(n_neighbors=1, n_jobs=-1) 
%time knn.fit(X_train, y_train)
%time y_pred_nn = knn.predict(X_test)
print('KNN score: %f' % metrics.accuracy_score(y_test, y_pred_nn))
affichage_150_images(X_test,y_test,y_pred_nn)        

Réponse:

</font>

Question 2. Quelles sont les informations fournies par classification_report et confusion_matrix du module metrics ?

In [ ]:
# votre code (voir l'exercice 1):

Réponse:

</font>

Question 3. Comparez aux résultats obtenus par

Comparez également les temps de calcul.

In [ ]:
from sklearn import naive_bayes

# votre code pour le classifieur naif Gaussien:
In [ ]:
from sklearn import linear_model

# votre code pour la régression logistique:

Réponse:

</font>

Remarque: les méthodes modernes arrivent à des précisions supérieures à 99% (sur la base MNIST) cf: http://yann.lecun.com/exdb/mnist/


Pour les plus rapides, complément facultatif

Génération aléatoire d'images de chiffres manuscrits

On change de base de données pour utiliser: python digits = datasets.load_digits() X_train2 = digits.data y_train2 = digits.target  Cette base est formée de 1797 images de taille 8 pixels par 8 pixels. La dimension des observations (64) est donc bien plus faible que dans la base MNIST, ce qui rend les calculs moins longs et les modèles moins sujets à la malédiction de la dimension.

Modélisez la distribution des chiffres manuscrits comme un mélange de gaussienne:

  • vous utiliserez un nombre de composantes minimisant le critère AIC (testez entre 1 et 200 composantes par pas de 20 pour limiter le temps de calcul)
  • vous représenterez les moyennes des composantes comme une image, en vous inspirant de la fonction d'affichage précédente (constatez que certains chiffres sont représentés par plusieurs gaussiennes)
  • vous générerez aléatoirement 100 chiffres avec cette méthode. Vous les représenterez, et vous les comparerez à 100 chiffres de la base.

Si vous avez des résultats intéressants, n'hésitez pas à discuter votre travail avec votre chargé de TD.

Je mettrai la correction sur Arche plus tard.

In [ ]: