Apprentissage automatique avec Node.js à l'aide de la bibliothèque Tensorflow.js

Bonjour à tous, chers collègues!

Peut-être que les fans de la bibliothèque Tensorflow, qui ont déjà remarqué ce livre dans notre pré-commande, ont également examiné de près les possibilités de la machine et du deep learning dans le navigateur, d'autant plus que François Schollet lui - même n'a pas ignoré le sujet. Nous invitons les personnes intéressées par le chat, qui explique comment les images sont reconnues à l'aide de la bibliothèque Tensorflow.js.

TensorFlow.js est une nouvelle version de la bibliothèque open source populaire qui enrichit JavaScript avec des capacités d'apprentissage approfondi. Les développeurs peuvent désormais définir, former et exécuter des modèles à l'aide de l' API de bibliothèque de haut niveau .

Grâce à des modèles pré-formés, les développeurs peuvent désormais facilement résoudre des tâches complexes telles que la reconnaissance de formes , la génération de musique ou la détermination de positions humaines en seulement quelques lignes de JavaScript.

Tensorflow.js a commencé comme une bibliothèque frontale pour travailler dans un navigateur, mais cette année, un support expérimental pour Node.js y a été ajouté. Ainsi, TensorFlow.js peut également être utilisé dans des applications backend JavaScript, ce qui nous évite complètement d'avoir à recourir à Python.

En lisant cette bibliothèque, j'ai décidé de l'essayer sur une tâche simple ...
Utilisez TensorFlow.js pour la reconnaissance visuelle des images sur les images lors de l'utilisation de JavaScript à partir de Node.js
Malheureusement, la documentation et les exemples de code décrivent principalement l'utilisation de cette bibliothèque dans le navigateur. Les utilitaires de projet conçus pour simplifier le chargement et l'utilisation de modèles pré-formés au moment de l'écriture ne prenaient pas encore en charge Node.js. J'ai dû consacrer beaucoup de temps à bien lire les sources Typescript pour cette bibliothèque.

Cependant, après quelques jours de swotting, je l'ai toujours fait! Hourra!

Avant de passer à une analyse détaillée du code, parlons d'autres implémentations de la bibliothèque TensorFlow.

Tensorflow

TensorFlow est une bibliothèque de logiciels gratuite pour les applications d'apprentissage automatique. TensorFlow peut être utilisé pour créer des réseaux de neurones et implémenter d'autres algorithmes d'apprentissage en profondeur.

Il s'agit d'une bibliothèque publiée par Google en novembre 2015, initialement écrite en Python . Pour la formation et l'évaluation des modèles créés, il utilise des calculs sur un CPU ou un GPU. Initialement, cette bibliothèque a été créée pour fonctionner sur des serveurs hautes performances utilisant des GPU gourmands en ressources.

Des mises à jour récentes ont permis d'optimiser cette bibliothèque et de l'utiliser dans des environnements aux ressources plus limitées, par exemple sur les appareils mobiles et les navigateurs Web.

TensorFlow Lite

Tensorflow Lite , la version allégée de cette bibliothèque pour appareils mobiles et systèmes embarqués, est sortie en mai 2017. Avec lui, un nouvel ensemble de modèles profonds pré-formés est fourni pour les tâches liées à la reconnaissance des formes; cette collection s'appelle MobileNet . Les modèles MobileNet ont été spécialement conçus pour un fonctionnement efficace dans des environnements avec une quantité limitée de ressources, tels que les appareils mobiles.

TensorFlow.js

Après Tensorflow Lite, TensorFlow.js a été annoncé en mars 2018. Cette version de la bibliothèque est conçue pour fonctionner dans un navigateur et est basée sur un projet antérieur appelé deeplearn.js . WebGL fournit un accès GPU à la bibliothèque. Les développeurs utilisent l'API JavaScript pour former, charger et exécuter des modèles.

Plus tard, TensorFlow.js a été développé pour fonctionner avec Node.js, le tfjs-node complémentaire de bibliothèque tfjs-node est utilisé à cet effet.

Importez des modèles existants dans TensorFlow.js

Les modèles TensorFlow et Keras prêts à l'emploi peuvent être exécutés à l'aide de la bibliothèque TensorFlow.js. Avant d'exécuter le modèle, vous devez convertir un nouveau format à l'aide de cet outil . Des modèles pré-formés et transformés pour classer les images, définir les poses et détecter les k-voisins les plus proches sont disponibles sur Github .

Utilisation de TensorFlow.js avec Node.js

