Ces dernières années, il y a eu une résurgence dans le domaine de l'intelligence artificielle. Il s’étend au-delà du monde académique avec des acteurs majeurs comme Google , Microsoft et Facebook créer leurs propres équipes de recherche et créer des acquisitions .
Cela peut être attribué en partie à l'abondance de données brutes générées par les utilisateurs des réseaux sociaux, dont une grande partie doit être analysée, à la montée des solutions de science des données , ainsi qu'à la puissance de calcul bon marché disponible via GPGPU .
Mais au-delà de ces phénomènes, cette résurgence a été alimentée en grande partie par une nouvelle tendance de l'IA, notamment en apprentissage automatique , connu sous le nom de «Deep Learning». Dans ce didacticiel, je vais vous présenter les concepts et algorithmes clés du deep learning, en commençant par l'unité de composition la plus simple et en développant les concepts de machine learning en Java.
lorsque vous utilisez un élément méta avec des requêtes multimédias, vous devez toujours
(Pour information 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 tu aimes ça, vous pouvez le soutenir en lui attribuant une étoile sur GitHub , pour lequel je serais reconnaissant. Les instructions d'utilisation sont disponibles sur le page d'accueil .)
Au cas où vous ne seriez pas familier, regardez ceci introduction à l'apprentissage automatique :
La procédure générale est la suivante:
Ce paramètre est incroyablement général: vos données peuvent être des symptômes et vos étiquettes de maladies; ou vos données peuvent être des images de caractères manuscrits et vos étiquettes les caractères réels qu'ils représentent.
L'un des premiers algorithmes d'entraînement supervisé est celui du perceptron, un élément de base du réseau neuronal.
Dis que nous avons n points dans le plan, étiquetés «0» et «1». On nous donne un nouveau point et nous voulons deviner son étiquette (cela s'apparente au scénario 'Chien' et 'Pas chien' ci-dessus). Comment faisons-nous ça?
Une approche pourrait consister à regarder le voisin le plus proche et à renvoyer l'étiquette de ce point. Mais une façon légèrement plus intelligente de procéder serait de choisir une ligne qui sépare le mieux les données étiquetées et de l'utiliser comme classificateur.
Dans ce cas, chaque élément de données d'entrée serait représenté comme un vecteur X = ( x_1, x_2 ) et notre fonction serait quelque chose comme '' 0 'si en dessous de la ligne,' 1 'si au-dessus'.
Pour représenter cela mathématiquement, laissez notre séparateur être défini par un vecteur de poids dans et un décalage vertical (ou biais) b . Ensuite, 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 alors introduit dans une fonction d'activation pour produire un marquage. Dans l'exemple ci-dessus, notre fonction d'activation était un seuil de coupure (par exemple, 1 si supérieur à une certaine valeur):
L'entraînement du perceptron consiste à lui fournir 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 le voulu (cible) et le actuel les sorties. Il existe d'autres fonctions d'erreur, comme erreur quadratique moyenne , mais le principe de base de la formation reste le même.
L'approche à perceptron unique de l'apprentissage profond a un inconvénient majeur: elle ne peut qu'apprendre fonctions linéairement séparables . Quelle est la gravité de cet inconvénient? Prenez XOR, une fonction relativement simple, et notez qu'elle ne peut pas être classée par un séparateur linéaire (remarquez l'échec de la tentative, ci-dessous):
Pour résoudre ce problème, nous devrons utiliser un perceptron multicouche, également connu sous le nom de réseau de neurones à feedforward: en fait, nous allons composer un groupe de ces perceptrons ensemble pour créer un mécanisme d'apprentissage plus puissant.
Un réseau de neurones n'est en réalité qu'une composition de perceptrons, connectés de différentes manières et fonctionnant sur différentes fonctions d'activation.
Pour commencer, nous allons examiner le réseau de neurones feedforward, qui possède les propriétés suivantes:
Et si chacun de nos perceptrons était autorisé à utiliser uniquement une fonction d'activation linéaire? Ensuite, la sortie finale de notre réseau sera encore être une fonction linéaire des entrées, juste ajustée avec une tonne de poids différents qu'elle est collectée dans tout le réseau. En d'autres termes, une composition linéaire d'un ensemble de fonctions linéaires n'est encore qu'une fonction linéaire. Si nous sommes limités aux fonctions d’activation linéaires, alors le réseau de neurones à feedforward 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 comme la logistique , de poisson , binaire ou redresseur . Sans eux, le réseau ne peut apprendre que des fonctions combinaisons linéaires de ses entrées .
L'algorithme d'apprentissage en profondeur le plus courant pour l'entraînement supervisé des perceptrons multicouches est connu sous le nom de rétropropagation. 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 est la sortie réelle du réseau. D'autres calculs d'erreur sont également acceptables, mais le MSE est un bon choix.
L'erreur de réseau est minimisée à 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 à 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-lot de plusieurs échantillons) de telle manière qu'ils essaient toujours d'atteindre le minimum global - mais ce n'est pas une tâche facile, car vous aboutissent souvent à des minima locaux, comme celui de droite. Par exemple, si le poids a une valeur de 0,6, il doit être changé vers 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 le poids du réseau et la fonction d'erreur sont beaucoup, beaucoup plus complexes.
Heureusement, la rétropropagation 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 nœud donné a la forme (simple) suivante:
Où EST est l'erreur de sortie, et Wi est le poids de l'entrée je au neurone.
Essentiellement, 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: par rétropropagation. Les erreurs sont d'abord calculées au niveau des unités de sortie où la formule est assez simple (basée sur la différence entre la cible et les valeurs prédites), puis propagées à travers le réseau de manière intelligente, nous permettant de mettre à jour efficacement nos poids pendant l'entraînement et (espérons-le) atteindre un minimum.
La couche cachée présente un intérêt particulier. Par le théorème d'approximation universelle , un réseau de couche cachée unique avec un nombre fini de neurones peut être formé pour approcher une fonction arbitrairement aléatoire. En d'autres termes, une seule couche cachée est suffisamment puissante pour apprendre tout fonction. Cela dit, nous apprenons souvent mieux dans la pratique avec plusieurs couches cachées (c'est-à-dire des filets plus profonds).
La couche masquée est l'endroit où le réseau stocke sa représentation abstraite interne des données d'entraînement.La couche cachée est l'endroit où le réseau stocke sa représentation abstraite interne des données d'entraînement, de la même manière qu'un cerveau humain (analogie grandement simplifiée) a une représentation interne du monde réel. Dans la suite du didacticiel, nous examinerons différentes façons de jouer avec le calque masqué.
Vous pouvez voir un simple réseau de neurones à action directe (couche 4-2-3) qui classe les IRIS ensemble de données implémenté en Java Ici à travers le testMLPSigmoidBP méthode. 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. Le réseau est fourni 50 échantillons par classe. Les entités sont fixées aux unités d'entrée, tandis que chaque unité de sortie correspond à une seule classe de l'ensemble de données: «1/0/0» indique que la plante est de classe Setosa, «0/1/0» indique Versicolour et « 0/0/1 ”indique Virginica). L'erreur de classification est de 2/150 (c'est-à-dire qu'elle classe mal 2 échantillons sur 150).
Un réseau neuronal 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 mentionné précédemment, vous pouvez souvent mieux apprendre dans la pratique avec de plus grands réseaux.
Cependant, l'augmentation du nombre de couches masquées entraîne deux problèmes connus:
Examinons quelques algorithmes d'apprentissage en profondeur pour résoudre ces problèmes.
La plupart des cours d'introduction à l'apprentissage automatique ont tendance à s'arrêter avec des réseaux de neurones à action directe. Mais l’espace des réseaux possibles est beaucoup plus riche - continuons donc.
Un auto-encodeur est généralement un réseau de neurones à rétroaction qui vise à apprendre une représentation (encodage) compressée et distribuée d'un ensemble de données.
Conceptuellement, le réseau est formé pour «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 de produire la même chose que vous avez entrée, mais compressée d'une manière ou d'une autre. C'est une approche déroutante, alors regardons un exemple.
Supposons que les données d'apprentissage se composent d'images en niveaux de gris 28x28 et que la valeur de chaque pixel est fixée à un neurone de la 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 de l'image.
L'intuition derrière cette architecture est que le réseau n'apprendra pas de «mappage» entre les données d'apprentissage et ses étiquettes, mais apprendra plutôt 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 .) Habituellement, le nombre d'unités cachées est plus petit que les couches d'entrée / sortie, ce qui oblige le réseau à apprendre uniquement les caractéristiques les plus importantes et permet une réduction de 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 d'une certaine manière capture les caractéristiques de base de notre entrée.
Pour une démonstration plus approfondie des auto-encodeurs, examinons une autre application.
Dans ce cas, nous utiliserons un ensemble de données simple constitué des symptômes de la grippe (crédit à ceci article de blog pour l'idée). Si vous êtes intéressé, vous trouverez le code de cet exemple dans le testAEBackpropagation méthode .
Voici comment l'ensemble de données se décompose:
Nous considérerons un patient comme malade quand il a au moins deux des trois premiers traits et en bonne santé s'il a au moins deux des trois seconds (avec rupture des liens en faveur des patients sains), par exemple:
Nous allons entraîner un encodeur automatique (utilisant la rétropropagation) 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, nous observons 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 d'activation plus élevée que le 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 pour 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 un Machines Boltzmann restreintes (RBM), à réseau neuronal stochastique génératif qui peut apprendre une distribution de probabilité sur son ensemble d'entrées .
Les RBM sont composés d'une couche cachée, visible et biaisée. Contrairement aux réseaux anticipés, les connexions entre les couches visibles et cachées sont non dirigées (les valeurs peuvent être propagées dans les directions visible-caché et caché-visible) et entièrement connectées (chaque unité d'une couche donnée est connectée à chaque unité de la suivante - si nous permettions à n'importe quelle unité de n'importe quelle couche de se connecter à n'importe quelle autre couche, alors nous aurions un Boltzmann (plutôt qu'un restreint Boltzmann ) machine).
design de communication vs design graphique
Le RBM standard a des unités binaires cachées et visibles: 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 GAR depuis un certain temps maintenant, l'introduction récente de la divergence contrastive L'algorithme d'entraînement non supervisé a renouvelé son intérêt.
L'algorithme de divergence contrastive en une seule étape (CD-1) fonctionne comme ceci:
Mise à jour du poids :
Où à est le taux d'apprentissage et v , v » , h , h » , et dans sont des vecteurs.
L'intuition derrière l'algorithme est que la phase positive ( h donné v ) reflète la représentation interne du réseau du monde réel Les données. 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 » donné h ). L'objectif principal est de données générées être le plus proche possible du monde réel et cela se reflète dans la formule de mise à jour du poids.
En d'autres termes, le réseau a une certaine 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 sa reproduction n’est pas assez proche de la réalité, il effectue un ajustement et essaie à nouveau.
Pour démontrer la divergence contrastive, nous utiliserons le même ensemble de données sur les symptômes qu'auparavant. Le réseau de test est un RBM avec six unités visibles et deux unités cachées. Nous formerons le réseau en utilisant une divergence contrastive avec les symptômes v serré sur la couche visible. Pendant le test, les symptômes sont à nouveau présentés à la couche visible; puis, les données sont propagées vers la couche masquée. Les unités cachées représentent l'état malade / sain, une architecture très similaire à l'auto-encodeur (propageant les données du visible vers la couche cachée).
Après plusieurs centaines d'itérations, nous pouvons observer 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 le testContrastiveDivergence méthode .
Nous avons maintenant démontré que les couches cachées des auto-encodeurs et des RBM agissent comme des détecteurs de caractéristiques efficaces; mais il est rare que nous puissions utiliser ces fonctionnalités directement. En fait, l'ensemble de données ci-dessus est plus une exception qu'une règle. Au lieu de cela, nous devons trouver un moyen d'utiliser ces fonctionnalités détectées indirectement.
Heureusement, cela a été découvert que ces structures peuvent être empilé former Profond réseaux. Ces réseaux peuvent être formés avec gourmandise, une couche à la fois, pour aider à surmonter les gradient de fuite et surapprentissage problèmes liés à la rétropropagation classique.
Les structures résultantes sont souvent assez puissantes, produisant des résultats impressionnants. Prenons, par exemple, le célèbre Google Papier «chat» dans lequel ils utilisent un type spécial d'autoencodeurs profonds pour «apprendre» la détection des visages humains et chats basée sur sans étiquette Les données.
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 encodeurs automatiques empilés consistent donc à fournir une méthode de pré-formation efficace pour initialiser les poids d'un réseau, vous laissant ainsi un perceptron complexe et multicouche prêt à être entraîné (ou affiner ).
les entreprises peuvent atteindre une croissance principalement en
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 de RBM t agit comme une couche visible pour RBM t + 1 . La couche d'entrée du premier RBM est la couche d'entrée pour l'ensemble du réseau, et la pré-formation gourmande par couche fonctionne comme ceci:
Cette procédure s'apparente à celle des auto-encodeurs empilés, mais avec les auto-encodeurs remplacés par des RBM et la rétropropagation remplacée par l'algorithme de divergence contrastive.
(Remarque: pour en savoir plus sur la construction et la formation d'autoencodeurs empilés ou de réseaux de croyances profondes, consultez l'exemple de code Ici .)
En guise d'architecture finale d'apprentissage en profondeur, jetons un coup d'œil aux réseaux convolutifs, une classe particulièrement intéressante et spéciale de réseaux à réaction qui sont très bien adaptés à la reconnaissance d'images.
Image via DeepLearning.net
Avant de regarder la structure réelle des réseaux convolutifs, nous définissons d'abord une image filtre , ou une région carrée avec des 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 les coordonnées 1,1 est la somme pondérée d'un carré 6x6 de pixels d'entrée avec le coin supérieur gauche 1,1 et les poids du filtre (qui est également un carré 6x6). Le pixel de sortie 2,1 est le résultat d'un carré d'entrée avec le coin supérieur gauche 2,1 et ainsi de suite.
Avec cela couvert, ces réseaux sont définis par les propriétés suivantes:
Vous pouvez voir plusieurs exemples de réseaux convolutifs entraînés (avec rétropropagation) sur le MNIST ensemble de données (images en niveaux de gris de lettres manuscrites) Ici , en particulier dans le testLeNet * méthodes (je recommanderais testLeNetTiny2 car il atteint un faible taux d'erreur d'environ 2% en un laps de temps relativement court). Il existe également une belle visualisation JavaScript d'un réseau similaire Ici .
Maintenant que nous avons couvert les variantes de réseau de neurones les plus courantes, j'ai pensé écrire un peu sur les défis posés lors de la mise en œuvre de ces structures d'apprentissage en profondeur.
De manière générale, mon objectif en créant un Bibliothèque de Deep Learning était (et est toujours) de construire un cadre basé sur un réseau de neurones qui satisfait aux critères suivants:
Pour répondre à ces exigences, j'ai adopté une approche à plusieurs niveaux (ou modulaire) de la conception du logiciel.
Commençons par les bases:
Cette structure est suffisamment agile pour être utilisée pour les réseaux classiques à feedforward, ainsi que pour RBM et des architectures plus complexes comme ImageNet .
Cela permet également à une couche de faire partie de plus d'un réseau. Par exemple, les calques d'un Réseau de croyance profonde sont également des couches dans leurs RBM correspondants.
De plus, cette architecture permet à un DBN d'être considéré comme une liste de RBM empilés pendant la phase de pré-formation et un réseau anticipé pendant la phase de réglage fin, ce qui est à la fois intuitivement agréable et pratique pour le programme.
Le module suivant s'occupe de propager les données à travers le réseau, un processus en deux étapes:
Comme je l'ai mentionné précédemment, 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 vous permet d'accélérer considérablement l'entraînement avec l'utilisation d'un GPGPU. Dans ce cas, j'ai choisi de travailler avec le Aparapi bibliothèque pour ajouter la prise en charge du GPU.
Aparapi impose des restrictions importantes sur les calculateurs de connexion:
En tant que tel, la plupart des données (poids, tableaux d'entrée et de sortie) sont stockées dans Matrice instances, qui utilisent des tableaux flottants unidimensionnels 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 de Architecture système hétérogène . Aparapi permet également d'exécuter le même code sur le CPU et le GPU.
La formation module implémente divers algorithmes de formation. Il s'appuie sur les deux modules précédents. Par exemple, RetourPropagationFormateur (tous les formateurs utilisent le Entraîneur classe de base) utilise un calculateur de couches à anticipation pour la phase d'anticipation et un calculateur spécial de largeur de première couche pour propager l'erreur et mettre à jour les poids.
Mes derniers travaux portent sur le support Java 8 et quelques autres améliorations, seront bientôt fusionnés dans Maître .
Le but de ce tutoriel d'apprentissage en profondeur Java é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 basique (le perceptron) et en progressant à travers diverses architectures efficaces et populaires, comme celle du Boltzmann restreint. machine.
Les idées derrière les réseaux de neurones existent depuis longtemps; mais aujourd'hui, vous ne pouvez pas entrer dans la communauté du machine learning sans avoir entendu parler des réseaux profonds ou d'une autre approche du deep learning. Le battage médiatique ne doit pas être confondu avec la justification, mais avec les progrès de l'informatique GPGPU et les progrès impressionnants réalisés par des chercheurs comme 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 le présent.
Si vous souhaitez en savoir plus, j'ai trouvé les ressources suivantes très utiles pendant mon travail: