diff --git a/Cours/ML-05-Reseaux_de_neurones.pdf b/Cours/ML-05-Reseaux_de_neurones.pdf new file mode 100644 index 0000000000000000000000000000000000000000..775736fcf124a8aa4ede5acfcf438eec830e84de Binary files /dev/null and b/Cours/ML-05-Reseaux_de_neurones.pdf differ diff --git a/TD/TD3/regression_logistique-complet.py b/TD/TD3/regression_logistique-complet.py new file mode 100644 index 0000000000000000000000000000000000000000..eb5adf7b079e2a8f5dcd7da03d25e2b0b86da233 --- /dev/null +++ b/TD/TD3/regression_logistique-complet.py @@ -0,0 +1,262 @@ +import matplotlib.pyplot as plt +import numpy as np + +def lecture_donnees(nom_fichier, delimiteur=','): + """ Lit le fichier contenant les données et renvoiee les matrices correspondant + + Parametres + ---------- + nom_fichier : nom du fichier contenant les données + delimiteur : caratère délimitant les colonne dans le fichier ("," par défaut) + + Retour + ------- + X : matrice des données de dimension [N, nb_var] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + N : nombre d'éléments + nb_var : nombre de variables prédictives + + """ + + data = np.loadtxt(nom_fichier, delimiter=delimiteur) + nb_var = data.shape[1] - 1 + N = data.shape[0] + + X = data[:, :-1] + Y = data[:, -1].reshape(N,1) + + return X, Y, N, nb_var + +def normalisation(X): + """ Normalise les données par un centrage-réduction des variables prédictives + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + X_norm : matrice des données centrées-réduites de dimension [N, nb_var] + mu : moyenne des variables de dimension [1,nb_var] + sigma : écart-type des variables de dimension [1,nb_var] + + """ + + mu = np.mean(X, 0) + sigma = np.std(X, 0) + X_norm = (X - mu) / sigma + + return X_norm, mu, sigma + +def sigmoide(z): + """ Calcule la valeur de la fonction sigmoide appliquée à z + + Parametres + ---------- + z : peut être un scalaire ou une matrice + + Return + ------- + s : valeur de sigmoide de z. Même dimension que z + + """ + + s = 1 / (1 + np.exp(-z)) + + return s + +def calcule_cout(X, Y, theta): + """ Calcule la valeur de la fonction cout ( - log vraisemblance) + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Return + ------- + cout : nombre correspondant à la valeur de la fonction cout (moyenne des différences au carré) + + """ + + N = X.shape[0] + + cout = - (Y*np.log(sigmoide(X.dot(theta.T))) + (1-Y)*np.log(1-sigmoide(X.dot(theta.T)))).sum() / N + + return cout + +def descente_gradient(X, Y, theta, alpha, nb_iters): + """ Apprentissage des parametres de regression logistique par descente du gradient + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + for i in range(0, nb_iters): + + error = sigmoide(X.dot(theta.T)) - Y + theta -= (alpha/N)*np.sum(X*error, 0) + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + +def prediction(X,theta): + """ Predit la classe de chaque élement de X + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + p : matrices de dimension [N,1] indiquant la classe de chaque élement de X (soit 0, soit 1) + + """ + + p = sigmoide(X.dot(theta.T)) + pos = np.where(p >= 0.5) + neg = np.where(p < 0.5) + + p[pos] = 1 + p[neg] = 0 + + return p + +def taux_classification(Ypred,Y): + """ Calcule le taux de classification (proportion d'éléments bien classés) + + Parametres + ---------- + Ypred : matrice contenant les valeurs de classe prédites de dimension [N, 1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments + + + Retour + ------- + t : taux de classification + + """ + + N = Ypred.size + nb_erreurs = np.sum(np.abs(Ypred-Y)) + + t = (N-nb_erreurs) / N + + return t + +def affichage(X, Y): + """ Affichage en 2 dimensions des données (2 dimensions de X) et représentation de la + classe (indiquée par Y) par une couleur + + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + None + + """ + + pos = np.where(Y == 1)[0] + neg = np.where(Y == 0)[0] + plt.scatter(X[pos, 1], X[pos, 2], marker="+", c='b') + plt.scatter(X[neg, 1], X[neg, 2], marker="o", c='r') + + +if __name__ == "__main__": + # ===================== Partie 1: Lecture et normalisation des données===================== + print("Lecture des données ...") + + X, Y, N, nb_var = lecture_donnees("notes.txt") + + # Affichage des 10 premiers exemples du dataset + print("Affichage des 10 premiers exemples du dataset : ") + for i in range(0, 10): + print(f"x = {X[i,:]}, y = {Y[i]}") + + # Normalisation des variables (centrage-réduction) + print("Normalisation des variables ...") + + X, mu, sigma = normalisation(X) + + # Ajout d'une colonne de 1 à X (pour theta0) + X = np.hstack((np.ones((N,1)), X)) + + # Affichage des points en 2D et représentation de leur classe réelle par une couleur + if nb_var == 2 : + plt.figure(0) + plt.title("Disposition des points en 2D - Réalité") + affichage(X,Y) + + # ===================== Partie 2: Descente du gradient ===================== + print("Apprentissage par descente du gradient ...") + + # Choix du taux d'apprentissage et du nombre d'itérations + alpha = 0.01 + nb_iters = 50000 + + # Initialisation de theta et réalisation de la descente du gradient + theta = np.zeros((1,nb_var+1)) + theta, J_history = descente_gradient(X, Y, theta, alpha, nb_iters) + + # Affichage de l'évolution de la fonction de cout lors de la descente du gradient + plt.figure(1) + plt.title("Evolution de le fonction de cout lors de la descente du gradient") + plt.plot(np.arange(J_history.size), J_history) + plt.xlabel("Nombre d'iterations") + plt.ylabel("Cout J") + + # Affichage de la valeur de theta + print(f"Theta calculé par la descente du gradient : {theta}") + + # Evaluation du modèle + Ypred = prediction(X,theta) + + print("Taux de classification : ", taux_classification(Ypred,Y)) + + # Affichage des points en 2D et représentation de leur classe prédite par une couleur + if nb_var == 2 : + plt.figure(2) + plt.title("Disposition des points en 2D - Prédiction") + affichage(X,Ypred) + + plt.show() + + print("Regression logistique Terminée.") diff --git a/TD/TD3/regression_logistique-etendu-1-complet.py b/TD/TD3/regression_logistique-etendu-1-complet.py new file mode 100644 index 0000000000000000000000000000000000000000..010ea2ca43862317903497d257e169da0f3c7c72 --- /dev/null +++ b/TD/TD3/regression_logistique-etendu-1-complet.py @@ -0,0 +1,369 @@ +# Ajout de différentes stratégies de descente du gradient + +import matplotlib.pyplot as plt +import numpy as np + +def lecture_donnees(nom_fichier, delimiteur=','): + """ Lit le fichier contenant les données et renvoiee les matrices correspondant + + Parametres + ---------- + nom_fichier : nom du fichier contenant les données + delimiteur : caratère délimitant les colonne dans le fichier ("," par défaut) + + Retour + ------- + X : matrice des données de dimension [N, nb_var] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + N : nombre d'éléments + nb_var : nombre de variables prédictives + + """ + + data = np.loadtxt(nom_fichier, delimiter=delimiteur) + nb_var = data.shape[1] - 1 + N = data.shape[0] + + X = data[:, :-1] + Y = data[:, -1].reshape(N,1) + + return X, Y, N, nb_var + +def normalisation(X): + """ Normalise les données par un centrage-réduction des variables prédictives + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + X_norm : matrice des données centrées-réduites de dimension [N, nb_var] + mu : moyenne des variables de dimension [1,nb_var] + sigma : écart-type des variables de dimension [1,nb_var] + + """ + + mu = np.mean(X, 0) + sigma = np.std(X, 0) + X_norm = (X - mu) / sigma + + return X_norm, mu, sigma + +def sigmoide(z): + """ Calcule la valeur de la fonction sigmoide appliquée à z + + Parametres + ---------- + z : peut être un scalaire ou une matrice + + Return + ------- + s : valeur de sigmoide de z. Même dimension que z + + """ + + s = 1 / (1 + np.exp(-z)) + + return s + +def calcule_cout(X, Y, theta): + """ Calcule la valeur de la fonction cout ( - log vraisemblance) + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Return + ------- + cout : nombre correspondant à la valeur de la fonction cout (moyenne des différences au carré) + + """ + + N = X.shape[0] + + cout = - (Y*np.log(sigmoide(X.dot(theta.T))) + (1-Y)*np.log(1-sigmoide(X.dot(theta.T)))).sum() / N + + return cout + +def descente_gradient_lot(X, Y, theta, alpha, nb_iters): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie par lot + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + for i in range(0, nb_iters): + + error = sigmoide(X.dot(theta.T)) - Y + theta -= (alpha/N)*np.sum(X*error, 0) + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + +def descente_gradient_stochastique(X, Y, theta, alpha, nb_iters): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie stochastique + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + # Création d'un vecteur d'indices pour parcourir X élément par élément, dans un ordre aléatoire + indices = np.arange(N) + np.random.shuffle(indices) + + for i in range(0, nb_iters): + + for j in range(N): + + error = sigmoide(X[indices[j],:].dot(theta.T)) - Y[indices[j]] + theta -= alpha*X[indices[j],:]*error + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + +def descente_gradient_mini_lot(X, Y, theta, alpha, nb_iters, taille_lots=16): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie par mini-lots + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + taille_lots = nombre d'éléments dans chaque mini-lot + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + # Création d'un vecteur d'indices pour parcourir X élément par élément, dans un ordre aléatoire + indices = np.arange(N) + np.random.shuffle(indices) + nb_lots = N // taille_lots + indices_lots = [] + for i in range(nb_lots): + ind_debut = i*taille_lots + indices_lots.append(indices[ind_debut:ind_debut+taille_lots]) + + for i in range(0, nb_iters): + + for j in range(nb_lots): + + error = sigmoide(X[indices_lots[j],:].dot(theta.T)) - Y[indices_lots[j]] + theta -= (alpha/taille_lots)*np.sum(X[indices_lots[j],:]*error, 0) + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + + +def prediction(X,theta): + """ Predit la classe de chaque élement de X + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + p : matrices de dimension [N,1] indiquant la classe de chaque élement de X (soit 0, soit 1) + + """ + + p = sigmoide(X.dot(theta.T)) + pos = np.where(p >= 0.5) + neg = np.where(p < 0.5) + + p[pos] = 1 + p[neg] = 0 + + return p + +def taux_classification(Ypred,Y): + """ Calcule le taux de classification (proportion d'éléments bien classés) + + Parametres + ---------- + Ypred : matrice contenant les valeurs de classe prédites de dimension [N, 1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments + + + Retour + ------- + t : taux de classification + + """ + + N = Ypred.size + nb_erreurs = np.sum(np.abs(Ypred-Y)) + + t = (N-nb_erreurs) / N + + return t + +def affichage(X, Y): + """ Affichage en 2 dimensions des données (2 dimensions de X) et représentation de la + classe (indiquée par Y) par une couleur + + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + None + + """ + + pos = np.where(Y == 1)[0] + neg = np.where(Y == 0)[0] + plt.scatter(X[pos, 1], X[pos, 2], marker="+", c='b') + plt.scatter(X[neg, 1], X[neg, 2], marker="o", c='r') + + +if __name__ == "__main__": + # ===================== Partie 1: Lecture et normalisation des données===================== + print("Lecture des données ...") + + X, Y, N, nb_var = lecture_donnees("notes.txt") + + # Affichage des 10 premiers exemples du dataset + print("Affichage des 10 premiers exemples du dataset : ") + for i in range(0, 10): + print(f"x = {X[i,:]}, y = {Y[i]}") + + # Normalisation des variables (centrage-réduction) + print("Normalisation des variables ...") + + X, mu, sigma = normalisation(X) + + # Ajout d'une colonne de 1 à X (pour theta0) + X = np.hstack((np.ones((N,1)), X)) + + # Affichage des points en 2D et représentation de leur classe réelle par une couleur + if nb_var == 2 : + plt.figure(0) + plt.title("Disposition des points en 2D - Réalité") + affichage(X,Y) + + # ===================== Partie 2: Descente du gradient ===================== + print("Apprentissage par descente du gradient ...") + + # Choix du taux d'apprentissage et du nombre d'itérations + alpha = 0.01 + nb_iters = 1000 + + J_histories = [] + # Initialisation de theta et réalisation de la descente du gradient + theta = np.zeros((1,nb_var+1)) + theta, J_history = descente_gradient_lot(X, Y, theta, alpha, nb_iters) + J_histories.append(J_history) + theta = np.zeros((1,nb_var+1)) + theta, J_history = descente_gradient_stochastique(X, Y, theta, alpha, nb_iters) + J_histories.append(J_history) + theta = np.zeros((1,nb_var+1)) + theta, J_history = descente_gradient_mini_lot(X, Y, theta, alpha, nb_iters, taille_lots=16) + J_histories.append(J_history) + J_histories = np.array(J_histories).T + + + # Affichage de l'évolution de la fonction de cout lors de la descente du gradient + plt.figure(1) + plt.title("Evolution de le fonction de cout lors de la descente du gradient") + plt.plot(np.arange(J_histories.shape[0]), J_histories, label = ["lot", "stochastique", "mini-lot"]) + plt.xlabel("Nombre d'iterations") + plt.ylabel("Cout J") + plt.legend() + + # Affichage de la valeur de theta + print(f"Theta calculé par la descente du gradient : {theta}") + + # Evaluation du modèle + Ypred = prediction(X,theta) + + print("Taux de classification : ", taux_classification(Ypred,Y)) + + # Affichage des points en 2D et représentation de leur classe prédite par une couleur + if nb_var == 2 : + plt.figure(2) + plt.title("Disposition des points en 2D - Prédiction") + affichage(X,Ypred) + + plt.show() + + print("Regression logistique Terminée.") diff --git a/TD/TD3/regression_logistique-etendu-2-complet.py b/TD/TD3/regression_logistique-etendu-2-complet.py new file mode 100644 index 0000000000000000000000000000000000000000..ccaf71cef082f76c6a5803458061355be002a4c8 --- /dev/null +++ b/TD/TD3/regression_logistique-etendu-2-complet.py @@ -0,0 +1,420 @@ +# Ajout des ensembles d'apprentissage et de test + +import matplotlib.pyplot as plt +import numpy as np + +def lecture_donnees(nom_fichier, delimiteur=','): + """ Lit le fichier contenant les données et renvoiee les matrices correspondant + + Parametres + ---------- + nom_fichier : nom du fichier contenant les données + delimiteur : caratère délimitant les colonne dans le fichier ("," par défaut) + + Retour + ------- + X : matrice des données de dimension [N, nb_var] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + N : nombre d'éléments + nb_var : nombre de variables prédictives + + """ + + data = np.loadtxt(nom_fichier, delimiter=delimiteur) + nb_var = data.shape[1] - 1 + N = data.shape[0] + + X = data[:, :-1] + Y = data[:, -1].reshape(N,1) + + return X, Y, N, nb_var + +def normalisation(X): + """ Normalise les données par un centrage-réduction des variables prédictives + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + X_norm : matrice des données centrées-réduites de dimension [N, nb_var] + mu : moyenne des variables de dimension [1,nb_var] + sigma : écart-type des variables de dimension [1,nb_var] + + """ + + mu = np.mean(X, 0) + sigma = np.std(X, 0) + X_norm = (X - mu) / sigma + + return X_norm, mu, sigma + +def decoupage_donnees(X,Y,ratio_apprentissage): + """ Découpe les données en deux ensembles : apprentissage et test + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + ratio_apprentissage : ratio de données d’apprentissage par rapport aux données de test (entre 0 et 1) + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + X_app : matrice des données d'apprentissage + Y_app : matrice contenant les valeurs de la variable cible pour les données d'apprentissage + X_test : matrice des données de test + Y_test : matrice contenant les valeurs de la variable cible pour les données de test + + """ + + # Création d'un vecteur d'indices dans un ordre aléatoire + N = X.shape[0] + indices = np.arange(N) + np.random.shuffle(indices) + + indice_split = int(N*ratio_apprentissage) + + indices_app = indices[:indice_split] + indices_test = indices[indice_split:] + + X_app = X[indices_app,:] + Y_app = Y[indices_app] + X_test = X[indices_test,:] + Y_test = Y[indices_test] + + return X_app, Y_app, X_test, Y_test + + +def sigmoide(z): + """ Calcule la valeur de la fonction sigmoide appliquée à z + + Parametres + ---------- + z : peut être un scalaire ou une matrice + + Return + ------- + s : valeur de sigmoide de z. Même dimension que z + + """ + + s = 1 / (1 + np.exp(-z)) + + return s + +def calcule_cout(X, Y, theta): + """ Calcule la valeur de la fonction cout ( - log vraisemblance) + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Return + ------- + cout : nombre correspondant à la valeur de la fonction cout (moyenne des différences au carré) + + """ + + N = X.shape[0] + + cout = - (Y*np.log(sigmoide(X.dot(theta.T))) + (1-Y)*np.log(1-sigmoide(X.dot(theta.T)))).sum() / N + + return cout + +def descente_gradient_lot(X, Y, theta, alpha, nb_iters): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie par lot + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + for i in range(0, nb_iters): + + error = sigmoide(X.dot(theta.T)) - Y + theta -= (alpha/N)*np.sum(X*error, 0) + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + +def descente_gradient_stochastique(X, Y, theta, alpha, nb_iters): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie stochastique + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + # Création d'un vecteur d'indices pour parcourir X élément par élément, dans un ordre aléatoire + indices = np.arange(N) + np.random.shuffle(indices) + + for i in range(0, nb_iters): + + for j in range(N): + + error = sigmoide(X[indices[j],:].dot(theta.T)) - Y[indices[j]] + theta -= alpha*X[indices[j],:]*error + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + +def descente_gradient_mini_lot(X, Y, theta, alpha, nb_iters, taille_lots=16): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie par mini-lots + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + taille_lots = nombre d'éléments dans chaque mini-lot + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + # Création d'un vecteur d'indices pour parcourir X élément par élément, dans un ordre aléatoire + indices = np.arange(N) + np.random.shuffle(indices) + nb_lots = N // taille_lots + indices_lots = [] + for i in range(nb_lots): + ind_debut = i*taille_lots + indices_lots.append(indices[ind_debut:ind_debut+taille_lots]) + + for i in range(0, nb_iters): + + for j in range(nb_lots): + + error = sigmoide(X[indices_lots[j],:].dot(theta.T)) - Y[indices_lots[j]] + theta -= (alpha/taille_lots)*np.sum(X[indices_lots[j],:]*error, 0) + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + + +def prediction(X,theta): + """ Predit la classe de chaque élement de X + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + p : matrices de dimension [N,1] indiquant la classe de chaque élement de X (soit 0, soit 1) + + """ + + p = sigmoide(X.dot(theta.T)) + pos = np.where(p >= 0.5) + neg = np.where(p < 0.5) + + p[pos] = 1 + p[neg] = 0 + + return p + +def taux_classification(Ypred,Y): + """ Calcule le taux de classification (proportion d'éléments bien classés) + + Parametres + ---------- + Ypred : matrice contenant les valeurs de classe prédites de dimension [N, 1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments + + + Retour + ------- + t : taux de classification + + """ + + N = Ypred.size + nb_erreurs = np.sum(np.abs(Ypred-Y)) + + t = (N-nb_erreurs) / N + + return t + +def affichage(X, Y): + """ Affichage en 2 dimensions des données (2 dimensions de X) et représentation de la + classe (indiquée par Y) par une couleur + + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + None + + """ + + pos = np.where(Y == 1)[0] + neg = np.where(Y == 0)[0] + plt.scatter(X[pos, 1], X[pos, 2], marker="+", c='b') + plt.scatter(X[neg, 1], X[neg, 2], marker="o", c='r') + + +if __name__ == "__main__": + # ===================== Partie 1: Lecture et normalisation des données===================== + print("Lecture des données ...") + + X, Y, N, nb_var = lecture_donnees("notes.txt") + + # Affichage des 10 premiers exemples du dataset + print("Affichage des 10 premiers exemples du dataset : ") + for i in range(0, 10): + print(f"x = {X[i,:]}, y = {Y[i]}") + + # Normalisation des variables (centrage-réduction) + print("Normalisation des variables ...") + + X, mu, sigma = normalisation(X) + + # Ajout d'une colonne de 1 à X (pour theta0) + X = np.hstack((np.ones((N,1)), X)) + + # Découpage des données en un ensemble d'apprentissage et un ensemble de test + X_app, Y_app, X_test, Y_test = decoupage_donnees(X,Y,0.8) + + # Affichage des points d'apprentissage en 2D et représentation de leur classe réelle par une couleur + if nb_var == 2 : + plt.figure() + plt.title("Disposition des points en 2D - Réalité (apprentissage)") + affichage(X_app,Y_app) + + # Affichage des points de test en 2D et représentation de leur classe réelle par une couleur + if nb_var == 2 : + plt.figure() + plt.title("Disposition des points en 2D - Réalité (test)") + affichage(X_test,Y_test) + + # ===================== Partie 2: Descente du gradient ===================== + print("Apprentissage par descente du gradient ...") + + # Choix du taux d'apprentissage et du nombre d'itérations + alpha = 0.01 + nb_iters = 50 + + # Initialisation de theta et réalisation de la descente du gradient + theta = np.zeros((1,nb_var+1)) + # theta, J_history = descente_gradient_lot(X_app, Y_app, theta, alpha, nb_iters) + # theta, J_history = descente_gradient_stochastique(X_app, Y_app, theta, alpha, nb_iters) + theta, J_history = descente_gradient_mini_lot(X_app, Y_app, theta, alpha, nb_iters, taille_lots=16) + + + # Affichage de l'évolution de la fonction de cout lors de la descente du gradient + plt.figure() + plt.title("Evolution de le fonction de cout lors de la descente du gradient") + plt.plot(np.arange(J_history.size), J_history) + plt.xlabel("Nombre d'iterations") + plt.ylabel("Cout J") + + # Affichage de la valeur de theta + print(f"Theta calculé par la descente du gradient : {theta}") + + # Evaluation du modèle sur les données d'apprentissage + Ypred_app = prediction(X_app,theta) + + print("Taux de classification sur l'ensemble d'apprentissage : ", taux_classification(Ypred_app,Y_app)) + + # Evaluation du modèle sur les données de test + Ypred_test = prediction(X_test,theta) + + print("Taux de classification sur l'ensemble de test : ", taux_classification(Ypred_test,Y_test)) + + # Affichage des points d'apprentissage en 2D et représentation de leur classe prédite par une couleur + if nb_var == 2 : + plt.figure() + plt.title("Disposition des points en 2D - Prédiction (apprentissage)") + affichage(X_app,Ypred_app) + + # Affichage des points de test en 2D et représentation de leur classe prédite par une couleur + if nb_var == 2 : + plt.figure() + plt.title("Disposition des points en 2D - Prédiction (test)") + affichage(X_test,Ypred_test) + + + plt.show() + + print("Regression logistique Terminée.") diff --git a/TD/TD3/regression_logistique-etendu-3-complet.py b/TD/TD3/regression_logistique-etendu-3-complet.py new file mode 100644 index 0000000000000000000000000000000000000000..b6a07efb075b9eaa8975bb04335205682f480b1f --- /dev/null +++ b/TD/TD3/regression_logistique-etendu-3-complet.py @@ -0,0 +1,436 @@ +# Ajout de la classification multi-classes + +import matplotlib.pyplot as plt +import numpy as np + +def lecture_donnees(nom_fichier, delimiteur=','): + """ Lit le fichier contenant les données et renvoiee les matrices correspondant + + Parametres + ---------- + nom_fichier : nom du fichier contenant les données + delimiteur : caratère délimitant les colonne dans le fichier ("," par défaut) + + Retour + ------- + X : matrice des données de dimension [N, nb_var] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + N : nombre d'éléments + nb_var : nombre de variables prédictives + nb_classes : nombre de classes (max de la valeur de la variable cible +1) + + + """ + + data = np.loadtxt(nom_fichier, delimiter=delimiteur) + nb_var = data.shape[1] - 1 + N = data.shape[0] + + X = data[:, :-1] + Y = data[:, -1].reshape(N,1) + + nb_classes = int(np.max(Y)+1) + + return X, Y, N, nb_var, nb_classes + +def normalisation(X): + """ Normalise les données par un centrage-réduction des variables prédictives + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + X_norm : matrice des données centrées-réduites de dimension [N, nb_var] + mu : moyenne des variables de dimension [1,nb_var] + sigma : écart-type des variables de dimension [1,nb_var] + + """ + + mu = np.mean(X, 0) + sigma = np.std(X, 0) + X_norm = (X - mu) / sigma + + return X_norm, mu, sigma + +def decoupage_donnees(X,Y,ratio_apprentissage): + """ Découpe les données en deux ensembles : apprentissage et test + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + ratio_apprentissage : ratio de données d’apprentissage par rapport aux données de test (entre 0 et 1) + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + X_app : matrice des données d'apprentissage + Y_app : matrice contenant les valeurs de la variable cible pour les données d'apprentissage + X_test : matrice des données de test + Y_test : matrice contenant les valeurs de la variable cible pour les données de test + + """ + + # Création d'un vecteur d'indices dans un ordre aléatoire + N = X.shape[0] + indices = np.arange(N) + np.random.shuffle(indices) + + indice_split = int(N*ratio_apprentissage) + + indices_app = indices[:indice_split] + indices_test = indices[indice_split:] + + X_app = X[indices_app,:] + Y_app = Y[indices_app] + X_test = X[indices_test,:] + Y_test = Y[indices_test] + + return X_app, Y_app, X_test, Y_test + + +def sigmoide(z): + """ Calcule la valeur de la fonction sigmoide appliquée à z + + Parametres + ---------- + z : peut être un scalaire ou une matrice + + Return + ------- + s : valeur de sigmoide de z. Même dimension que z + + """ + + s = 1 / (1 + np.exp(-z)) + + return s + +def calcule_cout(X, Y, theta): + """ Calcule la valeur de la fonction cout ( - log vraisemblance) + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Return + ------- + cout : nombre correspondant à la valeur de la fonction cout (moyenne des différences au carré) + + """ + + N = X.shape[0] + + cout = - (Y*np.log(sigmoide(X.dot(theta.T))) + (1-Y)*np.log(1-sigmoide(X.dot(theta.T)))).sum() / N + + return cout + +def descente_gradient_lot(X, Y, theta, alpha, nb_iters): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie par lot + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + for i in range(0, nb_iters): + + error = sigmoide(X.dot(theta.T)) - Y + theta -= (alpha/N)*np.sum(X*error, 0) + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + +def descente_gradient_stochastique(X, Y, theta, alpha, nb_iters): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie stochastique + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + # Création d'un vecteur d'indices pour parcourir X élément par élément, dans un ordre aléatoire + indices = np.arange(N) + np.random.shuffle(indices) + + for i in range(0, nb_iters): + + for j in range(N): + + error = sigmoide(X[indices[j],:].dot(theta.T)) - Y[indices[j]] + theta -= alpha*X[indices[j],:]*error + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + +def descente_gradient_mini_lot(X, Y, theta, alpha, nb_iters, taille_lots=16): + """ Apprentissage des parametres de regression logistique par descente du gradient + avec la stratégie par mini-lots + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + theta : matrices contenant les paramètres theta du modèle linéaire de dimension [1, nb_var+1] + alpha : taux d'apprentissage + nb_iters : nombre d'itérations + taille_lots = nombre d'éléments dans chaque mini-lot + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + theta : matrices contenant les paramètres theta appris par descente du gradient de dimension [1, nb_var+1] + J_history : tableau contenant les valeurs de la fonction cout pour chaque iteration de dimension nb_iters + + + """ + + # Initialisation de variables utiles + N = X.shape[0] + J_history = np.zeros(nb_iters) + + # Création d'un vecteur d'indices pour parcourir X élément par élément, dans un ordre aléatoire + indices = np.arange(N) + np.random.shuffle(indices) + nb_lots = N // taille_lots + indices_lots = [] + for i in range(nb_lots): + ind_debut = i*taille_lots + indices_lots.append(indices[ind_debut:ind_debut+taille_lots]) + + for i in range(0, nb_iters): + + for j in range(nb_lots): + + error = sigmoide(X[indices_lots[j],:].dot(theta.T)) - Y[indices_lots[j]] + theta -= (alpha/taille_lots)*np.sum(X[indices_lots[j],:]*error, 0) + + J_history[i] = calcule_cout(X, Y, theta) + + + return theta, J_history + + +def prediction(X,thetas): + """ Predit la classe de chaque élement de X + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + thetas : liste contenant les paramètres theta des modèle logistiques de dimension [1, nb_var+1] pour chaque classe + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + + Retour + ------- + p : matrices de dimension [N,1] indiquant la classe de chaque élement de X + + """ + + N = X.shape[0] + + preds = sigmoide(X.dot(thetas[0].T)).reshape(N,1) + + for i in range(1,len(thetas)): + pred = sigmoide(X.dot(thetas[i].T)).reshape(N,1) + preds = np.concatenate((preds, pred), axis=1) + + p = np.argmax(preds,1) + + return p + +def taux_classification(Ypred,Y): + """ Calcule le taux de classification (proportion d'éléments bien classés) + + Parametres + ---------- + Ypred : matrice contenant les valeurs de classe prédites de dimension [N, 1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments + + + Retour + ------- + t : taux de classification + + """ + + t = np.mean(Ypred==Y) + return t + +def affichage(X, Y): + """ Affichage en 2 dimensions des données (2 dimensions de X) et représentation de la + classe (indiquée par Y) par une couleur + + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var+1] + Y : matrice contenant les valeurs de la variable cible de dimension [N, 1] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + None + + """ + + plt.scatter(X[:, 1], X[:, 2], c=Y) + + +if __name__ == "__main__": + # ===================== Partie 1: Lecture et normalisation des données===================== + print("Lecture des données ...") + + X, Y, N, nb_var, nb_classes = lecture_donnees("iris.txt") + + # Affichage des 10 premiers exemples du dataset + print("Affichage des 10 premiers exemples du dataset : ") + for i in range(0, 10): + print(f"x = {X[i,:]}, y = {Y[i]}") + + # Normalisation des variables (centrage-réduction) + print("Normalisation des variables ...") + + X, mu, sigma = normalisation(X) + + # Ajout d'une colonne de 1 à X (pour theta0) + X = np.hstack((np.ones((N,1)), X)) + + # Découpage des données en un ensemble d'apprentissage et un ensemble de test + X_app, Y_app, X_test, Y_test = decoupage_donnees(X,Y,0.8) + + # Affichage des points d'apprentissage en 2D et représentation de leur classe réelle par une couleur + + plt.figure() + plt.title("Disposition des points en 2D - Réalité (apprentissage)") + affichage(X_app,Y_app) + + # Affichage des points de test en 2D et représentation de leur classe réelle par une couleur + + plt.figure() + plt.title("Disposition des points en 2D - Réalité (test)") + affichage(X_test,Y_test) + + # ===================== Partie 2: Descente du gradient ===================== + print("Apprentissage par descente du gradient ...") + + # Choix du taux d'apprentissage et du nombre d'itérations + alpha = 0.01 + nb_iters = 5000 + + # Initialisation de theta et réalisation de la descente du gradient pour chaque modèle + thetas = [] + J_histories = [] + for ind_classe in range(nb_classes): + theta = np.zeros((1,nb_var+1)) + + pos = np.where(Y_app == ind_classe) + neg = np.where(Y_app != ind_classe) + + Y_app_modif = np.copy(Y_app) + Y_app_modif[pos] = 1 + Y_app_modif[neg] = 0 + + + theta, J_history = descente_gradient_lot(X_app, Y_app_modif, theta, alpha, nb_iters) + # theta, J_history = descente_gradient_stochastique(X_app, Y_app_modif, theta, alpha, nb_iters) + # theta, J_history = descente_gradient_mini_lot(X_app, Y_app_modif, theta, alpha, nb_iters, taille_lots=16) + + thetas.append(theta) + J_histories.append(J_history) + + + # Affichage de l'évolution de la fonction de cout lors de la descente du gradient + plt.figure() + plt.title(f"Evolution de le fonction de cout lors de la descente du gradient") + for i in range(len(J_histories)): + plt.plot(np.arange(J_histories[i].size), J_histories[i], label = f"Class {i}") + plt.xlabel("Nombre d'iterations") + plt.ylabel("Cout J") + plt.legend() + + # Affichage de la valeur de thetas + print(f"Thetas calculés par la descente du gradient : {thetas}") + + # Evaluation du modèle sur les données d'apprentissage + Ypred_app = prediction(X_app,thetas).reshape(-1,1) + print("Taux de classification sur l'ensemble d'apprentissage : ", taux_classification(Ypred_app,Y_app)) + + # Evaluation du modèle sur les données de test + Ypred_test = prediction(X_test,thetas).reshape(-1,1) + + print("Taux de classification sur l'ensemble de test : ", taux_classification(Ypred_test,Y_test)) + + # Affichage des points d'apprentissage en 2D et représentation de leur classe prédite par une couleur + + plt.figure() + plt.title("Disposition des points en 2D - Prédiction (apprentissage)") + affichage(X_app,Ypred_app) + + # Affichage des points de test en 2D et représentation de leur classe prédite par une couleur + + plt.figure() + plt.title("Disposition des points en 2D - Prédiction (test)") + affichage(X_test,Ypred_test) + + + plt.show() + + print("Regression logistique Terminée.") diff --git a/TD/TD4/ML-TD4.pdf b/TD/TD4/ML-TD4.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0d3763f3b4f17ed25c7675d631385796edc38395 Binary files /dev/null and b/TD/TD4/ML-TD4.pdf differ diff --git a/TD/TD4/food_truck.txt b/TD/TD4/food_truck.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f88ccb611f840ba9283e0de2a26b6cb9b8fde02 --- /dev/null +++ b/TD/TD4/food_truck.txt @@ -0,0 +1,97 @@ +6.1101,17.592 +5.5277,9.1302 +8.5186,13.662 +7.0032,11.854 +5.8598,6.8233 +8.3829,11.886 +7.4764,4.3483 +8.5781,12 +6.4862,6.5987 +5.0546,3.8166 +5.7107,3.2522 +14.164,15.505 +5.734,3.1551 +8.4084,7.2258 +5.6407,0.71618 +5.3794,3.5129 +6.3654,5.3048 +5.1301,0.56077 +6.4296,3.6518 +7.0708,5.3893 +6.1891,3.1386 +20.27,21.767 +5.4901,4.263 +6.3261,5.1875 +5.5649,3.0825 +18.945,22.638 +12.828,13.501 +10.957,7.0467 +13.176,14.692 +22.203,24.147 +5.2524,-1.22 +6.5894,5.9966 +9.2482,12.134 +5.8918,1.8495 +8.2111,6.5426 +7.9334,4.5623 +8.0959,4.1164 +5.6063,3.3928 +12.836,10.117 +6.3534,5.4974 +5.4069,0.55657 +6.8825,3.9115 +11.708,5.3854 +5.7737,2.4406 +7.8247,6.7318 +7.0931,1.0463 +5.0702,5.1337 +5.8014,1.844 +11.7,8.0043 +5.5416,1.0179 +7.5402,6.7504 +5.3077,1.8396 +7.4239,4.2885 +7.6031,4.9981 +6.3328,1.4233 +6.3589,-1.4211 +6.2742,2.4756 +5.6397,4.6042 +9.3102,3.9624 +9.4536,5.4141 +8.8254,5.1694 +5.1793,-0.74279 +21.279,17.929 +14.908,12.054 +18.959,17.054 +7.2182,4.8852 +8.2951,5.7442 +10.236,7.7754 +5.4994,1.0173 +20.341,20.992 +10.136,6.6799 +7.3345,4.0259 +6.0062,1.2784 +7.2259,3.3411 +5.0269,-2.6807 +6.5479,0.29678 +7.5386,3.8845 +5.0365,5.7014 +10.274,6.7526 +5.1077,2.0576 +5.7292,0.47953 +5.1884,0.20421 +6.3557,0.67861 +9.7687,7.5435 +6.5159,5.3436 +8.5172,4.2415 +9.1802,6.7981 +6.002,0.92695 +5.5204,0.152 +5.0594,2.8214 +5.7077,1.8451 +7.6366,4.2959 +5.8707,7.2029 +5.3054,1.9869 +8.2934,0.14454 +13.394,9.0551 +5.4369,0.61705 diff --git a/TD/TD4/houses.txt b/TD/TD4/houses.txt new file mode 100644 index 0000000000000000000000000000000000000000..79e9a807edd86632d58aa2ec832e190d997f43e7 --- /dev/null +++ b/TD/TD4/houses.txt @@ -0,0 +1,47 @@ +2104,3,399900 +1600,3,329900 +2400,3,369000 +1416,2,232000 +3000,4,539900 +1985,4,299900 +1534,3,314900 +1427,3,198999 +1380,3,212000 +1494,3,242500 +1940,4,239999 +2000,3,347000 +1890,3,329999 +4478,5,699900 +1268,3,259900 +2300,4,449900 +1320,2,299900 +1236,3,199900 +2609,4,499998 +3031,4,599000 +1767,3,252900 +1888,2,255000 +1604,3,242900 +1962,4,259900 +3890,3,573900 +1100,3,249900 +1458,3,464500 +2526,3,469000 +2200,3,475000 +2637,3,299900 +1839,2,349900 +1000,1,169900 +2040,4,314900 +3137,3,579900 +1811,4,285900 +1437,3,249900 +1239,3,229900 +2132,4,345000 +4215,4,549000 +2162,4,287000 +1664,2,368500 +2238,3,329900 +2567,4,314000 +1200,3,299000 +852,2,179900 +1852,4,299900 +1203,3,239500 diff --git a/TD/TD4/iris.txt b/TD/TD4/iris.txt new file mode 100644 index 0000000000000000000000000000000000000000..1de4bbac2d427f72603868801f7647f04cb281a1 --- /dev/null +++ b/TD/TD4/iris.txt @@ -0,0 +1,150 @@ +5.1,3.5,1.4,0.2,0 +4.9,3.0,1.4,0.2,0 +4.7,3.2,1.3,0.2,0 +4.6,3.1,1.5,0.2,0 +5.0,3.6,1.4,0.2,0 +5.4,3.9,1.7,0.4,0 +4.6,3.4,1.4,0.3,0 +5.0,3.4,1.5,0.2,0 +4.4,2.9,1.4,0.2,0 +4.9,3.1,1.5,0.1,0 +5.4,3.7,1.5,0.2,0 +4.8,3.4,1.6,0.2,0 +4.8,3.0,1.4,0.1,0 +4.3,3.0,1.1,0.1,0 +5.8,4.0,1.2,0.2,0 +5.7,4.4,1.5,0.4,0 +5.4,3.9,1.3,0.4,0 +5.1,3.5,1.4,0.3,0 +5.7,3.8,1.7,0.3,0 +5.1,3.8,1.5,0.3,0 +5.4,3.4,1.7,0.2,0 +5.1,3.7,1.5,0.4,0 +4.6,3.6,1.0,0.2,0 +5.1,3.3,1.7,0.5,0 +4.8,3.4,1.9,0.2,0 +5.0,3.0,1.6,0.2,0 +5.0,3.4,1.6,0.4,0 +5.2,3.5,1.5,0.2,0 +5.2,3.4,1.4,0.2,0 +4.7,3.2,1.6,0.2,0 +4.8,3.1,1.6,0.2,0 +5.4,3.4,1.5,0.4,0 +5.2,4.1,1.5,0.1,0 +5.5,4.2,1.4,0.2,0 +4.9,3.1,1.5,0.1,0 +5.0,3.2,1.2,0.2,0 +5.5,3.5,1.3,0.2,0 +4.9,3.1,1.5,0.1,0 +4.4,3.0,1.3,0.2,0 +5.1,3.4,1.5,0.2,0 +5.0,3.5,1.3,0.3,0 +4.5,2.3,1.3,0.3,0 +4.4,3.2,1.3,0.2,0 +5.0,3.5,1.6,0.6,0 +5.1,3.8,1.9,0.4,0 +4.8,3.0,1.4,0.3,0 +5.1,3.8,1.6,0.2,0 +4.6,3.2,1.4,0.2,0 +5.3,3.7,1.5,0.2,0 +5.0,3.3,1.4,0.2,0 +7.0,3.2,4.7,1.4,1 +6.4,3.2,4.5,1.5,1 +6.9,3.1,4.9,1.5,1 +5.5,2.3,4.0,1.3,1 +6.5,2.8,4.6,1.5,1 +5.7,2.8,4.5,1.3,1 +6.3,3.3,4.7,1.6,1 +4.9,2.4,3.3,1.0,1 +6.6,2.9,4.6,1.3,1 +5.2,2.7,3.9,1.4,1 +5.0,2.0,3.5,1.0,1 +5.9,3.0,4.2,1.5,1 +6.0,2.2,4.0,1.0,1 +6.1,2.9,4.7,1.4,1 +5.6,2.9,3.6,1.3,1 +6.7,3.1,4.4,1.4,1 +5.6,3.0,4.5,1.5,1 +5.8,2.7,4.1,1.0,1 +6.2,2.2,4.5,1.5,1 +5.6,2.5,3.9,1.1,1 +5.9,3.2,4.8,1.8,1 +6.1,2.8,4.0,1.3,1 +6.3,2.5,4.9,1.5,1 +6.1,2.8,4.7,1.2,1 +6.4,2.9,4.3,1.3,1 +6.6,3.0,4.4,1.4,1 +6.8,2.8,4.8,1.4,1 +6.7,3.0,5.0,1.7,1 +6.0,2.9,4.5,1.5,1 +5.7,2.6,3.5,1.0,1 +5.5,2.4,3.8,1.1,1 +5.5,2.4,3.7,1.0,1 +5.8,2.7,3.9,1.2,1 +6.0,2.7,5.1,1.6,1 +5.4,3.0,4.5,1.5,1 +6.0,3.4,4.5,1.6,1 +6.7,3.1,4.7,1.5,1 +6.3,2.3,4.4,1.3,1 +5.6,3.0,4.1,1.3,1 +5.5,2.5,4.0,1.3,1 +5.5,2.6,4.4,1.2,1 +6.1,3.0,4.6,1.4,1 +5.8,2.6,4.0,1.2,1 +5.0,2.3,3.3,1.0,1 +5.6,2.7,4.2,1.3,1 +5.7,3.0,4.2,1.2,1 +5.7,2.9,4.2,1.3,1 +6.2,2.9,4.3,1.3,1 +5.1,2.5,3.0,1.1,1 +5.7,2.8,4.1,1.3,1 +6.3,3.3,6.0,2.5,2 +5.8,2.7,5.1,1.9,2 +7.1,3.0,5.9,2.1,2 +6.3,2.9,5.6,1.8,2 +6.5,3.0,5.8,2.2,2 +7.6,3.0,6.6,2.1,2 +4.9,2.5,4.5,1.7,2 +7.3,2.9,6.3,1.8,2 +6.7,2.5,5.8,1.8,2 +7.2,3.6,6.1,2.5,2 +6.5,3.2,5.1,2.0,2 +6.4,2.7,5.3,1.9,2 +6.8,3.0,5.5,2.1,2 +5.7,2.5,5.0,2.0,2 +5.8,2.8,5.1,2.4,2 +6.4,3.2,5.3,2.3,2 +6.5,3.0,5.5,1.8,2 +7.7,3.8,6.7,2.2,2 +7.7,2.6,6.9,2.3,2 +6.0,2.2,5.0,1.5,2 +6.9,3.2,5.7,2.3,2 +5.6,2.8,4.9,2.0,2 +7.7,2.8,6.7,2.0,2 +6.3,2.7,4.9,1.8,2 +6.7,3.3,5.7,2.1,2 +7.2,3.2,6.0,1.8,2 +6.2,2.8,4.8,1.8,2 +6.1,3.0,4.9,1.8,2 +6.4,2.8,5.6,2.1,2 +7.2,3.0,5.8,1.6,2 +7.4,2.8,6.1,1.9,2 +7.9,3.8,6.4,2.0,2 +6.4,2.8,5.6,2.2,2 +6.3,2.8,5.1,1.5,2 +6.1,2.6,5.6,1.4,2 +7.7,3.0,6.1,2.3,2 +6.3,3.4,5.6,2.4,2 +6.4,3.1,5.5,1.8,2 +6.0,3.0,4.8,1.8,2 +6.9,3.1,5.4,2.1,2 +6.7,3.1,5.6,2.4,2 +6.9,3.1,5.1,2.3,2 +5.8,2.7,5.1,1.9,2 +6.8,3.2,5.9,2.3,2 +6.7,3.3,5.7,2.5,2 +6.7,3.0,5.2,2.3,2 +6.3,2.5,5.0,1.9,2 +6.5,3.0,5.2,2.0,2 +6.2,3.4,5.4,2.3,2 +5.9,3.0,5.1,1.8,2 \ No newline at end of file diff --git a/TD/TD4/rn_regression.py b/TD/TD4/rn_regression.py new file mode 100644 index 0000000000000000000000000000000000000000..3c6e7727fd4b858354374acd392f88b46ce3f4c6 --- /dev/null +++ b/TD/TD4/rn_regression.py @@ -0,0 +1,321 @@ +import matplotlib.pyplot as plt +import numpy as np + +def lecture_donnees(nom_fichier, delimiteur=','): + """ Lit le fichier contenant les données et renvoiee les matrices correspondant + + Parametres + ---------- + nom_fichier : nom du fichier contenant les données + delimiteur : caratère délimitant les colonne dans le fichier ("," par défaut) + + Retour + ------- + x : matrice des données de dimension [N, nb_var] + d : matrice contenant les valeurs de la variable cible de dimension [N, nb_cible] + N : nombre d'éléments + nb_var : nombre de variables prédictives + nb_cible : nombre de variables cibles + + """ + + data = np.loadtxt(nom_fichier, delimiter=delimiteur) + + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return x, d, N, nb_var, nb_cible + +def normalisation(x): + """ Normalise les données par un centrage-réduction des variables prédictives + + Parametres + ---------- + X : matrice des données de dimension [N, nb_var] + + avec N : nombre d'éléments et nb_var : nombre de variables prédictives + + Retour + ------- + X_norm : matrice des données centrées-réduites de dimension [N, nb_var] + mu : moyenne des variables de dimension [1,nb_var] + sigma : écart-type des variables de dimension [1,nb_var] + + """ + + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return x_norm, mu, sigma + +def decoupage_donnees(x,d,prop_val=0.2, prop_test=0.2): + """ Découpe les données initiales en trois sous-ensembles distincts d'apprentissage, de validation et de test + + Parametres + ---------- + x : matrice des données de dimension [N, nb_var] + d : matrice des valeurs cibles [N, nb_cible] + prop_val : proportion des données de validation sur l'ensemble des données (entre 0 et 1) + prop_test : proportion des données de test sur l'ensemble des données (entre 0 et 1) + + avec N : nombre d'éléments, nb_var : nombre de variables prédictives, nb_cible : nombre de variables cibles + + Retour + ------- + x_app : matrice des données d'apprentissage + d_app : matrice des valeurs cibles d'apprentissage + x_val : matrice des données d'apprentissage + d_val : matrice des valeurs cibles d'apprentissage + x_test : matrice des données d'apprentissage + d_test : matrice des valeurs cibles d'apprentissage + + """ + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return x_app, d_app, x_val, d_val, x_test, d_test + +def calcule_cout_mse(y, d): + """ Calcule la valeur de la fonction cout MSE (moyenne des différences au carré) + + Parametres + ---------- + y : matrice des données prédites + d : matrice des données réelles + + Return + ------- + cout : nombre correspondant à la valeur de la fonction cout (moyenne des différences au carré) + + """ + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return cout + +def passe_avant(x, W, b, activation): + """ Réalise une passe avant dans le réseau de neurones + + Parametres + ---------- + x : matrice des entrées, de dimension nb_var x N + W : liste contenant les matrices des poids du réseau + b : liste contenant les matrices des biais du réseau + activation : liste contenant les fonctions d'activation des couches du réseau + + avec N : nombre d'éléments, nb_var : nombre de variables prédictives + + Return + ------- + a : liste contenant les potentiels d'entrée des couches du réseau + h : liste contenant les sorties des couches du réseau + + """ + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return a, h + +def passe_arriere(delta_h, a, h, W, activation): + """ Réalise une passe arrière dans le réseau de neurones (rétropropagation) + + Parametres + ---------- + delta_h : matrice contenant les valeurs du gradient du coût par rapport à la sortie du réseau + a : liste contenant les potentiels d'entrée des couches du réseau + h : liste contenant les sorties des couches du réseau + W : liste contenant les matrices des poids du réseau + activation : liste contenant les fonctions d'activation des couches du réseau + + Return + ------- + delta_W : liste contenant les matrice des gradients des poids des couches du réseau + delta_b : liste contenant les matrice des gradients des biais des couches du réseau + + """ + + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return delta_W, delta_b + +def sigmoide(z, deriv=False): + """ Calcule la valeur de la fonction sigmoide ou de sa dérivée appliquée à z + + Parametres + ---------- + z : peut être un scalaire ou une matrice + deriv : booléen. Si False renvoie la valeur de la fonction sigmoide, si True renvoie sa dérivée + + Return + ------- + s : valeur de la fonction sigmoide appliquée à z ou de sa dérivée. Même dimension que z + + """ + + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return s + +def lineaire(z, deriv=False): + """ Calcule la valeur de la fonction linéaire ou de sa dérivée appliquée à z + + Parametres + ---------- + z : peut être un scalaire ou une matrice + deriv : booléen. Si False renvoie la valeur de la fonction linéire, si True renvoie sa dérivée + + + Return + ------- + s : valeur de la fonction linéaire appliquée à z ou de sa dérivée. Même dimension que z + + """ + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return s + +def relu(z, deriv=False): + """ Calcule la valeur de la fonction relu ou de sa dérivée appliquée à z + + Parametres + ---------- + z : peut être un scalaire ou une matrice + deriv : booléen. Si False renvoie la valeur de la fonction relu, si True renvoie sa dérivée + + Return + ------- + s : valeur de la fonction relu appliquée à z ou de sa dérivée. Même dimension que z + + """ + + ######################################################### + ##### A compléter (et supprimer l'instruction pass) ##### + ######################################################### + pass + + # return s + + +# ===================== Partie 1: Lecture et normalisation des données ===================== +print("Lecture des données ...") + +x, d, N, nb_var, nb_cible = lecture_donnees("food_truck.txt") +# x, d, N, nb_var, nb_cible = lecture_donnees("houses.txt") + +# Affichage des 10 premiers exemples du dataset +print("Affichage des 10 premiers exemples du dataset : ") +for i in range(0, 10): + print(f"x = {x[i,:]}, d = {d[i]}") + +# Normalisation des variables (centrage-réduction) +print("Normalisation des variables ...") +x, mu, sigma = normalisation(x) +dmax = d.max() +d = d / dmax + +# Découpage des données en sous-ensemble d'apprentissage, de validation et de test +x_app, d_app, x_val, d_val, x_test, d_test = decoupage_donnees(x,d) + +# ===================== Partie 2: Apprentissage ===================== + +# Choix du taux d'apprentissage et du nombre d'itérations +alpha = 0.001 +nb_iters = 500 +couts_apprentissage = np.zeros(nb_iters) +couts_validation = np.zeros(nb_iters) + +# Dimensions du réseau +D_c = [nb_var, 5, 10, nb_cible] # liste contenant le nombre de neurones pour chaque couche +activation = [relu, sigmoide, lineaire] # liste contenant les fonctions d'activation des couches cachées et de la couche de sortie + +# Initialisation aléatoire des poids du réseau +W = [] +b = [] +for i in range(len(D_c)-1): + W.append(2 * np.random.random((D_c[i+1], D_c[i])) - 1) + b.append(np.zeros((D_c[i+1],1))) + +x_app = x_app.T # Les données sont présentées en entrée du réseau comme des vecteurs colonnes +d_app = d_app.T + +x_val = x_val.T # Les données sont présentées en entrée du réseau comme des vecteurs colonnes +d_val = d_val.T + +x_test = x_test.T # Les données sont présentées en entrée du réseau comme des vecteurs colonnes +d_test = d_test.T + +for t in range(nb_iters): + + ############################################################################# + # Passe avant : calcul de la sortie prédite y sur les données de validation # + ############################################################################# + a, h = passe_avant(x_val, W, b, activation) + y_val = h[-1] # Sortie prédite + + ############################################################################### + # Passe avant : calcul de la sortie prédite y sur les données d'apprentissage # + ############################################################################### + a, h = passe_avant(x_app, W, b, activation) + y_app = h[-1] # Sortie prédite + + ########################################### + # Calcul de la fonction perte de type MSE # + ########################################### + couts_apprentissage[t] = calcule_cout_mse(y_app,d_app) + couts_validation[t] = calcule_cout_mse(y_val,d_val) + + #################################### + # Passe arrière : rétropropagation # + #################################### + delta_h = (y_app-d_app) # Pour la dernière couche + delta_W, delta_b = passe_arriere(delta_h, a, h, W, activation) + + ############################################# + # Mise à jour des poids et des biais ##### # + ############################################# + for i in range(len(b)-1,-1,-1): + b[i] -= alpha * delta_b[i] + W[i] -= alpha * delta_W[i] + +print("Coût final sur l'ensemble d'apprentissage : ", couts_apprentissage[-1]) +print("Coût final sur l'ensemble de validation : ", couts_validation[-1]) + +# Affichage de l'évolution de la fonction de cout lors de la rétropropagation +plt.figure(0) +plt.title("Evolution de le fonction de coût lors de la retropropagation") +plt.plot(np.arange(couts_apprentissage.size), couts_apprentissage, label="Apprentissage") +plt.plot(np.arange(couts_validation.size), couts_validation, label="Validation") +plt.legend(loc="upper left") +plt.xlabel("Nombre d'iterations") +plt.ylabel("Coût") +plt.show() + +# ===================== Partie 3: Evaluation sur l'ensemble de test ===================== + +####################################################################### +# Passe avant : calcul de la sortie prédite y sur les données de test # +####################################################################### +a, h = passe_avant(x_test, W, b, activation) +y_test = h[-1] # Sortie prédite + +cout = calcule_cout_mse(y_test,d_test) +print("Coût sur l'ensemble de test : ", cout) diff --git a/TD/TD4/scores.txt b/TD/TD4/scores.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a5f95245719c6f7f08ece4a7785c0f0467c610e --- /dev/null +++ b/TD/TD4/scores.txt @@ -0,0 +1,100 @@ +34.62365962451697,78.0246928153624,0 +30.28671076822607,43.89499752400101,0 +35.84740876993872,72.90219802708364,0 +60.18259938620976,86.30855209546826,1 +79.0327360507101,75.3443764369103,1 +45.08327747668339,56.3163717815305,0 +61.10666453684766,96.51142588489624,1 +75.02474556738889,46.55401354116538,1 +76.09878670226257,87.42056971926803,1 +84.43281996120035,43.53339331072109,1 +95.86155507093572,38.22527805795094,0 +75.01365838958247,30.60326323428011,0 +82.30705337399482,76.48196330235604,1 +69.36458875970939,97.71869196188608,1 +39.53833914367223,76.03681085115882,0 +53.9710521485623,89.20735013750205,1 +69.07014406283025,52.74046973016765,1 +67.94685547711617,46.67857410673128,0 +70.66150955499435,92.92713789364831,1 +76.97878372747498,47.57596364975532,1 +67.37202754570876,42.83843832029179,0 +89.67677575072079,65.79936592745237,1 +50.534788289883,48.85581152764205,0 +34.21206097786789,44.20952859866288,0 +77.9240914545704,68.9723599933059,1 +62.27101367004632,69.95445795447587,1 +80.1901807509566,44.82162893218353,1 +93.114388797442,38.80067033713209,0 +61.83020602312595,50.25610789244621,0 +38.78580379679423,64.99568095539578,0 +61.379289447425,72.80788731317097,1 +85.40451939411645,57.05198397627122,1 +52.10797973193984,63.12762376881715,0 +52.04540476831827,69.43286012045222,1 +40.23689373545111,71.16774802184875,0 +54.63510555424817,52.21388588061123,0 +33.91550010906887,98.86943574220611,0 +64.17698887494485,80.90806058670817,1 +74.78925295941542,41.57341522824434,0 +34.1836400264419,75.2377203360134,0 +83.90239366249155,56.30804621605327,1 +51.54772026906181,46.85629026349976,0 +94.44336776917852,65.56892160559052,1 +82.36875375713919,40.61825515970618,0 +51.04775177128865,45.82270145776001,0 +62.22267576120188,52.06099194836679,0 +77.19303492601364,70.45820000180959,1 +97.77159928000232,86.7278223300282,1 +62.07306379667647,96.76882412413983,1 +91.56497449807442,88.69629254546599,1 +79.94481794066932,74.16311935043758,1 +99.2725269292572,60.99903099844988,1 +90.54671411399852,43.39060180650027,1 +34.52451385320009,60.39634245837173,0 +50.2864961189907,49.80453881323059,0 +49.58667721632031,59.80895099453265,0 +97.64563396007767,68.86157272420604,1 +32.57720016809309,95.59854761387875,0 +74.24869136721598,69.82457122657193,1 +71.79646205863379,78.45356224515052,1 +75.3956114656803,85.75993667331619,1 +35.28611281526193,47.02051394723416,0 +56.25381749711624,39.26147251058019,0 +30.05882244669796,49.59297386723685,0 +44.66826172480893,66.45008614558913,0 +66.56089447242954,41.09209807936973,0 +40.45755098375164,97.53518548909936,1 +49.07256321908844,51.88321182073966,0 +80.27957401466998,92.11606081344084,1 +66.74671856944039,60.99139402740988,1 +32.72283304060323,43.30717306430063,0 +64.0393204150601,78.03168802018232,1 +72.34649422579923,96.22759296761404,1 +60.45788573918959,73.09499809758037,1 +58.84095621726802,75.85844831279042,1 +99.82785779692128,72.36925193383885,1 +47.26426910848174,88.47586499559782,1 +50.45815980285988,75.80985952982456,1 +60.45555629271532,42.50840943572217,0 +82.22666157785568,42.71987853716458,0 +88.9138964166533,69.80378889835472,1 +94.83450672430196,45.69430680250754,1 +67.31925746917527,66.58935317747915,1 +57.23870631569862,59.51428198012956,1 +80.36675600171273,90.96014789746954,1 +68.46852178591112,85.59430710452014,1 +42.0754545384731,78.84478600148043,0 +75.47770200533905,90.42453899753964,1 +78.63542434898018,96.64742716885644,1 +52.34800398794107,60.76950525602592,0 +94.09433112516793,77.15910509073893,1 +90.44855097096364,87.50879176484702,1 +55.48216114069585,35.57070347228866,0 +74.49269241843041,84.84513684930135,1 +89.84580670720979,45.35828361091658,1 +83.48916274498238,48.38028579728175,1 +42.2617008099817,87.10385094025457,1 +99.31500880510394,68.77540947206617,1 +55.34001756003703,64.9319380069486,1 +74.77589300092767,89.52981289513276,1