Installer les bibliothèques TensorFlow

TensorFlow.js peut être installé à partir du registre NPM .


 npm install @tensorflow/tfjs @tensorflow/tfjs-node // ... npm install @tensorflow/tfjs @tensorflow/tfjs-node-gpu 

Les deux extensions pour Node.js utilisent des dépendances natives, qui seront compilées à la demande.

Télécharger les bibliothèques TensorFlow

L'API JavaScript pour Tensorflow est fournie par la bibliothèque principale. Aucune API d'extension n'est fournie dans les modules d'extension qui prennent en charge Node.js.

  const tf = require('@tensorflow/tfjs') //   ( CPU) require('@tensorflow/tfjs-node') //    ( GPU) require('@tensorflow/tfjs-node-gpu') 

Télécharger les modèles TensorFlow

TensorFlow.js fournit une bibliothèque NPM ( tfjs-models ) qui simplifie le chargement de tfjs-models pré-formés et transformés pour classer les images , définir les poses et détecter k voisins les plus proches .

Le modèle de classification d'images de MobileNet est un réseau neuronal profond formé pour distinguer entre 1000 classes d'images différentes .

Dans le fichier README du projet, le code suivant est utilisé comme exemple , utilisé pour charger le modèle.

 import * as mobilenet from '@tensorflow-models/mobilenet'; //   const model = await mobilenet.load(); 

L'un des premiers problèmes que j'ai rencontrés est que ce code ne fonctionne pas avec Node.js.

 Error: browserHTTPRequest is not supported outside the web browser. 

Après avoir examiné le code source , nous voyons que la bibliothèque mobilenet est un wrapper pour la classe tf.Model . Lorsqu'elle est appelée, la méthode load() télécharge automatiquement les fichiers de modèle nécessaires situés à une adresse HTTP externe et instancie le modèle TensorFlow.

L'extension Node.js au moment de l'écriture ne prenait pas encore en charge les requêtes HTTP pour la récupération de modèle dynamique. Il ne restait plus qu'à charger manuellement les modèles dans le système de fichiers.

Cependant, après avoir lu le code source de la bibliothèque, j'ai trouvé une solution de contournement ...

Téléchargement de modèles à partir du système de fichiers

Si la classe MobileNet est créée manuellement, vous ne pouvez pas appeler la méthode de load du module, mais réécrire le path variable généré automatiquement contenant l'adresse HTTP du modèle, en remplaçant cette adresse par le chemin local dans le système de fichiers. Après cela, lorsque la méthode de load est appelée dans l'instance de classe, la classe du chargeur de système de fichiers se déclenche; dans ce cas, nous refusons d'utiliser un téléchargeur HTTP basé sur un navigateur.

 const path = "mobilenet/model.json" const mn = new mobilenet.MobileNet(1, 1); mn.path = `file://${path}` await mn.load() 

Cool, tout fonctionne!

Mais d'où viennent les fichiers modèles?

Modèles MobileNet

Les modèles pour TensorFlow.js se composent de deux types de fichiers: un fichier de configuration de modèle stocké au format JSON et des poids de modèle stockés au format binaire. Les poids des modèles sont souvent fragmentés en plusieurs parties pour optimiser la mise en cache du navigateur.

Après avoir considéré le code de téléchargement automatique pour les modèles MobileNet, nous voyons que les modèles, leurs configurations et fragments de poids sont extraits du conteneur public à l'adresse suivante.

 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v${version}_${alpha}_${size}/ 

Les paramètres de modèle dans l'URL décrivent les versions de modèle répertoriées ici . La précision de classification résultante est également affichée sur la même page.

Le code source indique que seuls les modèles de MobileNet v1 peuvent être téléchargés à l'aide de la tensorflow-models/mobilenet .

Le code d'extraction HTTP télécharge le fichier model.json à partir de l'emplacement de stockage, puis sélectionne récursivement tous les fragments de modèles avec des poids référencés. Ce sont des fichiers au format groupX-shard1of1 .

Téléchargement manuel des modèles

Si vous souhaitez enregistrer tous les fichiers de modèle dans le système de fichiers, vous pouvez le faire: extraire le fichier de configuration de modèle, analyser la syntaxe de tous les fichiers pondérés référencés dans le fichier de configuration, puis télécharger manuellement chaque fichier pondéré.
J'allais utiliser le module MobileNet V1 avec une valeur alpha de 1,0 et une image de 224 pixels . J'obtiens donc l' URL suivante pour le fichier de configuration du modèle.

 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/model.json 

