Table des matières[Cacher][Montrer]
Le cerveau est comparable à des réseaux de neurones. C'est l'analogie qui est généralement utilisée pour aider une personne novice en la matière à comprendre les idées derrière l'apprentissage automatique et les réseaux de neurones artificiels.
Parce qu'il y a plusieurs couches de calculs mathématiques et statistiques en coulisses, définir ces réseaux comme une fonction mathématique est une méthode plus avancée.
Ceci est destiné aux personnes qui s'intéressent réellement à l'apprentissage automatique et qui souhaitent voir comment le code du réseau neuronal Python est écrit.
Dans cet article, nous allons montrer comment construire un réseau de neurones profonds (DNN) entièrement connecté à partir de zéro dans Python 3.
Un aperçu de la structure des fichiers pour notre code de réseau neuronal Python
Il y aura trois fichiers créés ici. Le premier est le simple fichier nn.py, qui sera abordé dans "Configuration des fonctions d'assistance" et "Construire le réseau de neurones à partir de zéro".
Nous aurons également un fichier nommé mnist loader.py pour charger les données de test, comme décrit dans « Chargement des données MNIST ».
Enfin, nous aurons un fichier nommé test.py qui sera lancé dans le terminal pour tester notre réseau de neurones.
Ce fichier est décrit en détail dans "Exécution des tests".
Installation
La bibliothèque NumPy Python doit être téléchargée afin de suivre ce tutoriel. Vous pouvez accomplir cela en utilisant la commande suivante sur le terminal :
Importation de modules et configuration de la fonction Helper
Les deux seules bibliothèques dont nous avons besoin sont random et NumPy, que nous importerons immédiatement. Pour les poids initiaux de notre réseau de neurones, nous les mélangerons à l'aide de la bibliothèque aléatoire.
Afin d'accélérer nos calculs, nous utiliserons NumPy ou np (par convention, il est souvent importé en tant que np). Nos deux fonctions d'assistance seront faites après nos importations. Deux fonctions sigmoïdes : une et sigmoïde prime.
La régression logistique classera les données à l'aide de la fonction sigmoïde, tandis que la rétropropagation calculera le delta ou le gradient à l'aide de la fonction sigmoïde principale.
Création d'une classe réseau
La construction d'un réseau neuronal entièrement lié est le seul objectif de cette section. La classe réseau englobera toutes les fonctions qui viennent après. La fonction Object() { [code natif] } sera initialement créée dans notre classe réseau.
Un argument, tailles, est requis par la fonction Object() { [code natif] }. La variable tailles est une collection de valeurs numériques qui représente le nombre de nœuds d'entrée présents dans chaque couche de notre réseau de neurones.
Nous initialisons quatre propriétés dans notre méthode __init__. Les variables d'entrée, tailles, sont utilisées pour définir la liste des tailles de couche et le nombre de couches, num couches, respectivement.
La première étape consiste à attribuer au hasard les biais initiaux de notre réseau à chaque couche qui suit la couche d'entrée.
Enfin, chaque lien entre les couches d'entrée et de sortie voit ses poids générés aléatoirement. Np.Random.Randn() donne un échantillon aléatoire tiré de la distribution normale pour le contexte.
Fonction d'avance
Dans un réseau neuronal, les informations sont transmises par la fonction feedforward. Un argument, a, indiquant le vecteur d'activation courant, sera requis par cette fonction.
Cette fonction estime les activations à chaque couche en itérant sur tous les biais et poids du réseau. La réponse donnée est la prédiction, c'est-à-dire les activations de la dernière couche.
Descente de gradient en mini-lot
Le cheval de bataille de notre classe Réseau est Gradient Descent. Dans cette version, nous utilisons la descente de gradient mini-batch (stochastique), une variation modifiée de la descente de gradient.
Cela indique qu'un petit lot de points de données sera utilisé pour mettre à jour notre modèle. Quatre arguments obligatoires et un argument facultatif sont passés à cette méthode. Les quatre variables requises sont l'ensemble de données d'apprentissage, le nombre d'époques, la taille des mini-lots et le taux d'apprentissage (eta).
Les données de test sont disponibles sur demande. Nous fournirons des données de test lorsque nous évaluerons éventuellement ce réseau. Le nombre d'échantillons dans cette fonction est initialement défini sur la longueur de la liste une fois que les données d'apprentissage ont été transformées en un type de liste.
Nous appliquons également le même processus pour tester les données qui nous sont fournies. En effet, au lieu de nous être renvoyées sous forme de listes, ce sont en réalité des compressés de listes. Lorsque nous chargerons les échantillons de données MNIST plus tard, nous en apprendrons plus à ce sujet.
Si nous pouvons nous assurer que nous fournissons les deux types de données sous forme de listes, alors cette typage n'est pas nécessairement essentielle.
Une fois que nous avons les données, nous passons en revue les époques d'entraînement en boucle. Une période de formation n'est qu'un cycle de formation sur les réseaux de neurones. Nous mélangeons d'abord les données à chaque époque pour garantir le caractère aléatoire avant de créer une liste de mini-lots.
La fonction de mise à jour du mini-lot, qui est décrite ci-dessous, sera appelée pour chaque mini-lot. La précision du test sera également renvoyée si les données de test sont disponibles.
Fonction d'aide à la dérivation des coûts
Développons d'abord une fonction d'assistance appelée dérivée de coût avant de créer réellement le code de rétropropagation. Si nous commettons une erreur dans notre couche de sortie, la fonction de dérivée de coût le montrera.
Il nécessite deux entrées : le tableau des activations de sortie et les coordonnées y des valeurs de sortie anticipées.
Fonction de rétropropagation
Notre vecteur d'activation actuel, activation, ainsi que tous les autres vecteurs d'activation, activations et vecteurs z, zs, doivent tous être gardés à l'esprit. Une couche appelée couche d'entrée est activée en premier.
Nous passerons en revue chaque biais et chaque poids après les avoir mis en place. Chaque boucle consiste à calculer le vecteur z en tant que produit scalaire des poids et de l'activation, à l'ajouter à la liste des z, à recalculer l'activation et à ajouter l'activation mise à jour à la liste des activations.
Enfin, les maths. Le delta, qui est égal à l'erreur de la couche précédente multipliée par le nombre premier sigmoïde du dernier élément des vecteurs zs, est calculé avant de commencer notre passe arrière.
La dernière couche de nabla b est définie comme étant le delta, et la dernière couche de nabla w est définie comme le produit scalaire du delta et l'avant-dernière couche d'activations (transposée pour que nous puissions réellement faire le calcul) .
Nous procédons comme avant, en commençant par la deuxième couche et en terminant par la dernière, et répétons le processus après avoir terminé ces dernières couches. Les nablas sont alors restitués sous forme de tuple.
Mise à jour de la descente de gradient en mini-batch
Notre méthode SGD (descente de gradient stochastique) d'avant intègre une mise à jour par mini-lots. Puisqu'il est utilisé dans SGD mais nécessite également un backprop, j'ai débattu de l'endroit où placer cette fonction.
Finalement, j'ai fait le choix de le poster ici. Il commence par générer 0 vecteurs des nablas des biais et des poids, tout comme notre fonction backprop l'a fait.
Il nécessite le mini-batch et le taux d'apprentissage êta comme ses deux entrées. Dans le mini-lot, nous utilisons ensuite la fonction backprop pour obtenir le delta de chaque tableau nabla pour chaque entrée, x, et sortie, y. Les listes nabla sont ensuite mises à jour avec ces deltas.
Enfin, nous utilisons le taux d'apprentissage et les nablas pour mettre à jour les poids et les biais du réseau. Chaque valeur est mise à jour avec la valeur la plus récente, moins le taux d'apprentissage, multipliée par la taille du mini-lot, puis ajoutée à la valeur nabla.
Évaluer la fonction
La fonction d'évaluation est la dernière que nous devons écrire. Les données de test sont la seule entrée pour cette fonction. Dans cette fonction, nous comparons uniquement les sorties du réseau avec le résultat attendu, y. En alimentant l'entrée, x, vers l'avant, les sorties du réseau sont déterminées.
Code complet
Lorsque nous combinons tout le code, voici comment il apparaît.
Tester le réseau de neurones
Chargement des données MNIST
La Données MNIST est au format .pkl.gz, que nous allons ouvrir avec GZIP et charger avec pickle. Écrivons une méthode rapide pour charger ces données sous la forme d'un tuple de taille trois, divisé en données d'entraînement, de validation et de test.
Pour faciliter la gestion de nos données, nous allons écrire une autre fonction pour encoder le y dans un tableau de 10 éléments. Le tableau sera composé uniquement de 0, à l'exception d'un 1 qui correspond au chiffre approprié de l'image.
Nous utiliserons les données de chargement de base et une méthode d'encodage à chaud pour charger nos données dans un format lisible. Une autre fonction sera écrite pour convertir nos valeurs x en une liste de taille 784, correspondant aux 784 pixels de l'image, et nos valeurs y en leur seule forme vectorielle codée à chaud.
Ensuite, nous combinerons les valeurs x et y de sorte qu'un index corresponde à l'autre. Cela s'applique aux ensembles de données de formation, de validation et de test. Nous renvoyons ensuite les données modifiées.
Exécution de tests
Nous allons créer un nouveau fichier appelé "mnist loader" qui importera à la fois le réseau de neurones que nous avons établi précédemment (simple nn) et le chargeur d'ensemble de données MNIST avant de commencer les tests.
Dans ce fichier, tout ce que nous avons à faire est d'importer les données, de créer un réseau avec une taille de couche d'entrée de 784 et une taille de couche de sortie de 10, d'exécuter la fonction SGD du réseau sur les données d'apprentissage, puis de la tester à l'aide des données de test.
Gardez à l'esprit que pour notre liste de couches d'entrée, les nombres compris entre 784 et 10 ne font aucune différence. Nous pouvons modifier les autres couches comme bon nous semble ; seules les tailles d'entrée et de sortie sont fixes.
Trois couches ne sont pas nécessaires ; nous pourrions en utiliser quatre, cinq ou même seulement deux. Amusez-vous à l'expérimenter.
Conclusion
Ici, en utilisant Python 3, nous créons un réseau de neurones à partir de zéro. En plus des mathématiques de haut niveau, nous avons également discuté des spécificités de la mise en œuvre.
Nous avons commencé par implémenter des fonctions d'assistance. Pour que les neurones fonctionnent, les fonctions sigmoïdes et sigmoïdes premières sont cruciales. Nous avons ensuite mis en pratique la fonction feedforward, qui est le processus fondamental pour alimenter les données dans le réseau de neurones.
Ensuite, nous avons créé la fonction de descente de gradient en Python, le moteur qui pilote notre réseau de neurones. Afin de localiser les "minima locaux" et d'optimiser leurs poids et leurs biais, notre réseau de neurones utilise la descente de gradient. Nous avons créé la fonction de rétropropagation en utilisant Descente graduelle.
En fournissant des mises à jour lorsque les sorties ne correspondent pas aux étiquettes appropriées, cette fonction permet au réseau neuronal d'« apprendre ».
Enfin, nous mettons notre tout nouveau Python Réseau neuronal au test en utilisant le jeu de données MNIST. Tout a fonctionné sans problème.
Codage heureux!
Soyez sympa! Laissez un commentaire