diff --git a/fondamentaux/01-regression_lineaire.py b/fondamentaux/01-regression_lineaire.py index 1119328..a5ba936 100644 --- a/fondamentaux/01-regression_lineaire.py +++ b/fondamentaux/01-regression_lineaire.py @@ -22,16 +22,37 @@ import time # - .dot : produit de matrice ### +############################################################################### +# Initialisation +############################################################################### + # Init du temps t_debut = time.time() +# Init des plots +fig = plt.figure(figsize=(10, 5)) +fig.suptitle("Régression linéaire") +donnees_ax = fig.add_subplot(111) + +############################################################################### +# Observations +############################################################################### + # Observations d'apprentisage m = 1000 # Nombre d'observations bg = 1 # Quantité du bruit gaussien -x = 2*np.random.rand(m, 1) # Liste des observations x1 -y = 4 + 3*x + bg * np.random.rand(m, 1) # Liste des cibles y -X = np.c_[np.ones((m, 1)), x] # Matrice des observations, avec x0=1 -plt.plot(x, y, 'b.') +x1 = 2*np.random.rand(m, 1) # Liste des observations x1 +y = 4 + 3*x1 + bg * np.random.rand(m, 1) # Liste des cibles y +X = np.c_[np.ones((m, 1)), x1] # Matrice des observations, avec x0=1 +plt.plot(x1, y, 'b.', label="Observations") + +# Nouvelles observations +x1_new=np.array([[0], [2]]) +X_new = np.c_[np.ones((2, 1)), x1_new] # Matrice des observations, avec x0=1 + +############################################################################### +# Phase d'apprentissage +############################################################################### # Phase d'apprentissage par régression linéaire avec l'équation normale # - theta : vecteur paramètres du modèle @@ -39,16 +60,25 @@ plt.plot(x, y, 'b.') theta_best= np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y) theta = theta_best -# Nouvelles observations -x_new=np.array([[0], [2]]) -X_new = np.c_[np.ones((2, 1)), x_new] # Matrice des observations, avec x0=1 - +############################################################################### # Phase d'inférence +############################################################################### + y_predict=X_new.dot(theta_best) # Liste des prédictions y_predict -plt.plot(x_new, y_predict, 'r-') + +############################################################################### +# Résultats +############################################################################### + +# Plot +donnees_ax.set_title("Données") +donnees_ax.plot(x1_new, y_predict, 'r-', label="Prédictions") +donnees_ax.set_xlabel(r'$x_1$') +donnees_ax.set_ylabel(r'$y$', rotation=0) +donnees_ax.legend() plt.show() -# Performance +# Performances print ("Theta th : theta0 : "+str(4)+" ; theta1 : "+str(3)) print ("Theta : theta0 : "+str(round(float(theta[0]),3))+" ; theta1 : "+str(round(float(theta[1]),3))) print ("Erreurs : theta0 : "+str(round(float(theta[0]-4),3))+" ; theta1 : "+str(round(float(theta[1]-3),3))) diff --git a/fondamentaux/02-descente_gradient.py b/fondamentaux/02-descente_gradient.py index fc45a47..d2ce402 100644 --- a/fondamentaux/02-descente_gradient.py +++ b/fondamentaux/02-descente_gradient.py @@ -1,6 +1,6 @@ import numpy as np import matplotlib.pyplot as plt -import time +import time, math ############################################################################### # 02-descente_gradient.py @@ -22,45 +22,128 @@ import time # - .dot : produit de matrice ### +############################################################################### +# Initialisation +############################################################################### + # Init du temps t_debut = time.time() +# Init des plots +fig = plt.figure(figsize=(10, 5)) +fig.suptitle("Descente de gradient") +donnees_ax = fig.add_subplot(131) +model_ax = fig.add_subplot(132) +couts_ax = fig.add_subplot(133) + +############################################################################### +# Observations +############################################################################### + # Observations d'apprentisage m = 1000 # Nombre d'observations bg = 1 # Quantité du bruit gaussien -x = 2*np.random.rand(m, 1) # Liste des observations x1 -y = 4 + 3*x + bg * np.random.rand(m, 1) # Liste des cibles y -X = np.c_[np.ones((m, 1)), x] # Matrice des observations, avec x0=1 -plt.plot(x, y, 'b.') +x1 = 2*np.random.rand(m, 1) # Liste des observations x1 +y = 4 + 3*x1 + bg * np.random.rand(m, 1) # Liste des cibles y +X = np.c_[np.ones((m, 1)), x1] # Matrice des observations, avec x0=1 +donnees_ax.plot(x1, y, 'b.', label="Observations") +exact_solution = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y) # Equation normale # Nouvelles observations -x_new=np.array([[0], [2]]) -X_new = np.c_[np.ones((2, 1)), x_new] # Matrice des observations, avec x0=1 +x1_new=np.array([[0], [2]]) +X_new = np.c_[np.ones((2, 1)), x1_new] # Matrice des observations, avec x0=1 + +############################################################################### +# Phases d'apprentissage et d'inférence +############################################################################### # Phase d'apprentissage par descente de gradient # - theta : vecteur paramètres du modèle # - gradient : gradient du coût en fonction de theta # - eta : taux d'appentissage -eta = 0.01 # Taux d'appentissage (valeur par défaut : 0.1) -n = 5000 # Nombre d'itérations (valeur par défaut : 1000) -theta= np.random.randn(2,1) # Initialisation aléatoire +eta = 0.01 # Taux d'appentissage (valeur par défaut : 0.1, hyperparamètre) +n = 5000 # Nombre d'itérations (valeur par défaut : 1000 , hyperparamètre) +# Calcul du coût (Mean Square Error (MSE)) +def mse(theta): + return np.sum((np.dot(X, theta) - y)**2)/m +def rmse(theta): + return math.sqrt(np.sum((np.dot(X, theta) - y)**2)/m) + +# Initialisation aléatoire +theta= np.random.randn(2,1) +theta0=[theta[0]] +theta1=[theta[1]] +couts_i=[] +couts_2d=[] +couts_delta=[] +delta = 0 +couts_mse=[] # MSE +couts_rmse=[] # RMSE + +# Descente du gradient for i in range(n): - # Calcul du pas + # Calcul du gradient du pas gradients = 2/m * X.T.dot(X.dot(theta) - y) theta = theta - eta * gradients + theta0.append(theta[0]) + theta1.append(theta[1]) + couts_i.append(i) + + # Calcul de l'erreur avec la norme du vecteur 2D (Objectif -> Theta) dans le plan (theta0, theta1) + couts_2d.append(math.sqrt((theta[0]-exact_solution[0])**2+(theta[1]-exact_solution[1])**2)) + + # Calcul du RMSE à la main : + # FIXME : étrange, je n'ai pas le même résultat qu'avec 'couts_rmse.append(rmse(theta))' + delta = 0 + for j in range (m): + delta= delta +((theta[0] + theta[1]*x1[j])-(exact_solution[0] + exact_solution[1]*x1[j]))**2 + delta = math.sqrt(delta/m) + couts_delta.append(delta) + + # Calcul du RMSE et du MSE par les matrices + couts_mse.append(mse(theta)) + couts_rmse.append(rmse(theta)) # Prédiction du pas + # Phase d'inférence (dernier pas) y_predict=X_new.dot(theta) - plt.plot(x_new, y_predict, 'c-', linewidth=0.5) + donnees_ax.plot(x1_new, y_predict, 'c-', linewidth=0.5) + +############################################################################### +# Résultats +############################################################################### + +# Plot des données +donnees_ax.set_title("Données") +donnees_ax.plot(x1_new, y_predict, 'r-', label="Prédictions") +donnees_ax.set_xlabel(r'$x_1$') +donnees_ax.set_ylabel(r'$y$', rotation=0) +donnees_ax.legend() + +# Plot des paramètres du modèle +model_ax.set_title("Paramètres du modèle") +model_ax.plot(theta0, theta1, '.', ls=':', color='c', fillstyle='none', label="Chemin", markevery=10) +model_ax.plot(exact_solution[0], exact_solution[1], "o", color='k', fillstyle='full', label="Equation normale") +model_ax.set_xlabel(r'$\theta_0$') +model_ax.set_ylabel(r'$\theta_1 $', rotation=0) +model_ax.legend() + +# Plot du cout +couts_ax.set_title("Coûts") +couts_ax.plot(couts_i, couts_2d, '.', ls=':', color='c', fillstyle='none', label="Coûts vecteur 2D", markevery=10) +couts_ax.plot(couts_i, couts_delta, '.', ls=':', color='r', fillstyle='none', label="Coûts RMSE à la main", markevery=10) +couts_ax.plot(couts_i, couts_mse, '.', ls=':', color='b', fillstyle='none', label="Coûts MSE", markevery=10) +couts_ax.plot(couts_i, couts_rmse, '.', ls=':', color='g', fillstyle='none', label="Coûts RMSE", markevery=10) +couts_ax.set_xlabel(r'$i$') +couts_ax.set_ylabel("Coûts") +couts_ax.legend() -# Phase d'inférence (dernier pas) -plt.plot(x_new, y_predict, 'r-') plt.show() -# Performance +# Performances print ("Theta th : theta0 : "+str(4)+" ; theta1 : "+str(3)) print ("Theta : theta0 : "+str(round(float(theta[0]),3))+" ; theta1 : "+str(round(float(theta[1]),3))) print ("Erreurs : theta0 : "+str(round(float(theta[0]-4),3))+" ; theta1 : "+str(round(float(theta[1]-3),3))) diff --git a/fondamentaux/03-descente_gradient_stochastique.py b/fondamentaux/03-descente_gradient_stochastique.py index f8b9c39..5fe19e7 100644 --- a/fondamentaux/03-descente_gradient_stochastique.py +++ b/fondamentaux/03-descente_gradient_stochastique.py @@ -1,6 +1,6 @@ import numpy as np import matplotlib.pyplot as plt -import time +import time, math ############################################################################### # 03-descente_gradient_stochastique.py @@ -22,20 +22,40 @@ import time # - .dot : produit de matrice ### +############################################################################### +# Initialisation +############################################################################### + # Init du temps t_debut = time.time() +# Init des plots +fig = plt.figure(figsize=(10, 5)) +fig.suptitle("Descente de gradient stochastique") +donnees_ax = fig.add_subplot(131) +model_ax = fig.add_subplot(132) +couts_ax = fig.add_subplot(133) + +############################################################################### +# Observations +############################################################################### + # Observations d'apprentisage m = 1000 # Nombre d'observations bg = 1 # Quantité du bruit gaussien -x = 2*np.random.rand(m, 1) # Liste des observations x1 -y = 4 + 3*x + bg * np.random.rand(m, 1) # Liste des cibles y -X = np.c_[np.ones((m, 1)), x] # Matrice des observations, avec x0=1 -plt.plot(x, y, 'b.') +x1 = 2*np.random.rand(m, 1) # Liste des observations x1 +y = 4 + 3*x1 + bg * np.random.rand(m, 1) # Liste des cibles y +X = np.c_[np.ones((m, 1)), x1] # Matrice des observations, avec x0=1 +donnees_ax.plot(x1, y, 'b.', label="Observations") +exact_solution = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y) # Equation normale # Nouvelles observations -x_new=np.array([[0], [2]]) -X_new = np.c_[np.ones((2, 1)), x_new] # Matrice des observations, avec x0=1 +x1_new=np.array([[0], [2]]) +X_new = np.c_[np.ones((2, 1)), x1_new] # Matrice des observations, avec x0=1 + +############################################################################### +# Phase d'apprentissage et d'inférence +############################################################################### # Phase d'apprentissage par descente de gradient stochastique # - theta : vecteur paramètres du modèle @@ -43,34 +63,98 @@ X_new = np.c_[np.ones((2, 1)), x_new] # Matrice des observations, avec x0=1 # - eta : taux d'appentissage ici dégressif par échéancier d'apprentissage (ech_app) # n_epoq = 50 # Nombre d'époques -n_epoq = 2 # Nombre d'époques -t0, t1 = 5, 50 # Hyperparamètres de l'échéancier d'apprentissage +n_epoq = 2 # Nombre d'époques (hyperparamètre) +# Rédéfinition du taux d'apprentissage à partir de l'échéancier d'apprentissage +t0, t1 = 5, 50 # Facteurs de l'échéancier d'apprentissage (hyperparamètres) def ech_app (t): - return t0/ (t + t1) - -theta= np.random.randn(2,1) # Initialisation aléatoire + return t0 / (t + t1) +# Calcul du coût (Mean Square Error (MSE), Root Mean Square Error (RMSE)) +def mse(theta): + return np.sum((np.dot(X, theta) - y)**2)/m +def rmse(theta): + return math.sqrt(np.sum((np.dot(X, theta) - y)**2)/m) + +# Initialisation aléatoire +theta= np.random.randn(2,1) +theta0=[theta[0]] +theta1=[theta[1]] +couts_i=[] +couts_2d=[] +couts_delta=[] +delta = 0 +couts_mse=[] # MSE +couts_rmse=[] # RMSE + +# Descente du gradient for epoq in range (n_epoq): for i in range(m): - # Calcul du pas - i = np.random.randint(m) # Index aléatoire - xi = X[i:i+1] - yi = y[i:i+1] + # Calcul du gradient du pas + idx = np.random.randint(m) # Index aléatoire + xi = X[idx : idx+1] + yi = y[idx : idx+1] gradients = 2/1 * xi.T.dot(xi.dot(theta) - yi) eta = ech_app (epoq * m + i) theta = theta - eta * gradients + theta0.append(theta[0]) + theta1.append(theta[1]) + couts_i.append(epoq * m + i) + + # Calcul de l'erreur avec la norme du vecteur 2D (Objectif -> Theta) dans le plan (theta0, theta1) + couts_2d.append(math.sqrt((theta[0]-exact_solution[0])**2+(theta[1]-exact_solution[1])**2)) + + # Calcul du RMSE à la main : + # FIXME : étrange, je n'ai pas le même résultat qu'avec 'couts_rmse.append(rmse(theta))' + delta = 0 + for j in range (m): + delta= delta +((theta[0] + theta[1]*x1[j])-(exact_solution[0] + exact_solution[1]*x1[j]))**2 + delta = math.sqrt(delta/m) + couts_delta.append(delta) + + # Calcul du RMSE et du MSE par les matrices + couts_mse.append(mse(theta)) + couts_rmse.append(rmse(theta)) # Prédiction du pas + # Phase d'inférence (dernier pas) y_predict=X_new.dot(theta) - plt.plot(x_new, y_predict, 'c-', linewidth=0.5) + donnees_ax.plot(x1_new, y_predict, 'c-', linewidth=0.5) + +############################################################################### +# Résultats +############################################################################### + +# Plot des données +donnees_ax.set_title("Données") +donnees_ax.plot(x1_new, y_predict, 'r-', label="Prédictions") +donnees_ax.set_xlabel(r'$x_1$') +donnees_ax.set_ylabel(r'$y$', rotation=0) +donnees_ax.legend() + +# Plot des paramètres du modèle +model_ax.set_title("Paramètres du modèle") +model_ax.plot(theta0, theta1, '.', ls=':', color='c', fillstyle='none', label="Chemin", markevery=10) +model_ax.plot(exact_solution[0], exact_solution[1], "o", color='k', fillstyle='full', label="Equation normale") +model_ax.set_xlabel(r'$\theta_0$') +model_ax.set_ylabel(r'$\theta_1 $', rotation=0) +model_ax.legend() + +# Plot du cout +couts_ax.set_title("Coûts") +couts_ax.plot(couts_i, couts_2d, '.', ls=':', color='c', fillstyle='none', label="Coûts vecteur 2D", markevery=10) +couts_ax.plot(couts_i, couts_delta, '.', ls=':', color='r', fillstyle='none', label="Coûts RMSE à la main", markevery=10) +couts_ax.plot(couts_i, couts_mse, '.', ls=':', color='b', fillstyle='none', label="Coûts MSE", markevery=10) +couts_ax.plot(couts_i, couts_rmse, '.', ls=':', color='g', fillstyle='none', label="Coûts RMSE", markevery=10) +# couts_ax.plot(couts_i, couts_rmse, color='g', label="Coûts RMSE") +couts_ax.set_xlabel(r'$i$') +couts_ax.set_ylabel("Coûts") +couts_ax.legend() -# Phase d'inférence (dernier pas) -plt.plot(x_new, y_predict, 'r-') plt.show() -# Performance +# Performances print ("Theta th : theta0 : "+str(4)+" ; theta1 : "+str(3)) print ("Theta : theta0 : "+str(round(float(theta[0]),3))+" ; theta1 : "+str(round(float(theta[1]),3))) print ("Erreurs : theta0 : "+str(round(float(theta[0]-4),3))+" ; theta1 : "+str(round(float(theta[1]-3),3))) diff --git a/fondamentaux/04-descente_gradient_mini_lot.py b/fondamentaux/04-descente_gradient_mini_lot.py new file mode 100644 index 0000000..6abbaca --- /dev/null +++ b/fondamentaux/04-descente_gradient_mini_lot.py @@ -0,0 +1,161 @@ +import numpy as np +import matplotlib.pyplot as plt +import time, math + +############################################################################### +# 04-descente_gradient_mini-lots.py +# @title: Apprentissage par descente de gradient par mini-lots +# @project: Mes scripts de ML +# @lang: fr +# @authors: Philippe Roy +# @copyright: Copyright (C) 2023 Philippe Roy +# @license: GNU GPL +############################################################################### + +### +# Commandes NumPy : +# - np.array : créer un tableau à partir d'une liste de listes +# - np.c_ : concatène les colonnes des tableaux +# - np.ones : créer un tableau de 1 +# - np.linalg.inv : inversion de matrice +# - .T : transposé de matrice +# - .dot : produit de matrice +### + +############################################################################### +# Initialisation +############################################################################### + +# Init du temps +t_debut = time.time() + +# Init des plots +fig = plt.figure(figsize=(10, 5)) +fig.suptitle("Descente de gradient par mini-lots") +donnees_ax = fig.add_subplot(131) +model_ax = fig.add_subplot(132) +couts_ax = fig.add_subplot(133) + +############################################################################### +# Observations +############################################################################### + +# Observations d'apprentisage +m = 1000 # Nombre d'observations +bg = 1 # Quantité du bruit gaussien +x1 = 2*np.random.rand(m, 1) # Liste des observations x1 +y = 4 + 3*x1 + bg * np.random.rand(m, 1) # Liste des cibles y +X = np.c_[np.ones((m, 1)), x1] # Matrice des observations, avec x0=1 +donnees_ax.plot(x1, y, 'b.', label="Observations") +exact_solution = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y) # Equation normale + +# Nouvelles observations +x1_new=np.array([[0], [2]]) +X_new = np.c_[np.ones((2, 1)), x1_new] # Matrice des observations, avec x0=1 + +############################################################################### +# Phase d'apprentissage et d'inférence +############################################################################### + +# Phase d'apprentissage par descente de gradient stochastique +# - theta : vecteur paramètres du modèle +# - gradient : gradient du coût en fonction de theta +# - eta : taux d'appentissage ici dégressif par échéancier d'apprentissage (ech_app) + +# n_epoq = 50 # Nombre d'époques +n_epoq = 2 # Nombre d'époques (hyperparamètre) + +# Rédéfinition du taux d'apprentissage à partir de l'échéancier d'apprentissage +t0, t1 = 5, 50 # Facteurs de l'échéancier d'apprentissage (hyperparamètres) +def ech_app (t): + return t0 / (t + t1) + +# Calcul du coût (Mean Square Error (MSE), Root Mean Square Error (RMSE)) +def mse(theta): + return np.sum((np.dot(X, theta) - y)**2)/m +def rmse(theta): + return math.sqrt(np.sum((np.dot(X, theta) - y)**2)/m) + +# Initialisation aléatoire +theta= np.random.randn(2,1) +theta0=[theta[0]] +theta1=[theta[1]] +couts_i=[] +couts_2d=[] +couts_delta=[] +delta = 0 +couts_mse=[] # MSE +couts_rmse=[] # RMSE + +# Descente du gradient +for epoq in range (n_epoq): + for i in range(m): + + # Calcul du gradient du pas + idx = np.random.randint(m) # Index aléatoire + xi = X[idx : idx+1] + yi = y[idx : idx+1] + gradients = 2/1 * xi.T.dot(xi.dot(theta) - yi) + eta = ech_app (epoq * m + i) + theta = theta - eta * gradients + theta0.append(theta[0]) + theta1.append(theta[1]) + couts_i.append(epoq * m + i) + + # Calcul de l'erreur avec la norme du vecteur 2D (Objectif -> Theta) dans le plan (theta0, theta1) + couts_2d.append(math.sqrt((theta[0]-exact_solution[0])**2+(theta[1]-exact_solution[1])**2)) + + # Calcul du RMSE à la main : + # FIXME : étrange, je n'ai pas le même résultat qu'avec 'couts_rmse.append(rmse(theta))' + delta = 0 + for j in range (m): + delta= delta +((theta[0] + theta[1]*x1[j])-(exact_solution[0] + exact_solution[1]*x1[j]))**2 + delta = math.sqrt(delta/m) + couts_delta.append(delta) + + # Calcul du RMSE et du MSE par les matrices + couts_mse.append(mse(theta)) + couts_rmse.append(rmse(theta)) + + # Prédiction du pas + # Phase d'inférence (dernier pas) + y_predict=X_new.dot(theta) + donnees_ax.plot(x1_new, y_predict, 'c-', linewidth=0.5) + +############################################################################### +# Résultats +############################################################################### + +# Plot des données +donnees_ax.set_title("Données") +donnees_ax.plot(x1_new, y_predict, 'r-', label="Prédictions") +donnees_ax.set_xlabel(r'$x_1$') +donnees_ax.set_ylabel(r'$y$', rotation=0) +donnees_ax.legend() + +# Plot des paramètres du modèle +model_ax.set_title("Paramètres du modèle") +model_ax.plot(theta0, theta1, '.', ls=':', color='c', fillstyle='none', label="Chemin", markevery=10) +model_ax.plot(exact_solution[0], exact_solution[1], "o", color='k', fillstyle='full', label="Equation normale") +model_ax.set_xlabel(r'$\theta_0$') +model_ax.set_ylabel(r'$\theta_1 $', rotation=0) +model_ax.legend() + +# Plot du cout +couts_ax.set_title("Coûts") +couts_ax.plot(couts_i, couts_2d, '.', ls=':', color='c', fillstyle='none', label="Coûts vecteur 2D", markevery=10) +couts_ax.plot(couts_i, couts_delta, '.', ls=':', color='r', fillstyle='none', label="Coûts RMSE à la main", markevery=10) +couts_ax.plot(couts_i, couts_mse, '.', ls=':', color='b', fillstyle='none', label="Coûts MSE", markevery=10) +couts_ax.plot(couts_i, couts_rmse, '.', ls=':', color='g', fillstyle='none', label="Coûts RMSE", markevery=10) +# couts_ax.plot(couts_i, couts_rmse, color='g', label="Coûts RMSE") +couts_ax.set_xlabel(r'$i$') +couts_ax.set_ylabel("Coûts") +couts_ax.legend() + +plt.show() + +# Performances +print ("Theta th : theta0 : "+str(4)+" ; theta1 : "+str(3)) +print ("Theta : theta0 : "+str(round(float(theta[0]),3))+" ; theta1 : "+str(round(float(theta[1]),3))) +print ("Erreurs : theta0 : "+str(round(float(theta[0]-4),3))+" ; theta1 : "+str(round(float(theta[1]-3),3))) +print ("Temps : "+str(time.time()-t_debut)) diff --git a/fondamentaux/README.md b/fondamentaux/README.md new file mode 100644 index 0000000..f52816d --- /dev/null +++ b/fondamentaux/README.md @@ -0,0 +1,5 @@ +# Mes scripts de ML - Fondamentaux + +### Apprentissage par régression linéaire + +![capture d'écran](img/01-regression_lineaire.png) diff --git a/fondamentaux/img/01-regression_lineaire.png b/fondamentaux/img/01-regression_lineaire.png new file mode 100644 index 0000000..28c8b35 Binary files /dev/null and b/fondamentaux/img/01-regression_lineaire.png differ diff --git a/fondamentaux/img/02-descente_gradient.png b/fondamentaux/img/02-descente_gradient.png new file mode 100644 index 0000000..7efa763 Binary files /dev/null and b/fondamentaux/img/02-descente_gradient.png differ diff --git a/fondamentaux/img/03-descente_gradient_stochastique.png b/fondamentaux/img/03-descente_gradient_stochastique.png new file mode 100644 index 0000000..d9dfe56 Binary files /dev/null and b/fondamentaux/img/03-descente_gradient_stochastique.png differ