Une fois ce fichier téléchargé localement, vous pouvez utiliser l' outil jq pour analyser les noms de tous les fichiers pondérés.

 $ cat model.json | jq -r ".weightsManifest[].paths[0]" group1-shard1of1 group2-shard1of1 group3-shard1of1 ... 

À l'aide de l'outil sed , vous pouvez préfixer le nom de chaque élément HTTP avec une URL pour générer une URL pour chaque fichier de poids.

 $ cat model.json | jq -r ".weightsManifest[].paths[0]" | sed 's/^/https:\/\/storage.googleapis.com\/tfjs-models\/tfjs\/mobilenet_v1_1.0_224\//' https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group1-shard1of1 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group2-shard1of1 https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/group3-shard1of1 ... 

Les commandes parallel et curl vous permettent ensuite de télécharger tous ces fichiers dans mon répertoire local.

 cat model.json | jq -r ".weightsManifest[].paths[0]" | sed 's/^/https:\/\/storage.googleapis.com\/tfjs-models\/tfjs\/mobilenet_v1_1.0_224\//' | parallel curl -O 

Classification d'image

Cet exemple de code fourni avec TensorFlow.js montre comment renvoyer le résultat de la classification d'image.

 const img = document.getElementById('img'); //   const predictions = await model.classify(img); 

Cela ne fonctionne pas dans Node.js en raison du manque de prise en charge DOM.

La méthode classify accepte divers éléments DOM ( canvas , video , image ) et extrait et convertit automatiquement les octets "image" de ces éléments en la classe tf.Tensor3D , utilisée comme entrée de modèle. Alternativement, l' tf.Tensor3D peut être transmise directement.

J'ai décidé de ne pas essayer d'utiliser un package externe pour simuler un élément DOM manuellement, mais tf.Tensor3D trouvé que tf.Tensor3D plus facile à assembler manuellement .

Nous générons Tensor3D à partir de l'image

En lisant le code source de la méthode utilisée pour convertir les éléments DOM en classes Tensor3D, nous constatons que les paramètres d'entrée suivants sont utilisés pour générer la classe Tensor3D.

 const values = new Int32Array(image.height * image.width * numChannels); //     ,    const outShape = [image.height, image.width, numChannels]; const input = tf.tensor3d(values, outShape, 'int32'); 

pixels est un tableau bidimensionnel de type (Int32Array) contenant une liste séquentielle de valeurs de canal pour chaque pixel. numChannels est le nombre de valeurs de canal par pixel.

Création de valeurs d'entrée pour JPEG

La bibliothèque jpeg-js est un encodeur / décodeur JPEG pour Node.js écrit en JavaScript pur. À l'aide de cette bibliothèque, vous pouvez extraire des valeurs RVB pour chaque pixel.

 const pixels = jpeg.decode(buffer, true); 

En conséquence, nous obtenons un Uint8Array avec quatre valeurs de canal ( RGBA ) pour chaque pixel ( width * height ). Le modèle MobileNet n'utilise que trois canaux de couleur ( RGB ) pour la classification, le canal alpha est ignoré. Ce code convertit un tableau à quatre canaux en une véritable version à trois canaux.

  const numChannels = 3; const numPixels = image.width * image.height; const values = new Int32Array(numPixels * numChannels); for (let i = 0; i < numPixels; i++) { for (let channel = 0; channel < numChannels; ++channel) { values[i * numChannels + channel] = pixels[i * 4 + channel]; } } 

Exigences d'entrée pour les modèles MobileNet

Le modèle MobileNet utilisé ici classe les images de 224 pixels de haut et de large. Les tenseurs d'entrée doivent contenir des valeurs à virgule flottante dans la plage de -1 à 1 pour chacune des trois valeurs de canal de chaque pixel.

Les valeurs d'entrée pour les images avec une dimension différente doivent être converties à la taille correcte avant la classification. De plus, les valeurs de pixels obtenues à partir du décodeur JPEG sont comprises entre 0 et 255, et non -1 et 1. Ces valeurs doivent également être converties avant la classification.

TensorFlow.js dispose de méthodes de bibliothèque pour simplifier ce processus, mais, mieux encore, il existe une tfjs-models/mobilenet spéciale tfjs-models/mobilenet qui résout automatiquement ce problème !

Le développeur peut transmettre des Tensor3D d'entrée de type int32 , ainsi que diverses dimensions à la méthode classify, qui traduit les valeurs d'entrée dans le format correct avant la classification. Autrement dit, nous n'avons rien à faire ici. Super!

