des résultats, mais faux
This commit is contained in:
parent
a8a8edac7c
commit
8189a03abf
129
CahierDesCharges.md
Normal file
129
CahierDesCharges.md
Normal file
@ -0,0 +1,129 @@
|
||||
# Conception d’une librairie de réseaux neuronaux
|
||||
|
||||
## Samedi 23 Octobre 2021
|
||||
|
||||
**Hugo EYNARD
|
||||
Thomas BLUSSON
|
||||
Romain MOREAU
|
||||
Gabriel CHAVANON**
|
||||
|
||||
Responsable référent:
|
||||
Gabriel CHAVANON
|
||||
|
||||
Dépot GITEA:
|
||||
https://dwarves.iut-fbleau.fr/gitiut/blusson/PT21-22-Reseau-Neurones
|
||||
|
||||
|
||||
## Sommaire
|
||||
|
||||
- Sommaire
|
||||
- Cahier des charges fonctionnelles
|
||||
- Contexte
|
||||
- Etudes détaillées des objectifs (analyses des besoins)
|
||||
- Calendrier et priorisation des objectives
|
||||
- Cahier des charges techniques et méthodologique
|
||||
- Bibliographie
|
||||
|
||||
|
||||
## Cahier des charges fonctionnelles
|
||||
|
||||
|
||||
### Contexte
|
||||
|
||||
Client : Pierre VALARCHER (tuteur)
|
||||
|
||||
Description:
|
||||
|
||||
Nous comptons concevoir notre propre librairie de réseaux neuronaux et l’optimiser
|
||||
par la suite à travers différents tests (reconnaître des caractères manuscrites). Pour
|
||||
ceci nous ne comptons pas nous appuyer sur des solutions déjà existantes (comme
|
||||
TensorFlow) mais bien tout réaliser de A à Z. Pour ce qui est de l’optimisation (une
|
||||
meilleure vitesse d'exécution et une meilleure précision des résultats) on pourra
|
||||
utiliser des tests et des outils comparatifs (ancienne version de notre projet ou
|
||||
encore des librairies déjà existantes).
|
||||
|
||||
Contraintes :
|
||||
|
||||
On réalisera ce projet en Python orienté objet et grâce à ses librairies, tout notre
|
||||
travail sera disponible surnotre dépôt GITEA.
|
||||
|
||||
Existant :
|
||||
|
||||
Nous avons à notre disposition un jeu de données contenant des images de chiffres
|
||||
annotés avec le chiffre correspondant. Ilnous permettra d'entraînernotre réseau
|
||||
neuronal pour le tester.
|
||||
|
||||
|
||||
### Etudes détaillées des objectifs (analyses des besoins)
|
||||
|
||||
Fonctionnalités :
|
||||
-Choix de la fonction d’activation pour chaque couche de neurones
|
||||
-Choix du nombre de couches de neurones
|
||||
-Choix du type de neurones pour chaque couche
|
||||
-Choix du nombre de neurones dans chaque couche
|
||||
-Faire une prédiction à partir d’un réseau de neurone
|
||||
-Entraîner le réseau de neurones
|
||||
-Exporter et importer l’état (modèle, biais et poids) d’un réseau de neurones
|
||||
-Visualiser l'entraînement d’un réseau de neurone à deux entrées
|
||||
|
||||
Bob le développeur possède un jeu de données comportant des images de chats et
|
||||
de chiens annotés. Il commence par importer Sobek. Ilchoisit ensuitepour son
|
||||
modèlederéseauneuronald’avoirunematrice 360 par 360 pourentrée.Ildécidede
|
||||
mettre 2 premières couches de 180 neurones convolutifs,puis 2 couchesde 64
|
||||
neuronesdenses(ouclassiques)etenfinunesortiede 2 neuronesdenses(Unpour
|
||||
chienet un pourchat). Il sépareson jeude donnéesen 2 parties:ilutiliseles 3
|
||||
premiers quarts pour entraîner son réseau neuronal et après quelques minutes
|
||||
d'attente, il utilise le dernier quart pour estimer sa précision. Après quelques
|
||||
modifications et tests de l'architecture de son réseaupour obtenir une meilleure
|
||||
précision, Bob est satisfait et peut maintenant utiliserson réseaupour faire des
|
||||
prédictions.
|
||||
|
||||
|
||||
### Calendrier et priorisation des objectives
|
||||
|
||||
Jalon 0 : Cahier des charges (à signer) début novembre
|
||||
Jalon 1 : Perceptron multicouche (première itération du projet), mi décembre M
|
||||
1.1 : Partie prédiction du perceptron multicouche M
|
||||
1.2 : Partie apprentissage du perceptron multicouche M
|
||||
1.3 : Estimation de la précision du perceptron multicouche S
|
||||
1.4 : Exportation et importation de l’état du réseau neuronal M
|
||||
Jalon 2 : Utilisation concrète du réseau neuronal, fin décembre M
|
||||
Jalon 3 : Visualisation 2D de l’entraînement du réseau neuronal M
|
||||
Jalon 4 : Réseau de neurones convolutif (version optimisée du perceptron multicouche), fin janvier S
|
||||
4.1 : Création d’un système de choix de type de couche M
|
||||
4.2 : Implémentation du neurone convolutif M
|
||||
Jalon 5 : Utilisation concrète du réseau convolutif, fin février C
|
||||
|
||||
|
||||
## Cahier des charges techniques et méthodologique
|
||||
|
||||
Nous avons choisi d’utiliser le Python car c’est un langage plutôt abordable qui est
|
||||
communément utilisé pour le machine learning. On compte également utiliser Scipy
|
||||
(NumPy (gestion des tableaux), Matplotlib (visualisation de données sous forme
|
||||
graphique).
|
||||
|
||||
Méthodologie de travail :
|
||||
On envisage d’utiliser la méthode agile (1 sprint correspond à 1 jalon) ainsi que le
|
||||
pair programming.
|
||||
|
||||
On compte utiliser très fréquemment GIT, et faire des tests unitaires dès que
|
||||
possible. On utilisera make pour l’exécution des tests et des mises en application.
|
||||
|
||||
|
||||
### Bibliographie
|
||||
|
||||
https://en.wikipedia.org/wiki/Types_of_artificial_neural_networks
|
||||
|
||||
https://youtu.be/bVQUSndDllU
|
||||
|
||||
https://youtu.be/aircAruvnKk
|
||||
|
||||
https://www.mygreatlearning.com/blog/open-source-python-libraries/
|
||||
|
||||
https://fr.wikipedia.org/wiki/Matplotlib
|
||||
|
||||
https://brilliant.org/wiki/backpropagation/
|
||||
|
||||
_Apprentissage machine Clé de l’intelligence artificielle_ - Rémi Gilleron, 2019
|
||||
|
||||
_Deep Learning with Python, 2nd Edition_ - FrançoisChollet, 2021
|
@ -1,4 +1,5 @@
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
class network:
|
||||
|
||||
@ -10,7 +11,7 @@ class network:
|
||||
self.__inputLayerSize = inputLayerSize
|
||||
oldLayerSize = inputLayerSize
|
||||
for layerSize in layerSizes:
|
||||
self.__weights.append( np.random.default_rng(42).random((oldLayerSize, layerSize)) )
|
||||
self.__weights.append( np.random.random((layerSize, oldLayerSize)) )
|
||||
oldLayerSize = layerSize
|
||||
self.__biases = [[0]*layerSize for layerSize in layerSizes]
|
||||
self.__weights = np.array(self.__weights, dtype=object)
|
||||
@ -24,7 +25,7 @@ class network:
|
||||
def __sigmoid(value, derivative=False):
|
||||
if (derivative):
|
||||
return network.__sigmoid(value) * (1 - network.__sigmoid(value))
|
||||
return 1/(1+np.exp(-value))
|
||||
return 1/(1+math.exp(-value))
|
||||
|
||||
def process(self, _input, __storeValues=False):
|
||||
if type(_input) != np.ndarray:
|
||||
@ -35,61 +36,70 @@ class network:
|
||||
# raise TypeError("The input vector must contain floats!")
|
||||
|
||||
if (__storeValues):
|
||||
self.activations = np.array([])
|
||||
self.outputs = np.array([])
|
||||
self.activations = []
|
||||
self.outputs = []
|
||||
|
||||
for layerWeights, bias in zip(self.__weights, self.__biases):
|
||||
_input = np.matmul(_input, layerWeights)
|
||||
|
||||
_input = np.matmul(layerWeights, _input)
|
||||
_input = np.add(_input, bias)
|
||||
|
||||
if (__storeValues):
|
||||
print("-------------------")
|
||||
print(bias)
|
||||
print("-------------------")
|
||||
self.activations = np.append(self.activations, _input)
|
||||
self.activations[len(self.activations)-1] = np.insert(self.activations[len(self.activations)-1], 0, bias)
|
||||
self.activations.append(_input.copy())
|
||||
|
||||
#reLu application
|
||||
with np.nditer(_input, op_flags=['readwrite'], flags=['refs_ok']) as layer:
|
||||
for neuron in layer:
|
||||
neuron = network.__reLu(neuron)
|
||||
for neuron in range(len(_input)):
|
||||
_input[neuron] = network.__sigmoid(_input[neuron])
|
||||
|
||||
#On peut comparer la performance si on recalcul plus tard
|
||||
if (__storeValues):
|
||||
self.outputs = np.append(self.outputs, _input)
|
||||
self.outputs[len(self.outputs)-1] = np.insert(self.outputs[len(self.outputs)-1], 0, 1)
|
||||
self.outputs.append(_input.copy())
|
||||
|
||||
self.activations = np.array(self.activations, dtype=object)
|
||||
self.outputs = np.array(self.outputs, dtype=object)
|
||||
|
||||
return _input
|
||||
|
||||
|
||||
|
||||
def train(self, inputs, desiredOutputs, learningRate):
|
||||
ErrorSums = [[0]*(len(layer)+1) for layer in self.__biases]
|
||||
errorSums = [[[0]*(len(neuron)) for neuron in layer] for layer in self.__weights]
|
||||
self.__errors = [[0]*(len(layer)) for layer in self.__weights]
|
||||
|
||||
for _input, desiredOutput in zip(inputs, desiredOutputs):
|
||||
self.__output = self.process(_input, True)
|
||||
self.__desiredOutput = desiredOutput
|
||||
for layerNumber in range(len(ErrorSums)-1, -1, -1):
|
||||
ErrorSums[layerNumber][0] += self.__partialDerivative(layerNumber, 0)
|
||||
for neuronNumber in range(1, len(ErrorSums[layerNumber])):
|
||||
print("layer : " + str(layerNumber) + " neuron : " + str(neuronNumber))
|
||||
ErrorSums[layerNumber][neuronNumber] += self.__partialDerivative(layerNumber, neuronNumber)
|
||||
for i in range(len(ErrorSums)):
|
||||
for j in range(len(ErrorSums[i])):
|
||||
ErrorSums[i][j] = 1 / ErrorSums[i][j]
|
||||
self.__biases[i, j] -= learningRate * ErrorSums[i][j]
|
||||
for layerNumber in range(len(errorSums)-1, -1, -1):
|
||||
for neuronNumber in range(len(errorSums[layerNumber])):
|
||||
for weightNumber in range(len(errorSums[layerNumber][neuronNumber])):
|
||||
#print("layer : " + str(layerNumber) + " neuron : " + str(neuronNumber) + " weight : " + str(weightNumber))
|
||||
errorSums[layerNumber][neuronNumber][weightNumber] += self.__partialDerivative(layerNumber, neuronNumber, weightNumber)
|
||||
|
||||
total = 0
|
||||
|
||||
for i in range(len(errorSums)):
|
||||
for j in range(len(errorSums[i])):
|
||||
for k in range(len(errorSums[i][j])):
|
||||
errorSums[i][j][k] = errorSums[i][j][k] / len(inputs)
|
||||
total += errorSums[i][j][k]
|
||||
self.__weights[i][j][k] -= learningRate * errorSums[i][j][k]
|
||||
|
||||
print("Error : " + str(total))
|
||||
|
||||
def __Error(self, layer, neuron):
|
||||
return self.__ErrorFinalLayer(neuron) if (layer == len(self.__weights)-1) else self.__ErrorHiddenLayer(layer, neuron)
|
||||
if (self.__errors[layer][neuron] == 0 ):
|
||||
self.__errors[layer][neuron] = self.__ErrorFinalLayer(neuron) if (layer == len(self.__weights)-1) else self.__ErrorHiddenLayer(layer, neuron)
|
||||
return self.__errors[layer][neuron]
|
||||
|
||||
def __ErrorFinalLayer(self, neuron):
|
||||
print(self.activations)
|
||||
return network.__reLu(self.activations[len(self.activations)-1][neuron], True) * (self.__output[neuron] - self.__desiredOutput[neuron])
|
||||
return network.__sigmoid(self.activations[len(self.activations)-1][neuron], True) * (self.__output[neuron] - self.__desiredOutput[neuron])
|
||||
|
||||
def __ErrorHiddenLayer(self, layer, neuron):
|
||||
upperLayerLinksSum = 0
|
||||
for upperLayerNeuron in range(len(self.__weights[layer+1]-1)):
|
||||
#A comparer avec un acces direct au erreurs precalcules
|
||||
upperLayerLinksSum += self.__weights[layer+1][upperLayerNeuron][neuron] * self.__Error(layer+1, neuron)
|
||||
return network.__reLu(self.activations[layer][neuron], True) * upperLayerLinksSum
|
||||
return network.__sigmoid(self.activations[layer][neuron], True) * upperLayerLinksSum
|
||||
|
||||
def __partialDerivative(self, layer, neuron):
|
||||
return self.__Error(layer, neuron) * self.outputs[layer][neuron]
|
||||
def __partialDerivative(self, layer, neuron, weight):
|
||||
return self.__Error(layer, neuron) * self.outputs[layer-1][weight]
|
@ -6,20 +6,23 @@ random.seed()
|
||||
|
||||
myNetwork = network(1, 8, 8, 10)
|
||||
|
||||
for j in range(5):
|
||||
for j in range(3000):
|
||||
inputs = []
|
||||
desiredOutputs = []
|
||||
|
||||
for i in range(1000):
|
||||
if (j%50 == 0):
|
||||
print(j)
|
||||
|
||||
for i in range(200):
|
||||
inputs.append([random.randrange(10)])
|
||||
inputs = np.array(inputs, dtype=object)
|
||||
|
||||
for i in range(1000):
|
||||
for i in range(200):
|
||||
desiredOutputs.append([0]*10)
|
||||
desiredOutputs[i][9 - inputs[i][0]] = 1
|
||||
desiredOutputs = np.array(desiredOutputs, dtype=object)
|
||||
|
||||
myNetwork.train(inputs, desiredOutputs, 0.1)
|
||||
myNetwork.train(inputs, desiredOutputs, 0.01)
|
||||
|
||||
print(myNetwork.process(np.array([8.0], dtype=object)))
|
||||
print(myNetwork.process(np.array([7.0], dtype=object)))
|
||||
print(myNetwork.process(np.array([1.0], dtype=object)))
|
12
timeTest.py
Normal file
12
timeTest.py
Normal file
@ -0,0 +1,12 @@
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
inputs = []
|
||||
|
||||
for i in range(10000000):
|
||||
inputs.append([random.randrange(10)])
|
||||
inputs = np.array(inputs, dtype=object)
|
||||
|
||||
inputs = np.insert(inputs, 0, 1, axis=1)
|
||||
|
||||
print(inputs)
|
40
timeTest2.py
Normal file
40
timeTest2.py
Normal file
@ -0,0 +1,40 @@
|
||||
import random
|
||||
import numpy as np
|
||||
import time
|
||||
|
||||
weights = np.random.default_rng(42).random((10, 10))
|
||||
biases = np.random.default_rng(42).random(10)
|
||||
biases = np.array(biases, dtype=object)
|
||||
|
||||
time1 = time.perf_counter()
|
||||
|
||||
for k in range(1000):
|
||||
_input = []
|
||||
for i in range(10):
|
||||
_input.append(random.randrange(10))
|
||||
_input = np.array(_input, dtype=object)
|
||||
|
||||
for f in range(100):
|
||||
_input = np.matmul(_input, weights)
|
||||
_input = np.add(_input, biases)
|
||||
|
||||
time2 = time.perf_counter()
|
||||
|
||||
weights = np.random.default_rng(42).random((11, 10))
|
||||
|
||||
time3 = time.perf_counter()
|
||||
|
||||
for k in range(1000):
|
||||
_input = []
|
||||
for i in range(10):
|
||||
_input.append(random.randrange(10))
|
||||
_input = np.array(_input, dtype=object)
|
||||
|
||||
for f in range(100):
|
||||
_input = np.insert(_input, 0, 1, axis=0)
|
||||
_input = np.matmul(_input, weights)
|
||||
|
||||
time4 = time.perf_counter()
|
||||
|
||||
print("Multiplication et addition : " + str(time2-time1) + " secondes")
|
||||
print("Insertion puis multiplication : " + str(time4-time3) + " secondes")
|
Loading…
Reference in New Issue
Block a user