TensorFlow.js funciona en el navegador y en Node.js, y en ambas plataformas hay muchas configuraciones diferentes disponibles. Cada plataforma tiene un conjunto único de consideraciones que afectarán la forma en que se desarrollan las aplicaciones.
En el navegador, TensorFlow.js es compatible tanto con dispositivos móviles como con dispositivos de escritorio. Cada dispositivo tiene un conjunto específico de restricciones, como las API WebGL disponibles, que se determinan y configuran automáticamente para usted.
En Node.js, TensorFlow.js admite el enlace directo a la API de TensorFlow o la ejecución con implementaciones de CPU básicas más lentas.
Ambientes
Cuando se ejecuta un programa TensorFlow.js, la configuración específica se denomina entorno. El entorno se compone de un único backend global, así como de un conjunto de indicadores que controlan las características detalladas de TensorFlow.js.
backends
TensorFlow.js admite múltiples backends diferentes que implementan almacenamiento tensorial y operaciones matemáticas. En un momento dado, solo hay un backend activo. La mayoría de las veces, TensorFlow.js elegirá automáticamente el mejor backend para usted según el entorno actual. Sin embargo, a veces es importante saber qué backend se está utilizando y cómo cambiarlo.
Para encontrar qué backend estás utilizando:
console.log(tf.getBackend());
Si desea cambiar manualmente el backend:
tf.setBackend('cpu');
console.log(tf.getBackend());
Servidor WebGL
El backend de WebGL, 'webgl', es actualmente el backend más potente para el navegador. Este backend es hasta 100 veces más rápido que el backend de CPU básico. Los tensores se almacenan como texturas WebGL y las operaciones matemáticas se implementan en sombreadores WebGL. Aquí hay algunas cosas útiles que debe saber al usar este backend: \
Evite bloquear el hilo de la interfaz de usuario
Cuando se llama a una operación, como tf.matMul(a, b), el tf.Tensor resultante se devuelve sincrónicamente; sin embargo, es posible que el cálculo de la multiplicación de matrices aún no esté listo. Esto significa que el tf.Tensor devuelto es solo un identificador del cálculo. Cuando llamas a x.data()
o x.array()
, los valores se resolverán cuando el cálculo se haya completado. Esto hace que sea importante utilizar los métodos asincrónicos x.data()
y x.array()
sobre sus contrapartes síncronos x.dataSync()
y x.arraySync()
para evitar bloquear el subproceso de la interfaz de usuario mientras se completa el cálculo.
Gestión de la memoria
Una advertencia al utilizar el backend de WebGL es la necesidad de una gestión de memoria explícita. WebGLTextures, que es donde finalmente se almacenan los datos de Tensor, el navegador no recolecta basura automáticamente.
Para destruir la memoria de un tf.Tensor
, puedes usar el método dispose()
:
const a = tf.tensor([[1, 2], [3, 4]]);
a.dispose();
Es muy común encadenar múltiples operaciones en una aplicación. Mantener una referencia a todas las variables intermedias para eliminarlas puede reducir la legibilidad del código. Para resolver este problema, TensorFlow.js proporciona un método tf.tidy()
que limpia todos tf.Tensor
s que no son devueltos por una función después de ejecutarla, de forma similar a la forma en que se limpian las variables locales cuando se ejecuta una función:
const a = tf.tensor([[1, 2], [3, 4]]);
const y = tf.tidy(() => {
const result = a.square().log().neg();
return result;
});
Precisión
En dispositivos móviles, es posible que WebGL solo admita texturas de punto flotante de 16 bits. Sin embargo, la mayoría de los modelos de aprendizaje automático se entrenan con activaciones y pesos de punto flotante de 32 bits. Esto puede causar problemas de precisión al transferir un modelo a un dispositivo móvil, ya que los números flotantes de 16 bits solo pueden representar números en el rango [0.000000059605, 65504]
. Esto significa que debes tener cuidado de que los pesos y activaciones de tu modelo no superen este rango. Para verificar si el dispositivo admite texturas de 32 bits, verifique el valor de tf.ENV.getBool('WEBGL_RENDER_FLOAT32_CAPABLE')
; si esto es falso, entonces el dispositivo solo admite texturas de punto flotante de 16 bits. Puede usar tf.ENV.getBool('WEBGL_RENDER_FLOAT32_ENABLED')
para verificar si TensorFlow.js usa actualmente texturas de 32 bits.
Compilación de sombreadores y cargas de texturas.
TensorFlow.js ejecuta operaciones en la GPU ejecutando programas de sombreado WebGL. Estos sombreadores se ensamblan y compilan de forma diferida cuando el usuario solicita ejecutar una operación. La compilación de un sombreador ocurre en la CPU en el hilo principal y puede ser lenta. TensorFlow.js almacenará en caché los sombreadores compilados automáticamente, lo que hará que la segunda llamada a la misma operación con tensores de entrada y salida de la misma forma sea mucho más rápida. Normalmente, las aplicaciones TensorFlow.js utilizarán las mismas operaciones varias veces durante la vida útil de la aplicación, por lo que el segundo paso por un modelo de aprendizaje automático es mucho más rápido.
TensorFlow.js también almacena datos de tf.Tensor como WebGLTextures. Cuando se crea un tf.Tensor
, no cargamos datos inmediatamente a la GPU, sino que mantenemos los datos en la CPU hasta que se utiliza el tf.Tensor
en una operación. Si tf.Tensor
se usa por segunda vez, los datos ya están en la GPU, por lo que no hay costo de carga. En un modelo típico de aprendizaje automático, esto significa que los pesos se cargan durante la primera predicción a través del modelo y el segundo paso por el modelo será mucho más rápido.
Si le importa el rendimiento de la primera predicción a través de su modelo o código TensorFlow.js, le recomendamos calentar el modelo pasando un tensor de entrada de la misma forma antes de usar datos reales.
Por ejemplo:
const model = await tf.loadLayersModel(modelUrl);
// Warmup the model before using real data.
const warmupResult = model.predict(tf.zeros(inputShape));
warmupResult.dataSync();
warmupResult.dispose();
// The second predict() will be much faster
const result = model.predict(userData);
Backend de Node.js TensorFlow
En el backend de TensorFlow Node.js, 'nodo', la API de TensorFlow C se utiliza para acelerar las operaciones. Esto utilizará la aceleración de hardware disponible de la máquina, como CUDA, si está disponible.
En este backend, al igual que en WebGL, las operaciones devuelven tf.Tensor
s sincrónicamente. Sin embargo, a diferencia del backend de WebGL, la operación se completa antes de recuperar el tensor. Esto significa que una llamada a tf.matMul(a, b)
bloqueará el hilo de la interfaz de usuario.
Por este motivo, si tiene intención de utilizar esto en una aplicación de producción, debe ejecutar TensorFlow.js en subprocesos de trabajo para no bloquear el subproceso principal.
Para obtener más información sobre Node.js, consulte esta guía.
Parte trasera de WASM
TensorFlow.js proporciona un backend WebAssembly ( wasm
), que ofrece aceleración de CPU y se puede utilizar como una alternativa a los backends de CPU ( cpu
) JavaScript estándar y acelerados WebGL ( webgl
). Para usarlo:
// Set the backend to WASM and wait for the module to be ready.
tf.setBackend('wasm');
tf.ready().then(() => {...});
Si su servidor sirve el archivo .wasm
en una ruta diferente o con un nombre diferente, use setWasmPath
antes de inicializar el backend. Consulte la sección "Uso de paquetes" en el archivo README para obtener más información:
import {setWasmPath} from '@tensorflow/tfjs-backend-wasm';
setWasmPath(yourCustomPath);
tf.setBackend('wasm');
tf.ready().then(() => {...});
¿Por qué WASM?
WASM se introdujo en 2015 como un nuevo formato binario basado en web, que proporciona a los programas escritos en JavaScript, C, C++, etc. un destino de compilación para ejecutarse en la web. WASM ha sido compatible con Chrome, Safari, Firefox y Edge desde 2017 y es compatible con el 90% de los dispositivos en todo el mundo.
Actuación
El backend WASM aprovecha la biblioteca XNNPACK para una implementación optimizada de operadores de redes neuronales.
Frente a JavaScript : los binarios WASM son generalmente mucho más rápidos que los paquetes de JavaScript para que los navegadores los carguen, analicen y ejecuten. JavaScript se escribe dinámicamente y se recolecta basura, lo que puede provocar ralentizaciones en tiempo de ejecución.
Frente a WebGL : WebGL es más rápido que WASM para la mayoría de los modelos, pero para modelos pequeños, WASM puede superar a WebGL debido a los costos generales fijos de ejecutar sombreadores de WebGL. La sección "Cuándo debo usar WASM" a continuación analiza las heurísticas para tomar esta decisión.
Portabilidad y estabilidad
WASM tiene aritmética flotante portátil de 32 bits, que ofrece paridad de precisión en todos los dispositivos. WebGL, por otro lado, es específico del hardware y diferentes dispositivos pueden tener diferente precisión (por ejemplo, recurrir a flotantes de 16 bits en dispositivos iOS).
Al igual que WebGL, WASM es oficialmente compatible con todos los principales navegadores. A diferencia de WebGL, WASM puede ejecutarse en Node.js y usarse en el lado del servidor sin necesidad de compilar bibliotecas nativas.
¿Cuándo debo usar WASM?
Tamaño del modelo y demanda computacional.
En general, WASM es una buena opción cuando los modelos son más pequeños o le interesan dispositivos de gama baja que carecen de soporte WebGL (extensión OES_texture_float
) o tienen GPU menos potentes. El siguiente cuadro muestra los tiempos de inferencia (a partir de TensorFlow.js 1.5.2) en Chrome en una MacBook Pro 2018 para 5 de nuestros modelos oficialmente admitidos en WebGL, WASM y backends de CPU:
Modelos más pequeños
Modelo | WebGL | WASM | UPC | Memoria |
---|---|---|---|---|
BlazeFace | 22,5 ms | 15,6 ms | 315,2 ms | .4MB |
malla facial | 19,3 ms | 19,2 ms | 335 ms | 2,8MB |
Modelos más grandes
Modelo | WebGL | WASM | UPC | Memoria |
---|---|---|---|---|
Posenet | 42,5 ms | 173,9 ms | 1514,7 ms | 4,5MB |
CuerpoPix | 77 ms | 188,4 ms | 2683 ms | 4,6MB |
MobileNet v2 | 37 ms | 94 ms | 923,6 ms | 13 megas |
La tabla anterior muestra que WASM es entre 10 y 30 veces más rápido que el backend de CPU JS simple en todos los modelos y competitivo con WebGL para modelos más pequeños como BlazeFace , que es liviano (400 KB), pero tiene una cantidad decente de operaciones (~140). Dado que los programas WebGL tienen un costo fijo fijo por ejecución de operación, esto explica por qué modelos como BlazeFace son más rápidos en WASM.
Estos resultados variarán según su dispositivo. La mejor manera de determinar si WASM es adecuado para su aplicación es probarlo en nuestros diferentes backends.
Inferencia versus entrenamiento
Para abordar el caso de uso principal para la implementación de modelos previamente entrenados, el desarrollo backend de WASM priorizará la inferencia sobre el soporte de capacitación . Vea una lista actualizada de operaciones admitidas en WASM y avísenos si su modelo tiene una operación no admitida. Para los modelos de entrenamiento, recomendamos utilizar el backend de Node (TensorFlow C++) o el backend de WebGL.
parte trasera de la CPU
El backend de la CPU, 'cpu', es el backend de menor rendimiento, sin embargo, es el más simple. Todas las operaciones se implementan en JavaScript básico, lo que las hace menos paralelizables. También bloquean el hilo de la interfaz de usuario.
Este backend puede resultar muy útil para realizar pruebas o en dispositivos donde WebGL no está disponible.
Banderas
TensorFlow.js tiene un conjunto de indicadores de entorno que se evalúan automáticamente y determinan la mejor configuración en la plataforma actual. Estas banderas son en su mayoría internas, pero algunas banderas globales se pueden controlar con una API pública.
-
tf.enableProdMode():
habilita el modo de producción, lo que eliminará la validación del modelo, las comprobaciones de NaN y otras comprobaciones de corrección a favor del rendimiento. -
tf.enableDebugMode()
: habilita el modo de depuración, que registrará en la consola cada operación que se ejecute, así como información de rendimiento en tiempo de ejecución, como la huella de memoria y el tiempo total de ejecución del kernel. Tenga en cuenta que esto ralentizará enormemente su aplicación; no lo utilice en producción.