Obtenir des prédictions

Les modèles MobileNet de Tensorflow apprennent à reconnaître les objets des 1000 classes les plus importantes de l' ensemble de données d' ImageNet . En sortie du modèle, donner des valeurs probabilistes caractérisant les chances de retrouver ces objets dans l'image classée.

Une liste complète des classes formées pour le modèle utilisé se trouve dans ce fichier .

La tfjs-models/mobilenet propose la méthode MobileNet dans la classe MobileNet , qui renvoie le top-X des classes les plus probables, en fonction de ce qui est montré dans l'image.

 const predictions = await mn_model.classify(input, 10); 

predictions est un tableau de classes X et de probabilités au format suivant.

  { className: 'panda', probability: 0.9993536472320557 } 

Exemple

Nous avons donc compris comment utiliser la bibliothèque TensorFlow.js et les modèles MobileNet dans Node.js, et examinons maintenant comment ce script classe l'image spécifiée comme argument de ligne de commande.

Code source

Enregistrez ce fichier de script et le descripteur de package dans des fichiers locaux.

 { "name": "tf-js", "version": "1.0.0", "main": "script.js", "license": "MIT", "dependencies": { "@tensorflow-models/mobilenet": "^0.2.2", "@tensorflow/tfjs": "^0.12.3", "@tensorflow/tfjs-node": "^0.1.9", "jpeg-js": "^0.3.4" } } 

 const tf = require('@tensorflow/tfjs') const mobilenet = require('@tensorflow-models/mobilenet'); require('@tensorflow/tfjs-node') const fs = require('fs'); const jpeg = require('jpeg-js'); const NUMBER_OF_CHANNELS = 3 const readImage = path => { const buf = fs.readFileSync(path) const pixels = jpeg.decode(buf, true) return pixels } const imageByteArray = (image, numChannels) => { const pixels = image.data const numPixels = image.width * image.height; const values = new Int32Array(numPixels * numChannels); for (let i = 0; i < numPixels; i++) { for (let channel = 0; channel < numChannels; ++channel) { values[i * numChannels + channel] = pixels[i * 4 + channel]; } } return values } const imageToInput = (image, numChannels) => { const values = imageByteArray(image, numChannels) const outShape = [image.height, image.width, numChannels]; const input = tf.tensor3d(values, outShape, 'int32'); return input } const loadModel = async path => { const mn = new mobilenet.MobileNet(1, 1); mn.path = `file://${path}` await mn.load() return mn } const classify = async (model, path) => { const image = readImage(path) const input = imageToInput(image, NUMBER_OF_CHANNELS) const mn_model = await loadModel(model) const predictions = await mn_model.classify(input) console.log('classification results:', predictions) } if (process.argv.length !== 4) throw new Error('incorrect arguments: node script.js <MODEL> <IMAGE_FILE>') classify(process.argv[2], process.argv[3]) 

Test

Téléchargez les fichiers de modèle dans le répertoire mobilenet en suivant les instructions ci-dessus.
Définir les dépendances du projet à l'aide de NPM

npm install

Télécharger un exemple de fichier JPEG pour la classification

wget http://bit.ly/2JYSal9 -O panda.jpg



Exécutez le script, dont les arguments seront le fichier modèle et l'image d'entrée.

node script.js mobilenet/model.json panda.jpg

Si tout fonctionnait correctement, la sortie suivante devrait apparaître dans la console.

  classification results: [ { className: 'giant panda, panda, panda bear, coon bear', probability: 0.9993536472320557 } ] 

L'image est correctement classée comme contenant un panda avec une probabilité de 99,93%!

Conclusion

La bibliothèque TensorFlow.js ouvre des opportunités d'apprentissage approfondi aux développeurs JavaScript. L'utilisation de modèles pré-formés avec la bibliothèque TensorFlow.js vous permet de créer facilement dans les applications JavaScript de nouvelles fonctionnalités pour résoudre des problèmes complexes d'apprentissage automatique, avec un minimum d'effort et un code concis.

La bibliothèque TensorFlow.js a été créée uniquement pour fonctionner dans un navigateur, mais maintenant elle interagit avec Node.js, bien que tous les outils et utilitaires ne prennent pas en charge ce nouveau runtime. Après avoir bricolé la bibliothèque pendant plusieurs jours, j'ai appris à l'utiliser avec des modèles MobileNet pour la reconnaissance visuelle des images d'un fichier local.

Source: https://habr.com/ru/post/fr432984/


All Articles