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 etd(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
void compute_centers(data* X, int n, int* classes, int k, data* centers)qui met à jour les centres des classes obtenues par l'algorithme des -moyennes dans le tableaucenters, oùclasses[i]est la classe deX[i],nest la taille deXetkest le nombre de classes. -
Écrire une fonction
void compute_classes(data* X, int n, data* centers, int k, int* classes, bool* has_changed)qui met à jour les classes obtenues par l'algorithme des -moyennes dans le tableauclasses, oùnest la taille deXetkest la taille decenters.has_changedest un pointeur qui doit ê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.