TP 10 : Apprentissage automatique
- Télécharger tp_apprentissage.zip et le charger dans le Codespace avec clic droit -> charger.
- Le décompresser avec
unzip tp_apprentissage.zipdans le terminal.
Fonctions utilitaires
Dans cette partie, les fonctions seront écrites dans utils.c et déclarées dans utils.h.
Le dossier data contient les données d'entraînement et de test pour deux problèmes : classification de chiffres manuscrits (digits) et de vêtements (fashion).
Pour chaque fichier :
- la première ligne est le nombre N de données
- chacune des N lignes suivantes contient valeurs : le label de la donnée (0 à 9 pour les chiffres et les vêtements) et les 28x28 pixels de l'image (de 0 à 255).


utils.h contient plusieurs définitions, dont un type sample permettant de représenter une donnée :
#define LEN (28 * 28) // taille d'une image
#define NB_CLASSES 10
typedef struct data {
int class;
float pixels[LEN]; // pixels[i*28+j] est le pixel (i, j)
} data;
utils.c contient une fonction data* read_dataset(char* path, int n) renvoyant un tableau contenant n données du fichier path.
-
Écrire une fonction
float d(data x1, data x2)calculant la distance euclidienne au carré entre deux données (il est inutile de calculer la racine carrée car on ne cherche qu'à comparer les distances). -
Écrire une fonction
int nearest(data x, data* X, bool* T, int n)renvoyant unitel queT[i]est vrai etdist(x, X[i])est minimum, oùnest la taille deXet deT. -
Écrire une fonction
int majority(int* T, int n, int p)renvoyant un élément majoritaire d'un tableauTde taillendont les éléments sont entre0etp - 1, en complexité O().
KNN
Dans cette partie, les fonctions seront écrites dans un nouveau fichier knn.c.
-
Écrire une fonction
int* k_nearest(data x, data* X, int n, int k)renvoyant les indices deskplus proches voisins dexdansX, oùnest la taille deX. -
Écrire une fonction
int knn(data x, data* X, int n, int k)renvoyant la classe majoritaire deskplus proches voisins dexdansX, oùnest la taille deX. -
Tester avec le code suivant, avec
gcc -fsanitize=address -g -Wall knn.c utils.c && ./a.out:
int main() {
int n_train = 10000;
int n_test = 200;
int k = 3;
data *train = read_dataset("data/digit-train.txt", n_train);
printf("Read %d training data\n", n_train);
data *test = read_dataset("data/digit-test.txt", n_test);
printf("Read %d testing data\n", n_test);
int c = knn(test[0], train, n_train, k);
printf("Predicted class: %d (class is %d)\n", c, test[0].class); // doit afficher 7
free(train);
free(test);
return 0;
}
- Écrire une fonction
precision(data* test, int n_test, data* train, int n_train, int k)renvoyant la précision du classifieur KNN surtesten utilisanttrainpour l'entraînement. Essayer avec différentes valeurs dek,n_trainetn_test.
-moyennes
Dans cette partie, les fonctions seront écrites dans dans un nouveau fichier kmeans.c.
-
Écrire une fonction
data* compute_centers(data* X, int n, int* classes, int k)renvoyant les centres des classes obtenues par l'algorithme des -moyennes, oùclasses[i]est la classe deX[i],nest la taille deXetkest la taille de classes. -
Écrire une fonction
int* compute_classes(data* X, int n, data* centers, int k, bool* has_changed)renvoyant les classes obtenues par l'algorithme des -moyennes, oùnest la taille deXetkest la taille decenters.has_changeddoit être mis à vrai si une donnée change de classe, faux sinon. -
Écrire une fonction
data* init_centers(data* X, int n, int k)renvoyantkcentres aléatoires parmi les données deX, oùnest la taille deX. On utiliserasrand(time(NULL));dans lemainetrand() % npour générer un nombre aléatoire entre0etn - 1. -
Écrire une fonction
int* kmeans(data* X, int n, int k)renvoyant les classes obtenues par l'algorithme des -moyennes, oùnest la taille deX. -
Tester sur les données de chiffres.