Hola a todos, colegas!
Quizás los fanáticos de la biblioteca Tensorflow, que ya notaron
este libro en nuestro pedido anticipado, también observaron de cerca las posibilidades de aprendizaje automático y profundo en el navegador, especialmente porque el propio
Francois Schollet no ignoró el tema. Invitamos a los interesados en el gato, que explica cómo se reconocen las imágenes utilizando la biblioteca Tensorflow.js.
TensorFlow.js es una nueva versión de la popular biblioteca de código abierto que enriquece JavaScript con capacidades de aprendizaje profundo. Los desarrolladores ahora pueden definir, entrenar y ejecutar modelos utilizando la
API de biblioteca de alto nivel .
Gracias a
los modelos previamente entrenados, los desarrolladores ahora pueden resolver fácilmente tareas complejas como el
reconocimiento de patrones ,
la generación de música o la
determinación de posiciones humanas en solo unas pocas líneas de JavaScript.
Tensorflow.js comenzó como una biblioteca front-end para trabajar en un navegador, pero este año se agregó
soporte experimental para Node.js. Por lo tanto, TensorFlow.js también se puede utilizar en aplicaciones de back-end de JavaScript, lo que nos evita por completo tener que recurrir a Python.
Al leer sobre esta biblioteca, decidí probarla en una tarea simple ...Use TensorFlow.js para el reconocimiento visual de imágenes en imágenes cuando use JavaScript de Node.js
Desafortunadamente, la
documentación y los
ejemplos de código describen principalmente el uso de esta biblioteca en el navegador. Tuve que pasar mucho tiempo para leer bien las fuentes de Script para esta biblioteca.
Sin embargo, después de unos días de swotting, ¡todavía lo hice! ¡Hurra!
Antes de pasar a un análisis detallado del código, hablemos de otras implementaciones de la biblioteca TensorFlow.TensorflowTensorFlow es una biblioteca de software gratuita para aplicaciones de aprendizaje automático. TensorFlow se puede usar para crear redes neuronales e implementar otros algoritmos de aprendizaje profundo.
Esta es una biblioteca lanzada por Google en noviembre de 2015, originalmente
escrita en Python . Para la capacitación y evaluación de modelos creados, utiliza cálculos en una CPU o GPU. Inicialmente, esta biblioteca fue creada para trabajar en servidores de alto rendimiento utilizando GPU de uso intensivo de recursos.
Las actualizaciones recientes han permitido optimizar esta biblioteca y usarla en entornos con recursos más limitados, por ejemplo, en dispositivos móviles y navegadores web.
TensorFlow LiteTensorflow Lite , la versión lite de esta biblioteca para dispositivos móviles y sistemas integrados, se lanzó en mayo de 2017. Junto con él, se proporciona un nuevo conjunto de modelos profundos previamente entrenados para tareas relacionadas con el reconocimiento de patrones; Esta colección se llama
MobileNet . Los modelos MobileNet se han diseñado específicamente para un funcionamiento eficiente en entornos con una cantidad limitada de recursos, como dispositivos móviles.
TensorFlow.js
Después de Tensorflow Lite, TensorFlow.js se
anunció en marzo de 2018. Esta versión de la biblioteca está diseñada para funcionar en un navegador y se basa en un proyecto anterior llamado
deeplearn.js . WebGL proporciona acceso de GPU a la biblioteca. Los desarrolladores usan la API de JavaScript para entrenar, cargar y ejecutar modelos.
Más tarde, TensorFlow.js se expandió para trabajar con Node.js, para esto se utiliza el
complemento de biblioteca tfjs-node
.
Importe modelos existentes en TensorFlow.jsLos modelos de TensorFlow y Keras listos para usar se pueden ejecutar utilizando la biblioteca TensorFlow.js. Antes de ejecutar el modelo, debe convertir a un nuevo formato con
esta herramienta . Los modelos preformados y transformados para clasificar imágenes, definir poses y detectar vecinos más cercanos
están disponibles en Github .
Usando TensorFlow.js con Node.jsInstalar bibliotecas TensorFlow
TensorFlow.js se puede instalar desde el
registro NPM .
npm install @tensorflow/tfjs @tensorflow/tfjs-node // ... npm install @tensorflow/tfjs @tensorflow/tfjs-node-gpu
Ambas extensiones para Node.js usan dependencias nativas, que se compilarán a pedido.
Descargar TensorFlow LibrariesLa API de JavaScript para Tensorflow se proporciona desde la biblioteca principal. No se proporcionan API de extensión en los módulos de extensión que admiten Node.js.
const tf = require('@tensorflow/tfjs')
Descargar modelos TensorFlowTensorFlow.js proporciona una
biblioteca NPM (
tfjs-models
) que simplifica la carga de
tfjs-models
pre-entrenados y transformados para
clasificar imágenes ,
definir poses y
detectar vecinos k-más cercanos .
El
modelo de clasificación de imágenes de
MobileNet es una red neuronal profunda entrenada para distinguir entre
1000 clases diferentes de imágenes .
En el archivo README para el proyecto
como ejemplo , el siguiente código se usa para cargar el modelo.
import * as mobilenet from '@tensorflow-models/mobilenet';
Uno de los primeros problemas que encontré es que este código no funciona con Node.js.
Error: browserHTTPRequest is not supported outside the web browser.
Después de examinar el
código fuente , vemos que la biblioteca mobilenet es un contenedor para la clase
tf.Model
. Cuando se lo llama, el método
load()
descarga automáticamente los archivos de modelo necesarios ubicados en una dirección HTTP externa y crea una instancia del modelo TensorFlow.
La extensión Node.js en el momento de la escritura aún no admitía solicitudes HTTP para la recuperación de modelos dinámicos. Todo lo que quedaba era cargar manualmente los modelos en el sistema de archivos.
Sin embargo, después de leer el código fuente de la biblioteca, encontré una solución ...Descargar modelos del sistema de archivosSi la clase MobileNet se crea manualmente, no puede llamar al método de
load
del módulo, sino reescribir la
path
variable generada automáticamente
path
contiene la dirección HTTP del modelo, reemplazando esta dirección con la ruta local en el sistema de archivos. Después de eso, cuando se llama al método de
load
en la instancia de clase, se disparará la clase del
cargador del sistema de archivos ; en este caso, nos negamos a usar un descargador HTTP basado en navegador.
const path = "mobilenet/model.json" const mn = new mobilenet.MobileNet(1, 1); mn.path = `file://${path}` await mn.load()
¡Genial, todo funciona!
Pero, ¿de dónde vienen los archivos del modelo?
Modelos MobileNetLos modelos para TensorFlow.js consisten en dos tipos de archivos: un archivo de configuración de modelo almacenado en formato JSON y pesos de modelo almacenados en formato binario. Los pesos del modelo a menudo se fragmentan en muchas partes para optimizar el almacenamiento en caché del navegador.
Después de considerar el
código de descarga automática para los modelos MobileNet, vemos que los modelos, sus configuraciones y fragmentos de peso se extraen del contenedor público en la siguiente dirección.
https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v${version}_${alpha}_${size}/
Los parámetros de la plantilla en la URL describen las versiones del modelo enumeradas
aquí . La precisión de clasificación resultante también se muestra en la misma página.
El código fuente indica que solo los modelos de MobileNet v1 pueden descargarse usando la
tensorflow-models/mobilenet
.
El código de extracción HTTP descarga el archivo
model.json
desde la ubicación de almacenamiento y luego selecciona recursivamente todos los fragmentos de los modelos con pesos referenciados. Estos son archivos en el formato
groupX-shard1of1
.
Descarga manual de modelosSi desea guardar todos los archivos de modelo en el sistema de archivos, puede hacer esto: extraer el archivo de configuración del modelo, analizar la sintaxis de todos los archivos ponderados a los que se hace referencia en el archivo de configuración y luego descargar cada archivo ponderado manualmente.
Iba a usar el módulo MobileNet V1 con un valor alfa de 1.0 y una imagen de 224 píxeles . Entonces obtengo la
siguiente URL para el archivo de configuración del modelo.
https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_1.0_224/model.json
Una vez que este archivo se descarga localmente, puede usar la
herramienta jq
para analizar los nombres de todos los archivos ponderados.
$ cat model.json | jq -r ".weightsManifest[].paths[0]" group1-shard1of1 group2-shard1of1 group3-shard1of1 ...
Con la herramienta
sed
, puede prefijar el nombre de cada elemento HTTP con una URL para generar una URL para cada archivo de peso.
$ cat model.json | jq -r ".weightsManifest[].paths[0]" | sed 's/^/https:\/\/storage.googleapis.com\/tfjs-models\/tfjs\/mobilenet_v1_1.0_224\//' https:
Los comandos
parallel
y
curl
le permiten descargar todos estos archivos a mi directorio 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
Clasificación de la imagenEste código de muestra proporcionado con TensorFlow.js muestra cómo devolver el resultado de la clasificación de imágenes.
const img = document.getElementById('img');
Esto no funciona en Node.js debido a la falta de soporte DOM.
El método de classify
acepta varios elementos DOM (
canvas
,
video
,
image
) y extrae y convierte automáticamente los bytes de "imagen" de estos elementos a la clase
tf.Tensor3D
, utilizada como entrada de modelo. Alternativamente, la
tf.Tensor3D
se puede transmitir directamente.
Decidí no intentar usar un paquete externo para simular un elemento DOM manualmente, pero descubrí que tf.Tensor3D
más fácil de ensamblar manualmente .
Generamos Tensor3D a partir de la imagen.Al leer el
código fuente del método utilizado para convertir elementos DOM a clases Tensor3D, encontramos que los siguientes parámetros de entrada se utilizan para generar la clase Tensor3D.
const values = new Int32Array(image.height * image.width * numChannels);
pixels
es una matriz de tipo
(Int32Array)
contiene una lista secuencial de valores de canal para cada píxel.
numChannels
es el número de valores de canal por píxel.
Crear valores de entrada para JPEGLa biblioteca jpeg-js
es un codificador / decodificador JPEG para Node.js escrito en JavaScript puro. Con esta biblioteca, puede extraer valores RGB para cada píxel.
const pixels = jpeg.decode(buffer, true);
Como resultado, obtenemos un Uint8Array con cuatro valores de canal (
RGBA
) para cada píxel (
width * height
). El modelo MobileNet usa solo tres canales de color (
RGB
) para la clasificación, el canal alfa se ignora. Este código convierte una matriz de cuatro canales en una verdadera versión de tres canales.
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]; } }
Requisitos de entrada para modelos MobileNetEl
modelo de MobileNet utilizado aquí clasifica las imágenes de 224 píxeles de alto y ancho. Los tensores de entrada deben contener valores de coma flotante en el rango de -1 a 1 para cada uno de los tres valores de canal de cada píxel.
Los valores de entrada para imágenes con una dimensión diferente deben convertirse al tamaño correcto antes de la clasificación. Además, los valores de píxeles obtenidos del decodificador JPEG están en el rango de 0 a 255, no de -1 a 1. Estos valores también deben convertirse antes de la clasificación.
TensorFlow.js tiene métodos de biblioteca para simplificar este proceso, pero, aún mejor, ¡hay una
tfjs-models/mobilenet
especial tfjs-models/mobilenet
que resuelve automáticamente este problema !El desarrollador puede pasar los Tensor3D de entrada de tipo
int32
, así como varias dimensiones al método de
classify
, que traduce los valores de entrada al formato correcto antes de la clasificación. Es decir, no tenemos nada que hacer aquí. Genial
Obteniendo prediccionesLos modelos MobileNet de Tensorflow aprenden a reconocer objetos de las
1000 clases más importantes del
conjunto de datos de
ImageNet . En la salida del modelo, proporcione valores probabilísticos que caractericen cuáles son las posibilidades de encontrar estos objetos en la imagen clasificada.
En este archivo se encuentra una lista completa de clases capacitadas para el modelo utilizado .
La
tfjs-models/mobilenet
ofrece el método de
classify
en la clase
MobileNet
, que devuelve la X superior de las clases más probables, según lo que se muestra en la imagen.
const predictions = await mn_model.classify(input, 10);
predictions
es una matriz de clases X y probabilidades en el siguiente formato.
{ className: 'panda', probability: 0.9993536472320557 }
EjemploEntonces, hemos descubierto cómo usar la biblioteca TensorFlow.js y los modelos MobileNet en Node.js, y ahora veamos cómo este script clasifica la imagen especificada como un argumento de línea de comandos.
Código fuenteGuarde este archivo de script y el descriptor del paquete en archivos locales.
{ "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])
PruebaDescargue los archivos del modelo en el directorio de mobilenet siguiendo las instrucciones anteriores.
Establecer dependencias del proyecto usando NPM
npm install
Descargue un archivo JPEG de muestra para clasificarlo
wget http://bit.ly/2JYSal9 -O panda.jpg

Ejecute el script, cuyos argumentos serán el archivo del modelo y la imagen de entrada.
node script.js mobilenet/model.json panda.jpg
Si todo funcionó correctamente, la siguiente salida debería aparecer en la consola.
classification results: [ { className: 'giant panda, panda, panda bear, coon bear', probability: 0.9993536472320557 } ]
¡La imagen está clasificada correctamente como que contiene un panda con una probabilidad del 99,93%!
ConclusiónLa biblioteca TensorFlow.js abre oportunidades de aprendizaje profundo para los desarrolladores de JavaScript. El uso de modelos previamente entrenados con la biblioteca TensorFlow.js le permite construir fácilmente en aplicaciones JavaScript nuevas funciones para resolver problemas complejos de aprendizaje automático, con un esfuerzo mínimo y un código conciso.
La biblioteca TensorFlow.js se creó exclusivamente para trabajar en un navegador, pero ahora interactúa con Node.js, aunque no todas las herramientas y utilidades admiten este nuevo tiempo de ejecución. Después de jugar con la biblioteca durante varios días, aprendí a usarla con los modelos MobileNet para el reconocimiento visual de imágenes de un archivo local.