Ces dernières années, il y a eu une résurgence dans le domaine de l'intelligence artificielle. Il s'est répandu au-delà du monde académique, avec de grandes figures telles que Google , Microsoft et Facebook , qui ont créé leurs propres équipes de recherche, obtenant des acquisitions .
On fait remarquer que cela peut être attribué à la grande quantité de données brutes générées par les utilisateurs des réseaux sociaux, dont une grande partie doit être analysée, ainsi qu'à la puissance de calcul précaire disponible via GPGPU .
Mais au-delà de ces phénomènes, cette résurgence a été en grande partie tirée par une nouvelle tendance en IA, en particulier dans le apprentissage automatique , connu sous le nom de 'deep learning'. Dans ce didacticiel, je vais vous présenter les concepts clés et les algorithmes du deep learning, en commençant par l'unité de composition la plus simple jusqu'aux concepts d'apprentissage automatique en Java.
( Pour une description complète: Je suis également l'auteur d'une bibliothèque Java Deep Learning, disponible ici , et les exemples de cet article sont implémentés à l'aide de la bibliothèque ci-dessus. Si vous l'aimez, vous pouvez la soutenir en lui attribuant une étoile sur GitHub, ce dont je vous serais très reconnaissant. Les instructions d'utilisation sont disponibles sur page d'accueil .)
Au cas où vous ne seriez pas familier, consultez cette introduction à apprentissage automatique :
La procédure générale est la suivante:
Nous avons un algorithme qui reçoit une poignée d'exemples étiquetés; par exemple, 10 images de chiens avec le tag 1 ('chien') et 10 images d'autres choses taguées 0 ('Pas de chien') - Notez que nous utilisons principalement pour ce message, la classification supervisé Oui binaire .
L'algorithme «apprend» à identifier des images de chiens et lorsqu'il reçoit une nouvelle image, il s'attend à produire l'étiquette correcte (1 s'il s'agit d'une image d'un chien, 0 sinon).
Cette configuration est très générale: les données peuvent être des symptômes et des maladies sur les étiquettes, ou vos données peuvent être des images de caractères manuscrits et les étiquettes les caractères qu'ils représentent.
L'un des premiers algorithmes d'apprentissage supervisé est le perceptron; un élément de base des réseaux de neurones.
Supposons que nous ayons des points n dans le plan, avec les étiquettes «0» et «1». Ils nous donnent un nouveau point et nous voulons deviner leur étiquette (c'est similaire au scénario «chien» et «pas de chien» ci-dessus). Comment faisons-nous ça?
Une bonne approche pourrait être de regarder le voisin le plus proche et de renvoyer la balise à partir de ce point. Mais une façon un peu plus intelligente de faire les choses serait de choisir une ligne qui sépare mieux les données étiquetées et de l'utiliser comme classificateur.
Dans ce cas, chaque élément de données d'entrée est représenté par un vecteur X = (x_1, x_2) et notre fonction serait quelque chose comme '' 0 'si elle est en dessous de la ligne,' 1 'si elle est au-dessus'.
Pour représenter cela mathématiquement, laissez notre séparateur être défini par un vecteur de poids w et un biais de décalage vertical b. Ainsi, notre fonction combinerait les entrées et les poids avec une fonction de transfert de somme pondérée:
Le résultat de cette fonction de transfert serait ensuite transmis à une fonction d'activation pour produire une étiquette. Dans l'exemple ci-dessus, notre fonction de déclenchement était un seuil de coupure (par exemple, 1 s'il est supérieur à une certaine valeur):
L'entraînement du perceptron consiste à alimenter plusieurs échantillons d'apprentissage et à calculer la sortie pour chacun d'eux. Après chaque échantillon, les poids dans sont ajustés de manière à minimiser les erreur de sortie , défini comme la différence entre la sortie voulu (objectif) et le réel . Il existe d'autres fonctions d'erreur, telles que erreur quadratique moyenne , mais le principe de formation de base reste le même.
L'approche perceptron simple de l'apprentissage profond a un inconvénient majeur: vous ne pouvez qu'apprendre fonctions linéairement séparables . Quelle est l'importance de cet inconvénient? Prenez XOR, une fonction relativement simple, et vous remarquerez qu'elle ne peut pas être classée par un séparateur linéaire (notez l'échec de la tentative, ci-dessous):
comment fonctionne le bitcoin pour les nuls
Pour faire face à ce problème, nous devrons utiliser un perceptron multicouche, également appelé réseau de neurones feedforward: en effet, nous allons composer un grand nombre de ces perceptrons pour créer un mécanisme d'apprentissage plus puissant.
Un réseau de neurones est en fait une composition de perceptrons connectés de différentes manières, et fonctionnant avec différentes fonctions d'activation.
Pour commencer, examinons le réseau de neurones feedforward, qui possède les propriétés suivantes:
Et si chacun de nos perceptrons n'était autorisé à utiliser qu'une fonction d'activation linéaire? Ainsi, la sortie finale de notre réseau sera toujours une fonction linéaire des entrées, simplement équipée d'une tonne de poids différents collectés via le réseau. En d'autres termes, une composition linéaire d'un groupe de fonctions linéaires n'est encore qu'une fonction linéaire. Si nous nous limitons aux fonctions d'activation linéaires, alors le réseau de neurones à anticipation n'est pas plus puissant que le perceptron, quel que soit le nombre de couches dont il dispose.
Une composition linéaire d'un ensemble de fonctions linéaires n'est encore qu'une fonction linéaire, de sorte que la plupart des réseaux de neurones utilisent des fonctions d'activation non linéaires.Pour cette raison, la plupart des réseaux de neurones utilisent des fonctions d'activation non linéaires telles que la logistique , de poisson , binaire ou redresseur . Sans eux, le réseau ne peut apprendre que des fonctions qui sont des combinaisons linéaire de vos entrées .
L'algorithme d'apprentissage en profondeur le plus courant pour la formation supervisée de perceptrons multicouches est connu sous le nom de propagation inverse. La procédure de base:
L'erreur de sortie est calculée, généralement l'erreur quadratique moyenne:
Où t est la valeur cible et Oui c'est la sortie réelle du réseau. D'autres calculs d'erreur sont également acceptables, mais le MSE est une bonne option.
Les erreurs de réseau sont réduites à l'aide d'une méthode appelée descente de gradient stochastique .
La descente de gradient est universelle, mais dans le cas des réseaux neuronaux, ce serait un graphique de l'erreur d'apprentissage en fonction des paramètres d'entrée. La valeur optimale pour chaque poids est celle dans laquelle l'erreur atteint un minimum global . Pendant la phase de formation, les poids sont mis à jour par petites étapes (après chaque échantillon de formation ou un mini-groupe de plusieurs échantillons) afin qu'ils essaient toujours d'atteindre le minimum global, mais ce n'est plus une tâche facile, plus souvent. se terminent par des creux locaux, comme celui vu à droite. Par exemple, si le poids a une valeur de 0,6, il doit être remplacé par 0,4.
Ce chiffre représente le cas le plus simple, celui dans lequel l'erreur dépend d'un seul paramètre. Cependant, l'erreur réseau dépend de chaque La fonction de pondération et d'erreur du réseau est beaucoup plus complexe.
Heureusement, la propagation vers l'arrière fournit une méthode pour mettre à jour chaque poids entre deux neurones, par rapport à l'erreur de sortie. La dérivation elle-même est assez compliquée, mais la mise à jour du poids pour un certain nœud a la forme (simple) suivante:
Où EST est l'erreur de sortie, et Wi est le poids de l'entrée je au neurone.
En substance, le but est de se déplacer dans le sens du gradient par rapport au poids je . Le terme clé est bien sûr la dérivée de l'erreur, qui n'est pas toujours facile à calculer: comment trouver cette dérivée pour un poids aléatoire d'un nœud caché aléatoire au milieu d'un grand réseau?
La réponse: grâce à la propagation vers l'arrière. Les erreurs sont d'abord calculées dans les unités de sortie, où la formule est assez simple (basée sur la différence entre la cible et les valeurs par défaut), puis propagées à travers le réseau de manière intelligente, ce qui nous permet de mettre à jour de manière efficace obtenir nos poids pendant l'entraînement et (espérons-le) atteindre un minimum.
La couche cachée présente un intérêt particulier. Pour lui théorème d'approximation universelle , un réseau à couche cachée unique avec un nombre fini de neurones peut être formé pour approcher une fonction aléatoire arbitraire. En d'autres termes, une seule couche cachée est suffisamment puissante pour apprendre n'importe quelle fonction. Cela dit, nous apprenons souvent mieux dans la pratique avec plusieurs couches cachées (c'est-à-dire des réseaux plus profonds).
La couche masquée est l'endroit où le réseau stocke la représentation abstraite interne des données d'apprentissage.La couche cachée est l'endroit où le réseau stocke la représentation abstraite interne des données d'entraînement, de la même manière qu'un cerveau humain (analogie très simplifiée) a une représentation interne du monde réel. À l'avenir dans le didacticiel, nous allons examiner différentes façons de jouer avec le calque caché.
Vous pouvez voir un simple réseau (couche 4-2-3) de feedforward neuronal qui classe l'ensemble de données IRIS , implémenté en Java ici , à travers la méthode testMLPSigmoidBP . L'ensemble de données contient trois classes de plantes d'iris avec des caractéristiques telles que la longueur des sépales, la longueur des pétales, etc. 50 échantillons par classe sont fournis au réseau. Les caractéristiques dépendent des unités d'entrée, tandis que chaque unité de sortie correspond à une seule classe dans l'ensemble de données: '1/0/0' indique que la plante est de classe Setosa, '0/1/0' indique versicolor, et ' 0/0/1 'indique Virginica. L'erreur de classification est 2/150 (c'est-à-dire qu'elle ne classe pas correctement 2 échantillons sur 150).
comment fonctionne ruby on rails
Un réseau de neurones peut avoir plus d'une couche cachée: dans ce cas, les couches supérieures «construisent» de nouvelles abstractions au-dessus des couches précédentes. Et comme nous l'avons déjà mentionné, vous pouvez souvent mieux apprendre sur le tas avec de plus grands réseaux.
Cependant, augmenter le nombre de couches cachées conduit à deux problèmes connus:
processus de levée de fonds de private equity
Disparition du dégradé : À mesure que nous ajoutons de plus en plus de couches cachées, la propagation vers l'arrière devient de moins en moins utile pour transmettre des informations aux couches inférieures. En effet, à mesure que l'information est à nouveau transmise, les gradients commencent à disparaître et deviennent plus petits par rapport aux poids des réseaux.
Sur-ajustement : C'est peut-être le problème central de l'apprentissage automatique. En termes simples, le surajustement décrit le phénomène d'ajustement des données d'entraînement de trop près, peut-être en supposant qu'il est très complexe. Dans un tel cas, l'étudiant termine très bien l'assemblage des données de formation mais se comportera très mal dans des exemples réels.
Examinons quelques algorithmes d'apprentissage en profondeur pour répondre à ces questions.
La plupart des cours d'introduction à l'apprentissage automatique ont tendance à se terminer par des réseaux de neurones à action directe. Mais l'espace des réseaux possibles est beaucoup plus riche, alors continuons.
Un auto-encodeur est généralement un réseau neuronal à anticipation, qui vise à apprendre une représentation (encodage) compressée et distribuée d'un ensemble de données.
Conceptuellement, le réseau est capable de «recréer» l'entrée, c'est-à-dire que l'entrée et les données cibles sont les mêmes. En d'autres termes: vous essayez d'utiliser la même chose que la sortie et l'entrée, mais en quelque sorte compressé. C'est une approche déroutante, alors regardons un exemple.
Supposons que les données d'entraînement se composent d'images en niveaux de gris 28x28 et que la valeur de chaque pixel est définie sur un neurone de couche d'entrée (c'est-à-dire que la couche d'entrée aura 784 neurones). Ensuite, la couche de sortie aurait le même nombre d'unités (784) que la couche d'entrée et la valeur cible pour chaque unité de sortie serait la valeur d'échelle de gris d'un pixel dans l'image.
L'intuition derrière cette architecture est que le réseau n'apprendra pas un «mappage» entre les données d'apprentissage et ses étiquettes, mais il apprendra le structure interne et les caractéristiques des données elles-mêmes. (Pour cette raison, la couche cachée est également appelée détecteur de caractéristiques .) En général, le nombre d'unités cachées est plus petit que les couches d'entrée / sortie, ce qui oblige le réseau à n'apprendre que les caractéristiques les plus importantes et permet de réduire la dimensionnalité.
Nous voulons quelques petits nœuds au milieu pour apprendre les données à un niveau conceptuel, produisant une représentation compacte.En effet, nous voulons que quelques petits nœuds au milieu apprennent vraiment les données à un niveau conceptuel, produisant une représentation compacte qui capture en quelque sorte les caractéristiques fondamentales de notre entrée.
Pour démontrer encore plus les auto-encodeurs, nous allons voir une autre application. Dans ce cas, nous allons utiliser un ensemble de données simple, constitué de symptômes de grippe (crédit à cette entrée dans le Blog de l'idée). Si vous êtes intéressé, le code de cet exemple se trouve dans le testAEBackpropagation, méthode .
Voici comment l'ensemble de données se décompose:
Nous allons considérer qu'un patient est malade. Lorsqu'il ou elle présente au moins deux des trois premières caractéristiques, et en bonne santé s'il en a au moins deux des trois dernières (avec des tie-breaks rompus en faveur de patients sains), par exemple:
Nous allons former un auto-encodeur (en se propageant) avec six unités d'entrée et six unités de sortie, mais seulement deux unités cachées .
Après plusieurs centaines d'itérations, on observe que lorsque chacun des échantillons «malades» est présenté au réseau d'apprentissage automatique, l'une des deux unités cachées (la même unité pour chaque échantillon «malade») présente toujours une valeur de déclenchement supérieure à la autre. Au contraire, lorsqu'un échantillon «sain» est présenté, l'autre unité cachée a une activation plus élevée.
Essentiellement, nos deux unités cachées ont appris une représentation compacte de l'ensemble de données sur les symptômes de la grippe. Pour voir comment cela se rapporte à l'apprentissage, nous revenons au problème du surajustement. En entraînant notre réseau à apprendre une représentation compacte des données, nous privilégions une représentation plus simple plutôt qu'une hypothèse très complexe qui suradapte les données d'apprentissage.
D'une certaine manière, en privilégiant ces représentations plus simples, nous essayons d'apprendre les données dans un sens plus vrai.
La prochaine étape logique consiste à examiner Boltzmann restreint (MBR) , ongle réseau neuronal génératif qui peut apprendre une distribution de probabilité sur son propre ensemble d'entrées.
Ces mécanismes sont composés d'une couche de biais cachée et visible (biais). Contrairement aux réseaux à anticipation, les connexions entre les couches visibles et cachées sont non dirigées (les valeurs peuvent se propager dans les directions visible-cachée et cachée-visible) et entièrement connectées (chaque unité d'une couche est connectée à chaque unité dans le couche suivante, si nous permettons à n'importe quelle unité de n'importe quelle couche de se connecter à n'importe quelle autre couche, alors nous aurions un Boltzmann (au lieu d'un machine Boltzmann restreinte ).
Le standard MBR a des unités binaires et visibles cachées: c'est-à-dire que l'activation de l'unité est 0 ou 1 sous un Distribution de Bernoulli , mais il existe des variantes avec d'autres non-linéarités .
Alors que les chercheurs connaissent les MBR depuis un certain temps, l'introduction récente de l'algorithme d'entraînement non supervisé du divergence contrastive , a un intérêt renouvelé.
L'algorithme de divergence contrastive en une étape (CD-1) fonctionne comme ceci:
Mise à jour du poids :
Où à est le taux d'apprentissage et v , v » , h , h » , Y dans ce sont des vecteurs.
L'intuition derrière l'algorithme est que la phase positive ( h Dadaïste v ) reflète la représentation interne du réseau de données du Vie réelle . Pendant ce temps, la phase négative représente une tentative de recréer les données, sur la base de cette représentation interne ( v » Dadaïste h ). L'objectif principal est que les données générées soient aussi proches que possible de celles de la vie réelle et cela se reflète dans la formule de mise à jour du poids.
comment vérifier les fuites de mémoire
En d'autres termes, le réseau a une perception de la façon dont les données d'entrée peuvent être représentées, il essaie donc de reproduire les données sur la base de cette perception. Si votre lecture n'est pas assez proche de la réalité, effectuez un ajustement et réessayez.
Pour démontrer la divergence contrastive, nous utiliserons le même ensemble de données de symptômes que nous avons utilisé précédemment. Le réseau de test est un MBR avec six lecteurs visibles et deux lecteurs cachés. Nous allons former le réseau, en utilisant la divergence contrastive avec les symptômes v soumis à la couche visible. Au cours des tests, les symptômes sont renvoyés à la couche visible; puis les données sont propagées vers la couche cachée. Les lecteurs cachés représentent l'état malade / sain, une architecture très similaire à l'autoencoder (propagation des données de la couche visible à la couche cachée).
Après plusieurs centaines d'itérations, on observe le même résultat qu'avec les auto-encodeurs: l'une des unités cachées a une valeur d'activation plus élevée lorsque l'un des échantillons «malades» est présenté, tandis que l'autre est toujours plus active pour les échantillons «sains». .
Vous pouvez voir cet exemple en action dans la méthode testContrastiveDivergence .
Nous avons maintenant montré que les couches cachées des auto-encodeurs et des MBR agissent comme des détecteurs de caractéristiques efficaces; mais il est rare que nous puissions utiliser ces fonctions directement. En fait, l'ensemble de données ci-dessus est plus une exception qu'une règle. Au lieu de cela, nous devons déterminer comment utiliser ces fonctionnalités détectées, indirectement.
Par chance, cela a été découvert que ces structures peuvent être empilé former des réseaux Profond . Ces réseaux peuvent être entraînés avec gourmandise, une couche à la fois, pour aider à surmonter la disparition des gradients et les problèmes de surapprentissage associé à la propagation arrière classique.
Les structures résultantes sont souvent assez puissantes, produisant des résultats impressionnants. Prenons, par exemple, le célèbre Papier «chat» de Google, dans lequel ils utilisent une classe spéciale d'autoencodeurs profonds pour 'apprendre' la détection du visage humain et des chats, sur la base de données non marqué.
Regardons de plus près.
Comme son nom l'indique, ce réseau se compose de plusieurs auto-encodeurs empilés.
La couche cachée de l'autoencoder t agit comme une couche d'entrée pour l'autoencodeur t + 1 . La couche d'entrée du premier autoencodeur est la couche d'entrée pour l'ensemble du réseau. La procédure de formation gourmande par couche fonctionne comme ceci:
Les auto-encodeurs empilés essaient donc de fournir une méthode de pré-formation efficace pour initialiser les poids d'un réseau, vous laissant avec un perceptron multicouche complexe, prêt à être entraîné (ou à faire réglage fin ).
Comme pour les auto-encodeurs, nous pouvons également empiler des machines Boltzmann, pour créer une classe appelée réseaux de croyances profondes (DBN) .
Dans ce cas, la couche cachée du MBR t agit comme une couche visible de MBR t + 1 . La couche d'entrée du premier MBR est la couche d'entrée pour tout le réseau, et la couche gourmande de pré-formation fonctionne comme ceci:
Cette procédure est similaire aux auto-encodeurs empilés, mais les auto-encodeurs sont remplacés par MBR et la propagation vers l'arrière est remplacée par l'algorithme de divergence contrastive.
( Remarque: Pour plus d'informations sur la création et la formation d'autoencodeurs empilés ou de réseaux de croyances profondes, consultez l'exemple de code ici . )
En tant qu'architecture finale d'apprentissage profond, nous allons nous pencher sur les réseaux convolutifs, une classe particulièrement intéressante et particulière de réseaux feedforward, très bien adaptés à la reconnaissance d'images.
Image via DeepLearning.net
Avant d'examiner la structure réelle des réseaux convolutifs, nous allons d'abord définir un filtre image ou une région carrée avec les poids associés. Un filtre est appliqué sur toute une image d'entrée et vous appliquerez souvent plusieurs filtres. Par exemple, vous pouvez appliquer quatre filtres 6x6 à une image d'entrée donnée. Ensuite, le pixel de sortie avec 1,1 coordonnées est la somme pondérée d'un carré de pixels d'entrée 6x6, avec le coin supérieur gauche de 1,1 et les poids de filtre (qui est également un carré 6x6). Le pixel de sortie de 2,1 est le résultat du carré d'entrée, avec le coin supérieur gauche de 2,1 et ainsi de suite.
Après examen, ces réseaux sont définis par les propriétés suivantes:
Plusieurs exemples de réseaux convolutifs entraînés (propagés vers l'arrière) peuvent être vus dans l'ensemble de données MNIST (images en niveaux de gris de lettres manuscrites) ici , spécifiquement dans les méthodes testLeNet * (Je recommanderais testLeNetTiny2 car il atteint un faible taux d'erreur d'environ 2% dans un laps de temps relativement court). Il y a aussi un bel affichage JavaScript d'un réseau similaire ici .
Maintenant que nous avons passé en revue les variantes de réseau de neurones les plus courantes, je voudrais écrire un peu sur les défis posés lors de l'exécution de ces structures d'apprentissage en profondeur.
De manière générale, mon objectif en créant un bibliothèque d'apprentissage en profondeur était (et est toujours) de construire un cadre basé sur un réseau de neurones, qui répondrait aux critères suivants:
Pour répondre à ces exigences, j'ai adopté une approche à plusieurs niveaux (ou modulaire) de la conception de logiciels.
Commençons par les bases:
Cette structure est suffisamment agile pour être utilisée pour les réseaux classiques à feedforward, ainsi que pour MBR et des architectures plus complexes telles que ImageNet .
dans quel code Windows est-il écrit
Cela permet également à une couche de faire partie de plus d'un réseau. Par exemple, les calques d'un réseau de croyances profondes ce sont également des couches dans leurs MBR correspondants.
De plus, cette architecture permet à un DBN d'être considéré comme une liste de MBR empilés pendant la phase de pré-formation, et comme un réseau anticipé pendant la phase de réglage fin, ce qui est intuitivement agréable et pratique en termes de programmation.
Le module suivant gère la propagation des données sur le réseau, un processus en deux étapes:
Comme je l'ai mentionné plus tôt, l'une des raisons pour lesquelles les réseaux de neurones ont fait une résurgence ces dernières années est que leurs méthodes d'entraînement sont très propices au parallélisme, ce qui permet d'accélérer considérablement l'entraînement, avec l'utilisation d'un GPGPU. Dans ce cas, j'ai décidé de travailler avec la bibliothèque Aparapi pour ajouter le support GPU.
Aparapi impose des restrictions importantes sur les calculateurs de connexion:
Ainsi, la plupart des données (poids, matrices d'entrée et de sortie) sont stockées dans des instances Matrix, qui utilisent des matrices flottantes unidimensionnelles, en interne. Toutes les calculatrices de connexion Aparapi utilisent soit AparapiWeightedSum (pour les couches entièrement connectées et les fonctions d'entrée de somme pondérée), AparapiSubsampling2D (pour les couches de sous-échantillonnage), ou AparapiConv2D (pour les couches convolutives). Certaines de ces limitations peuvent être surmontées avec l'introduction du Architecture de système hétérogène (HSA) . Aparapi permet également d'exécuter le même code sur le CPU et le GPU.
La module de formation implémente divers algorithmes de formation. Il s'appuie sur les deux modules précédents. Par exemple, RetourPropagationFormateur (tous les entraîneurs utilisent le Entraîneur de la classe de base) utilise le calculateur de couche à anticipation pour la phase d'anticipation et un calculateur de couche de largeur spécial, pour propager l'erreur et mettre à jour les poids.
Mon dernier travail prend en charge Java 8 et quelques autres améliorations, qui sont disponibles dans cette branche et seront bientôt fusionnées avec prof .
L'objectif de ce didacticiel Java Deep Learning était de vous donner une brève introduction au domaine des algorithmes d'apprentissage profond, en commençant par l'unité de composition la plus élémentaire (le perceptron) et en vous frayant un chemin à travers diverses architectures populaires et efficaces, telles que le of machine Boltzmann restreinte.
Les idées derrière les réseaux de neurones existent depuis longtemps; Mais aujourd'hui, vous ne pouvez pas entrer dans la communauté d'apprentissage automatique sans avoir entendu parler des sites Web profonds ou d'une autre opinion sur l'apprentissage profond. La mode ne doit pas être confondue avec la justification, mais avec les progrès de l'informatique GPGPU et les progrès impressionnants réalisés par des chercheurs tels que Geoffrey Hinton, Yoshua Bengio, Yann LeCun et Andrew Ng, le domaine est certainement très prometteur. Il n'y a pas de meilleur moment pour se familiariser et s'impliquer comme aujourd'hui.
Si vous souhaitez en savoir plus, j'ai trouvé les ressources très utiles suivantes au cours de mon travail: