diff --git a/Code/NeuralNet.py b/Code/NeuralNet.py index 45401ba..094d436 100644 --- a/Code/NeuralNet.py +++ b/Code/NeuralNet.py @@ -2,78 +2,135 @@ """ 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, - * 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 + * 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 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 - +import NeuralNode # le nom de votre classe # NeuralNet pour le modèle Réseaux de Neurones # DecisionTree le modèle des arbres de decision -class Classifier: #nom de la class à changer +class NeuralNet: #nom de la class à changer - def __init__(self, **kwargs): - """ - c'est un Initializer. - Vous pouvez passer d'autre paramètres au besoin, - c'est à vous d'utiliser vos propres notations - """ - - - def train(self, train, train_labels): #vous pouvez rajouter d'autres attribus au besoin - """ - 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 - - vous pouvez rajouter d'autres arguments, il suffit juste de - les expliquer en commentaire - - - - ------------ - - """ + def __init__(self, layers_size, **kwargs): + """ + 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)] + + # 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])) + + 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 + + def train(self, train, train_labels, alpha): #vous pouvez rajouter d'autres attribus au besoin + """ + 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 + + + + ------------ + + """ + + for i in range(len(train)): + deltas = [] + output = self.feed_forward(train[i]) + print("Les valeurs des sorties sont: "+str(output)) + output_layer_error = [] + output_layer_error.append(sum(np.power(output[-1]-train_labels[i],2))/2) + deltas.append(output_layer_error) + # 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]) + + + - 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 + 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 - """ + """ - def test(self, test, test_labels): - """ - 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 - - """ - - - # Vous pouvez rajouter d'autres méthodes et fonctions, - # il suffit juste de les commenter. \ No newline at end of file + def test(self, test, test_labels): + """ + 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 + + """ + + + # Vous pouvez rajouter d'autres méthodes et fonctions, + # il suffit juste de les commenter. \ No newline at end of file diff --git a/Code/NeuralNetUtils.py b/Code/NeuralNetUtils.py new file mode 100644 index 0000000..3bb9a9e --- /dev/null +++ b/Code/NeuralNetUtils.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Apr 30 19:58:26 2019 + +@author: francois +""" + +import math + +def sigmoid(x): + """ + Sigmoid function evaluated at x + """ + return 1/(1 + math.exp(-x)) + +def sigmoid_derivative(x): + """ + Derivative of the sigmoid function evaluated at x + """ + return math.exp(x)/(math.pow((math.exp(x) + 1),2)) \ No newline at end of file diff --git a/Code/NeuralNode.py b/Code/NeuralNode.py new file mode 100644 index 0000000..b445c4d --- /dev/null +++ b/Code/NeuralNode.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Apr 30 19:57:27 2019 + +@author: francois +""" +import numpy as np +import NeuralNetUtils as nnu + +class NeuralNode: + def __init__(self, input_size, input_weights=None, **kwargs): + self.input_size = input_size+1 + if (input_weights == None): + self.input_weights = np.random.uniform(-1,1,self.input_size) + else: + self.input_weights = input_weights + + def __str__(self): + return str(self.input_weights) + + def input_function(self,input_values): + return np.dot(input_values,self.input_weights) + + def activation(self,input_values): + input_values_with_bias = np.hstack((1,input_values)) + return round(nnu.sigmoid(self.input_function(input_values_with_bias))) + + def activation_derivative(self,input_values): + input_values_with_bias = np.hstack((1,input_values)) + return nnu.sigmoid_derivative(self.input_function(input_values_with_bias)) + + def update_weights(self,input_values,alpha,delta): + input_values_with_bias = np.hstack((1,input_values)) + self.input_weights = self.input_weights+(alpha*input_values_with_bias*delta) \ No newline at end of file diff --git a/Code/main.py b/Code/main.py index e3fc2f5..c13264c 100644 --- a/Code/main.py +++ b/Code/main.py @@ -41,4 +41,8 @@ dt4.test(test4, test_labels4) dt5 = DecisionTree.DecisionTree(attribute_type="discrete") dt5.train(train5, train_labels5) dt5.predict(test5[0],test_labels5[0]) -dt5.test(test5, test_labels5) \ No newline at end of file +dt5.test(test5, test_labels5) + +nn1 = NeuralNet.NeuralNet(np.array([4,4,4,1])) +nn1.feed_forward(train1[0]) +nn1.train(train1, train_labels1, 0.1)