2019-04-29 05:10:20 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
Vous allez definir une classe pour chaque algorithme que vous allez développer,
|
|
|
|
votre classe doit contenit au moins les 3 methodes definies ici bas,
|
2019-05-01 03:31:50 +00:00
|
|
|
* train : pour entrainer le modèle sur l'ensemble d'entrainement
|
|
|
|
* predict : pour prédire la classe d'un exemple donné
|
|
|
|
* test : pour tester sur l'ensemble de test
|
2019-04-29 05:10:20 +00:00
|
|
|
vous pouvez rajouter d'autres méthodes qui peuvent vous etre utiles, mais moi
|
|
|
|
je vais avoir besoin de tester les méthodes train, predict et test de votre code.
|
|
|
|
"""
|
|
|
|
|
|
|
|
import numpy as np
|
2019-05-02 06:49:42 +00:00
|
|
|
import time
|
2019-05-01 03:31:50 +00:00
|
|
|
import NeuralNode
|
2019-05-02 06:49:42 +00:00
|
|
|
import metrics
|
|
|
|
import random
|
|
|
|
|
2019-04-29 05:10:20 +00:00
|
|
|
# le nom de votre classe
|
|
|
|
# NeuralNet pour le modèle Réseaux de Neurones
|
|
|
|
# DecisionTree le modèle des arbres de decision
|
|
|
|
|
2019-05-01 03:31:50 +00:00
|
|
|
class NeuralNet: #nom de la class à changer
|
2019-04-29 05:10:20 +00:00
|
|
|
|
2019-05-02 06:49:42 +00:00
|
|
|
def __init__(self, layers_size, all_labels, **kwargs):
|
2019-05-01 03:31:50 +00:00
|
|
|
"""
|
|
|
|
c'est un Initializer.
|
|
|
|
Vous pouvez passer d'autre paramètres au besoin,
|
|
|
|
c'est à vous d'utiliser vos propres notations
|
|
|
|
"""
|
|
|
|
|
|
|
|
self.layers_size = layers_size
|
|
|
|
self.n_hidden_layers = len(layers_size) - 2
|
|
|
|
self.layers = [[] for i in range(self.n_hidden_layers+1)]
|
2019-05-02 06:49:42 +00:00
|
|
|
self.all_labels = all_labels
|
2019-05-01 03:31:50 +00:00
|
|
|
|
|
|
|
# Couches cachées
|
|
|
|
for j in range(self.n_hidden_layers):
|
|
|
|
for i in range(self.layers_size[j+1]):
|
|
|
|
self.layers[j].append(NeuralNode.NeuralNode(layers_size[j]))
|
|
|
|
|
|
|
|
# Couche de sortie
|
|
|
|
for i in range(layers_size[-1]):
|
|
|
|
self.layers[-1].append(NeuralNode.NeuralNode(layers_size[-2]))
|
|
|
|
|
2019-05-02 06:49:42 +00:00
|
|
|
def __str__(self):
|
|
|
|
outstr = ""
|
|
|
|
for layer in self.layers:
|
|
|
|
for node in layer:
|
|
|
|
outstr+"\n"+str(node.input_weights)
|
|
|
|
return outstr
|
|
|
|
|
|
|
|
def one_hot_encoder(self,labels):
|
|
|
|
nb_labels = len(self.all_labels)
|
|
|
|
one_hot_matrix = []
|
|
|
|
for label in labels:
|
|
|
|
one_rank = np.where(np.array(self.all_labels)==label)
|
|
|
|
one_hot = np.zeros(nb_labels,dtype=np.int64)
|
|
|
|
one_hot[one_rank] = 1
|
|
|
|
one_hot_matrix.append(one_hot)
|
|
|
|
return np.array(one_hot_matrix)
|
|
|
|
|
2019-05-01 03:31:50 +00:00
|
|
|
def feed_forward(self,input_values):
|
|
|
|
all_input_values = []
|
|
|
|
current_input_values = input_values
|
|
|
|
all_input_values.append(current_input_values)
|
|
|
|
for layer in self.layers:
|
|
|
|
activation_values = []
|
|
|
|
for node in layer:
|
|
|
|
activation_values.append(node.activation(current_input_values))
|
|
|
|
current_input_values = activation_values
|
|
|
|
all_input_values.append(current_input_values)
|
|
|
|
return all_input_values
|
|
|
|
|
2019-05-02 06:49:42 +00:00
|
|
|
def train(self, train, train_labels, alpha, nb_epoch): #vous pouvez rajouter d'autres attribus au besoin
|
2019-05-01 03:31:50 +00:00
|
|
|
"""
|
|
|
|
c'est la méthode qui va entrainer votre modèle,
|
|
|
|
train est une matrice de taille nxm, avec
|
|
|
|
n : le nombre d'exemple d'entrainement dans le dataset
|
|
|
|
m : le mobre d'attribus (le nombre de caractéristiques)
|
|
|
|
|
|
|
|
train_labels : est une matrice de taille nx1
|
|
|
|
alpha: learning rate
|
|
|
|
vous pouvez rajouter d'autres arguments, il suffit juste de
|
|
|
|
les expliquer en commentaire
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
------------
|
|
|
|
|
|
|
|
"""
|
2019-05-02 06:49:42 +00:00
|
|
|
train_labels_enc = self.one_hot_encoder(train_labels)
|
|
|
|
|
|
|
|
for epoch in range(nb_epoch):
|
|
|
|
print("epoch"+str(epoch))
|
|
|
|
for i in range(len(train)):
|
|
|
|
deltas = []
|
|
|
|
output = self.feed_forward(train[i])
|
|
|
|
print("Les valeurs des sorties sont: "+str(output)+"\nLabel:"+str(train_labels_enc[i]))
|
|
|
|
deltas.append(train_labels_enc[i]-output[-1])
|
|
|
|
# On recule dans les couches cachées j
|
|
|
|
for j in reversed(range(self.n_hidden_layers)):
|
|
|
|
#print("la couche "+str(j))
|
|
|
|
layerError = []
|
|
|
|
# Pour chaque neurone k de la couche cachée courante
|
|
|
|
for k in range(len(self.layers[j])):
|
|
|
|
#print("le neurone "+str(k)+" de la couche "+str(j))
|
|
|
|
average_error = 0
|
|
|
|
# Pour chaque neurone l de la couche j+1
|
|
|
|
for l in range(len(self.layers[j+1])):
|
|
|
|
#print("la "+str(l)+"e entrée dans le neurone "+str(k)+" de la couche "+str(j+1))
|
|
|
|
current_delta = deltas[0][l]
|
|
|
|
average_error += current_delta * self.layers[j+1][l].input_weights[k+1]
|
|
|
|
layerError.append(average_error * self.layers[j][k].activation_derivative(output[j]))
|
|
|
|
# Vu qu'on recule, on insère au début au lieu de la fin
|
|
|
|
deltas.insert(0,layerError)
|
|
|
|
# Mise à jour des poids
|
|
|
|
print("Mise à jour des poids. Les deltas sont: "+str(deltas))
|
|
|
|
for j in range(len(self.layers)):
|
|
|
|
# Pour chaque neurone k
|
|
|
|
for k in range(len(self.layers[j])):
|
|
|
|
self.layers[j][k].update_weights(output[j],alpha,deltas[j][k])
|
|
|
|
return self.test(train, train_labels)
|
|
|
|
|
2019-05-01 03:31:50 +00:00
|
|
|
def predict(self, exemple, label):
|
|
|
|
"""
|
|
|
|
Prédire la classe d'un exemple donné en entrée
|
|
|
|
exemple est de taille 1xm
|
|
|
|
|
|
|
|
si la valeur retournée est la meme que la veleur dans label
|
|
|
|
alors l'exemple est bien classifié, si non c'est une missclassification
|
2019-04-29 05:10:20 +00:00
|
|
|
|
2019-05-01 03:31:50 +00:00
|
|
|
"""
|
2019-05-02 06:49:42 +00:00
|
|
|
return np.argmax(self.feed_forward(exemple)[-1])
|
2019-04-29 05:10:20 +00:00
|
|
|
|
2019-05-02 06:49:42 +00:00
|
|
|
def test(self, test, test_labels, verbose=True):
|
2019-05-01 03:31:50 +00:00
|
|
|
"""
|
|
|
|
c'est la méthode qui va tester votre modèle sur les données de test
|
|
|
|
l'argument test est une matrice de taille nxm, avec
|
|
|
|
n : le nombre d'exemple de test dans le dataset
|
|
|
|
m : le mobre d'attribus (le nombre de caractéristiques)
|
|
|
|
|
|
|
|
test_labels : est une matrice taille nx1
|
|
|
|
|
|
|
|
vous pouvez rajouter d'autres arguments, il suffit juste de
|
|
|
|
les expliquer en commentaire
|
|
|
|
|
|
|
|
Faites le test sur les données de test, et afficher :
|
|
|
|
- la matrice de confision (confusion matrix)
|
|
|
|
- l'accuracy (ou le taux d'erreur)
|
|
|
|
|
|
|
|
Bien entendu ces tests doivent etre faits sur les données de test seulement
|
|
|
|
|
|
|
|
"""
|
2019-05-02 06:49:42 +00:00
|
|
|
|
|
|
|
start_time = time.time()
|
|
|
|
prediction_test = [self.predict(exemple,label) for exemple,label in zip(test,test_labels)]
|
|
|
|
print(prediction_test)
|
|
|
|
cm = metrics.confusion_matrix(test_labels,prediction_test)
|
|
|
|
accuracy, precision, recall = metrics.prediction_metrics(cm,test_labels,prediction_test)
|
|
|
|
compute_time = time.time() - start_time
|
|
|
|
if (verbose):
|
|
|
|
metrics.print_prediction_metrics(cm,accuracy,precision,recall,compute_time)
|
|
|
|
|
|
|
|
return cm,accuracy,precision,recall,compute_time
|
2019-05-01 03:31:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Vous pouvez rajouter d'autres méthodes et fonctions,
|
|
|
|
# il suffit juste de les commenter.
|