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 numpy as np
|
||||||
|
import math
|
||||||
|
|
||||||
class network:
|
class network:
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ class network:
|
|||||||
self.__inputLayerSize = inputLayerSize
|
self.__inputLayerSize = inputLayerSize
|
||||||
oldLayerSize = inputLayerSize
|
oldLayerSize = inputLayerSize
|
||||||
for layerSize in layerSizes:
|
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
|
oldLayerSize = layerSize
|
||||||
self.__biases = [[0]*layerSize for layerSize in layerSizes]
|
self.__biases = [[0]*layerSize for layerSize in layerSizes]
|
||||||
self.__weights = np.array(self.__weights, dtype=object)
|
self.__weights = np.array(self.__weights, dtype=object)
|
||||||
@ -24,7 +25,7 @@ class network:
|
|||||||
def __sigmoid(value, derivative=False):
|
def __sigmoid(value, derivative=False):
|
||||||
if (derivative):
|
if (derivative):
|
||||||
return network.__sigmoid(value) * (1 - network.__sigmoid(value))
|
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):
|
def process(self, _input, __storeValues=False):
|
||||||
if type(_input) != np.ndarray:
|
if type(_input) != np.ndarray:
|
||||||
@ -35,61 +36,70 @@ class network:
|
|||||||
# raise TypeError("The input vector must contain floats!")
|
# raise TypeError("The input vector must contain floats!")
|
||||||
|
|
||||||
if (__storeValues):
|
if (__storeValues):
|
||||||
self.activations = np.array([])
|
self.activations = []
|
||||||
self.outputs = np.array([])
|
self.outputs = []
|
||||||
|
|
||||||
for layerWeights, bias in zip(self.__weights, self.__biases):
|
for layerWeights, bias in zip(self.__weights, self.__biases):
|
||||||
_input = np.matmul(_input, layerWeights)
|
|
||||||
|
_input = np.matmul(layerWeights, _input)
|
||||||
_input = np.add(_input, bias)
|
_input = np.add(_input, bias)
|
||||||
|
|
||||||
if (__storeValues):
|
if (__storeValues):
|
||||||
print("-------------------")
|
self.activations.append(_input.copy())
|
||||||
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)
|
|
||||||
|
|
||||||
#reLu application
|
#reLu application
|
||||||
with np.nditer(_input, op_flags=['readwrite'], flags=['refs_ok']) as layer:
|
for neuron in range(len(_input)):
|
||||||
for neuron in layer:
|
_input[neuron] = network.__sigmoid(_input[neuron])
|
||||||
neuron = network.__reLu(neuron)
|
|
||||||
|
|
||||||
#On peut comparer la performance si on recalcul plus tard
|
#On peut comparer la performance si on recalcul plus tard
|
||||||
if (__storeValues):
|
if (__storeValues):
|
||||||
self.outputs = np.append(self.outputs, _input)
|
self.outputs.append(_input.copy())
|
||||||
self.outputs[len(self.outputs)-1] = np.insert(self.outputs[len(self.outputs)-1], 0, 1)
|
|
||||||
|
self.activations = np.array(self.activations, dtype=object)
|
||||||
|
self.outputs = np.array(self.outputs, dtype=object)
|
||||||
|
|
||||||
return _input
|
return _input
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def train(self, inputs, desiredOutputs, learningRate):
|
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):
|
for _input, desiredOutput in zip(inputs, desiredOutputs):
|
||||||
self.__output = self.process(_input, True)
|
self.__output = self.process(_input, True)
|
||||||
self.__desiredOutput = desiredOutput
|
self.__desiredOutput = desiredOutput
|
||||||
for layerNumber in range(len(ErrorSums)-1, -1, -1):
|
for layerNumber in range(len(errorSums)-1, -1, -1):
|
||||||
ErrorSums[layerNumber][0] += self.__partialDerivative(layerNumber, 0)
|
for neuronNumber in range(len(errorSums[layerNumber])):
|
||||||
for neuronNumber in range(1, len(ErrorSums[layerNumber])):
|
for weightNumber in range(len(errorSums[layerNumber][neuronNumber])):
|
||||||
print("layer : " + str(layerNumber) + " neuron : " + str(neuronNumber))
|
#print("layer : " + str(layerNumber) + " neuron : " + str(neuronNumber) + " weight : " + str(weightNumber))
|
||||||
ErrorSums[layerNumber][neuronNumber] += self.__partialDerivative(layerNumber, neuronNumber)
|
errorSums[layerNumber][neuronNumber][weightNumber] += self.__partialDerivative(layerNumber, neuronNumber, weightNumber)
|
||||||
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]
|
|
||||||
|
|
||||||
|
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):
|
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):
|
def __ErrorFinalLayer(self, neuron):
|
||||||
print(self.activations)
|
return network.__sigmoid(self.activations[len(self.activations)-1][neuron], True) * (self.__output[neuron] - self.__desiredOutput[neuron])
|
||||||
return network.__reLu(self.activations[len(self.activations)-1][neuron], True) * (self.__output[neuron] - self.__desiredOutput[neuron])
|
|
||||||
|
|
||||||
def __ErrorHiddenLayer(self, layer, neuron):
|
def __ErrorHiddenLayer(self, layer, neuron):
|
||||||
upperLayerLinksSum = 0
|
upperLayerLinksSum = 0
|
||||||
for upperLayerNeuron in range(len(self.__weights[layer+1]-1)):
|
for upperLayerNeuron in range(len(self.__weights[layer+1]-1)):
|
||||||
#A comparer avec un acces direct au erreurs precalcules
|
#A comparer avec un acces direct au erreurs precalcules
|
||||||
upperLayerLinksSum += self.__weights[layer+1][upperLayerNeuron][neuron] * self.__Error(layer+1, neuron)
|
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):
|
def __partialDerivative(self, layer, neuron, weight):
|
||||||
return self.__Error(layer, neuron) * self.outputs[layer][neuron]
|
return self.__Error(layer, neuron) * self.outputs[layer-1][weight]
|
@ -6,20 +6,23 @@ random.seed()
|
|||||||
|
|
||||||
myNetwork = network(1, 8, 8, 10)
|
myNetwork = network(1, 8, 8, 10)
|
||||||
|
|
||||||
for j in range(5):
|
for j in range(3000):
|
||||||
inputs = []
|
inputs = []
|
||||||
desiredOutputs = []
|
desiredOutputs = []
|
||||||
|
|
||||||
for i in range(1000):
|
if (j%50 == 0):
|
||||||
|
print(j)
|
||||||
|
|
||||||
|
for i in range(200):
|
||||||
inputs.append([random.randrange(10)])
|
inputs.append([random.randrange(10)])
|
||||||
inputs = np.array(inputs, dtype=object)
|
inputs = np.array(inputs, dtype=object)
|
||||||
|
|
||||||
for i in range(1000):
|
for i in range(200):
|
||||||
desiredOutputs.append([0]*10)
|
desiredOutputs.append([0]*10)
|
||||||
desiredOutputs[i][9 - inputs[i][0]] = 1
|
desiredOutputs[i][9 - inputs[i][0]] = 1
|
||||||
desiredOutputs = np.array(desiredOutputs, dtype=object)
|
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([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