From f333429567525c50ad87d69f8cdd12ad8b201bc4 Mon Sep 17 00:00:00 2001
From: unknown <you@example.com>
Date: Fri, 10 Nov 2023 14:19:46 +0100
Subject: [PATCH] Ajout des fichiers

---
 knn.py                            |  86 ++++++++++++++++++++
 mlp.py                            | 126 ++++++++++++++++++++++++++++++
 read_cifar.py                     |  44 +++++++++++
 results/._mlp.png                 | Bin 0 -> 4096 bytes
 results/mlp_training_accuracy.png | Bin 0 -> 19182 bytes
 5 files changed, 256 insertions(+)
 create mode 100644 knn.py
 create mode 100644 mlp.py
 create mode 100644 read_cifar.py
 create mode 100644 results/._mlp.png
 create mode 100644 results/mlp_training_accuracy.png

diff --git a/knn.py b/knn.py
new file mode 100644
index 0000000..3a8bd65
--- /dev/null
+++ b/knn.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Oct 26 15:59:25 2023
+
+@author: DE SIMEIS
+"""
+
+from read_cifar import *
+from collections import Counter
+import matplotlib.pyplot as plt
+
+
+# Définition de la fonction calculant la matrice des distances euclidiennes entre les données d'apprentissage et de test
+def distance_matrix(data_train, data_test):
+    sum_of_squares_matrix1 = np.sum(data_train ** 2, axis=1, keepdims=True)
+
+    
+    sum_of_squares_matrix2 = np.sum(data_test ** 2, axis=1, keepdims=True)
+
+
+    dot_product = np.dot(data_train, data_test.T)
+
+    dists = np.sqrt(sum_of_squares_matrix1 - 2 * dot_product + sum_of_squares_matrix2.T)
+
+    return dists
+# Définition de la fonction k-NN pour faire des prédictions
+def knn_predict(dists, labels_train, k):
+
+    dists=dists.T
+    predictions = []
+    for distances in dists:
+        min_indexes = np.argpartition(distances, k)[:k]
+        possible_pred = labels_train[min_indexes]
+        counted = Counter(possible_pred)
+        pred = counted.most_common(1)[0][0]
+        predictions.append(pred)
+    return predictions
+
+# Évaluation de la précision des prédictions
+def evaluate_knn(predictions, labels_test):
+    sum=0
+    for i in range(len(predictions)):
+        if predictions[i] == labels_test[i]:
+            sum+=1
+
+    return sum / len(predictions)
+
+'''def evaluate_knn(data_train , labels_train,data_test ,labels_test, k):
+        
+    return'''
+# Fonction principale
+def main():
+
+    print('#START#')
+    folder_path = 'data/cifar-10-batches-py'
+    data, labels = read_cifar(folder_path)
+
+
+
+    data_train, data_test, labels_train, labels_test = split_dataset(data, labels, 0.9)
+
+
+
+    num_epochs = 20
+    accuracies=[]
+    dists = distance_matrix(data_train, data_test)
+
+    for k in range(num_epochs):
+        prediction=knn_predict(dists, labels_train, k+1)
+        accuracy = evaluate_knn(prediction, labels_test)
+        print(accuracy)
+        accuracies.append(accuracy)
+
+    plt.figure(figsize=(10, 6))
+    x = range(1, num_epochs + 1)
+    plt.plot(x, accuracies)
+    plt.xlabel('Epochs')
+    plt.ylabel('Accuracy')
+    plt.title('Training Accuracy Evolution')
+    plt.grid()
+
+    plt.savefig('KNN.png')
+    plt.show()
+
+
+main()
diff --git a/mlp.py b/mlp.py
new file mode 100644
index 0000000..130bdff
--- /dev/null
+++ b/mlp.py
@@ -0,0 +1,126 @@
+import numpy as np
+import os
+import matplotlib.pyplot as plt
+from read_cifar import read_cifar, split_dataset
+
+
+# Fonction d'activation sigmoid
+def sigmoid(x):
+    return 1 / (1 + np.exp(-x))
+
+# Dérivée de la fonction d'activation sigmoid
+def sigmoid_derivative(x):
+    return x * (1 - x)
+# Fonction d'erreur quadratique moyenne
+
+def mean_squared_error(predictions, targets):
+    return np.mean(np.square(predictions - targets))
+
+# Conversion des étiquettes en one-hot encoding
+def one_hot(labels, num_classes):
+    one_hot_labels = np.zeros((len(labels), num_classes))
+    one_hot_labels[np.arange(len(labels)), labels] = 1
+    return one_hot_labels
+
+# Fonction pour une itération d'apprentissage avec la perte de mean squared error (MSE)
+def learn_once_mse(w1, b1, w2, b2, data, targets, learning_rate):
+    a0 = data
+    z1 = np.dot(a0, w1) + b1
+    a1 = sigmoid(z1)
+    z2 = np.dot(a1, w2) + b2
+    a2 = sigmoid(z2)
+
+    dC_da2 = a2 - targets
+    dC_dz2 = dC_da2 * sigmoid_derivative(a2)
+    dC_da1 = np.dot(dC_dz2, w2.T)
+    dC_dz1 = dC_da1 * sigmoid_derivative(a1)
+
+    dC_dw2 = np.dot(a1.T, dC_dz2)
+    dC_db2 = np.sum(dC_dz2, axis=0)
+    dC_dw1 = np.dot(a0.T, dC_dz1)
+    dC_db1 = np.sum(dC_dz1, axis=0)
+
+    # moyenne des gradients
+    w1 -= learning_rate * dC_dw1 / len(data)
+    b1 -= learning_rate * dC_db1 / len(data)
+    w2 -= learning_rate * dC_dw2 / len(data)
+    b2 -= learning_rate * dC_db2 / len(data)
+
+    loss = mean_squared_error(a2, targets)
+
+    return w1, b1, w2, b2, loss
+
+# Initialisation des poids 
+def initialize_weights(input_size, hidden_size, output_size):
+    
+    w1 = np.random.randn(input_size, hidden_size) / np.sqrt(input_size)
+    b1 = np.zeros((1, hidden_size))
+    w2 = np.random.randn(hidden_size, output_size) / np.sqrt(hidden_size)
+    b2 = np.zeros((1, output_size))
+
+    return w1, b1, w2, b2
+
+# Ajout de la fonction de prédiction
+def predict_mlp(w1, b1, w2, b2, data):
+    a0 = data
+    z1 = np.dot(a0, w1) + b1
+    a1 = sigmoid(z1)
+    z2 = np.dot(a1, w2) + b2
+    a2 = sigmoid(z2)
+    return a2
+
+
+# Fonction principale pour le training du MLP
+
+def run_mlp_training(data_train, labels_train, data_test, labels_test, d_h, learning_rate, num_epochs, results_dir='results'):
+    # Create results directory if it does not exist
+    if not os.path.exists(results_dir):
+        os.makedirs(results_dir)
+
+    N_train = len(data_train)
+    N_test = len(data_test)
+    d_in = data_train.shape[1]
+    d_out = len(np.unique(labels_train))
+
+    w1, b1, w2, b2 = initialize_weights(d_in, d_h, d_out)
+
+    train_accuracies = []
+    losses = []
+
+    for epoch in range(num_epochs):
+        w1, b1, w2, b2, loss = learn_once_mse(w1, b1, w2, b2, data_train, one_hot(labels_train, d_out), learning_rate)
+
+        predictions = predict_mlp(w1, b1, w2, b2, data_train)
+        accuracy = np.mean(np.argmax(predictions, axis=1) == labels_train)
+        train_accuracies.append(accuracy)
+        losses.append(loss)
+        print(f"Epoch {epoch + 1}/{num_epochs} - Loss: {loss:.4f} - Accuracy: {accuracy:.4f}")
+
+    # Enregistrement du graphe training accuracy
+    plt.figure(figsize=(8, 6))
+    plt.plot(range(1, num_epochs + 1), train_accuracies)
+    plt.xlabel("Epoch")
+    plt.ylabel("Training Accuracy")
+    plt.title("MLP Training Accuracy Evolution")
+    plt.grid(True)
+
+    save_path = os.path.join(results_dir, "mlp_training_accuracy.png")
+    plt.savefig(save_path)
+    plt.show()
+
+
+# Avec les données on a :
+split_factor = 0.9
+folder_path = 'data/cifar-10-batches-py'
+data, labels = read_cifar(folder_path)
+
+data_train, data_test, labels_train, labels_test = split_dataset(data, labels, split_factor)
+d_h = 64
+learning_rate = 0.01
+num_epochs = 100
+
+# Pour que ça aille dans le dossier results dans le même dossier que le code
+results_directory = 'results'
+
+# Exécution de l'entraînement mlp
+w1, b1, w2, b2, train_accuracies, losses = run_mlp_training(data_train, labels_train, data_test, labels_test, d_h, learning_rate, num_epochs, results_directory)
diff --git a/read_cifar.py b/read_cifar.py
new file mode 100644
index 0000000..f25b49c
--- /dev/null
+++ b/read_cifar.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Oct 26 15:53:56 2023
+
+@author: DE SIMEIS
+"""
+
+import pickle
+import numpy as np
+import os
+from sklearn.model_selection import train_test_split
+# Charge un batch CIFAR-10 depuis le chemin spécifié.
+#Returns:
+#  - data (numpy.ndarray): Les données du batch.
+#  - labels (numpy.ndarray): Les étiquettes associées aux données.
+def read_cifar_batch(batch):
+    with open(batch, 'rb') as fo:
+        dict = pickle.load(fo, encoding='bytes')
+        data = dict[b'data']
+        labels = dict[b'labels']
+    return data, labels
+
+
+# Charge l'ensemble du dataset CIFAR-10 depuis le répertoire spécifié
+def read_cifar(path):
+    batches_list = os.listdir(path)
+    data, labels = [], []
+    for batch in batches_list:
+        if(batch == 'batches.meta' or batch == 'readme.html'):
+            continue
+        data_batch, labels_batch = read_cifar_batch(path + '/' + batch)
+        data.append(data_batch)
+        labels.append(labels_batch)
+    return np.array(data, dtype=np.float32).reshape((60000, 3072)), np.array(labels, dtype=np.int64).reshape(-1)
+
+#Divise l'ensemble de données en ensembles d'entraînement et de test.
+# Returns:
+#   - data_train (numpy.ndarray): Les données d'entraînement.
+#   - data_test (numpy.ndarray): Les données de test.
+#   - labels_train (numpy.ndarray): Les étiquettes d'entraînement.
+#   - labels_test (numpy.ndarray): Les étiquettes de test.
+def split_dataset(data, labels, split):
+    data_train, data_test, labels_train, labels_test = train_test_split(data, labels, test_size=1-split, shuffle=True)
+    return data_train, data_test, labels_train,labels_test
diff --git a/results/._mlp.png b/results/._mlp.png
new file mode 100644
index 0000000000000000000000000000000000000000..114a742c3cedf3b0d023b2b2efb2a81f4fb82862
GIT binary patch
literal 4096
zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3Cj$e65d#C?1_lNYpYIU^1EU-RLEsn?5@bE=
z<bMVRkPe0e3=9lvXquQ97{KCU3=E>l`MG+D1qC^&dWEHlMTvPOnR%%o<<}S(7z7v?
zq!98siNz(Q#i=PNi6yDZ0l^?e1_l;J)@G(AN#+)oN!9^Hsb!g|<<<s`-e4ngBJw~s
zffSD7(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c4S``F0*nj{3?K~ls9Z=!X0bw1
zYH@yPQF5w6T7FTsLS|k`YF<fZeqLfuPNhOlYFddxQchxCwt|8JSkDkAKz;{dus0C>
KcNqq`|NjB^pgPt7

literal 0
HcmV?d00001

diff --git a/results/mlp_training_accuracy.png b/results/mlp_training_accuracy.png
new file mode 100644
index 0000000000000000000000000000000000000000..65d1741acd1b30b71f783da6820d730109fe1358
GIT binary patch
literal 19182
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

literal 0
HcmV?d00001

-- 
GitLab