Implementación de MobileNet con TensorFlow.js y Flask

JavaScriptJavaScriptBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Este proyecto te guía a través del proceso de implementar un modelo MobileNetV2 pre-entrenado utilizando TensorFlow.js dentro de una aplicación web Flask. MobileNetV2 es una red neuronal profunda ligera utilizada principalmente para la clasificación de imágenes. TensorFlow.js permite ejecutar modelos de aprendizaje automático directamente en el navegador, lo que permite crear aplicaciones web interactivas. Flask, un marco web de Python, servirá como el backend para alojar nuestra aplicación. Al final de este proyecto, tendrás una aplicación web en funcionamiento que clasifique imágenes en tiempo real utilizando el modelo MobileNetV2.

👀 Vista previa

🎯 Tareas

En este proyecto, aprenderás:

  • Cómo exportar un modelo MobileNetV2 pre-entrenado de Keras a un formato compatible con TensorFlow.js.
  • Cómo crear una aplicación Flask simple para servir tu contenido web y modelo.
  • Cómo diseñar una página HTML para subir y mostrar imágenes para su clasificación.
  • Cómo utilizar TensorFlow.js para cargar el modelo exportado en el navegador.
  • Cómo preprocesar imágenes en el navegador para que coincidan con los requisitos de entrada de MobileNetV2.
  • Cómo ejecutar el modelo en el navegador para clasificar imágenes y mostrar los resultados.

🏆 Logros

Después de completar este proyecto, podrás:

  • Convertir un modelo Keras pre-entrenado en un formato que se puede utilizar con TensorFlow.js, lo que permite que los modelos de ML se ejecuten en el navegador.
  • Configurar una aplicación Flask y servir contenido HTML y archivos estáticos.
  • Integrar TensorFlow.js en una aplicación web para realizar tareas de aprendizaje automático en el lado del cliente.
  • Preprocesar imágenes en JavaScript para que sean compatibles con los requisitos de entrada de los modelos de aprendizaje profundo.
  • Realizar predicciones utilizando un modelo de aprendizaje profundo en el navegador y mostrar los resultados dinámicamente en la página web.

Preparando el entorno y los archivos del proyecto

Antes de comenzar a codificar, es importante configurar correctamente nuestro entorno de proyecto. Esto incluye instalar los paquetes necesarios y entender la estructura de archivos del proyecto que ya está en lugar.

Primero, familiarízate con la estructura inicial de archivos del proyecto. Los siguientes archivos y carpetas ya se encuentran en tu directorio de trabajo:

tree

Salida:

.
├── app.py
├── model_convert.py
├── static
│ ├── imagenet_classes.js
│ ├── tfjs.css
│ └── tfjs.js
└── templates
└── tfjs.html

2 directorios, 6 archivos

La estructura de tu proyecto consta de varios componentes clave, cada uno desempeñando un papel fundamental en la implementación de tu aplicación web para la clasificación de imágenes utilizando el modelo MobileNetV2 con TensorFlow.js y Flask. A continuación, se presenta una descripción general de cada directorio y archivo dentro de tu proyecto:

  • app.py: Este es el archivo principal de Python para tu aplicación Flask. Inicializa la aplicación Flask, configura la ruta para tu página web e incluye cualquier lógica de backend necesaria para servir tu modelo TensorFlow.js y el contenido web.
  • model_convert.py: Este script de Python se encarga de cargar el modelo MobileNetV2 pre-entrenado y convertirlo a un formato compatible con TensorFlow.js. Esta conversión es crucial para permitir que el modelo se ejecute en un navegador web.
  • static/: Este directorio almacena los archivos estáticos requeridos por tu aplicación web. Estos incluyen:
    • imagenet_classes.js: Un archivo JavaScript que contiene las clases de ImageNet. Este archivo se utiliza para mapear las predicciones numéricas del modelo a nombres de clases legibles por humanos.
    • tfjs.css: Una adición nueva, este archivo de hojas de estilo en cascada (CSS) se utiliza para dar estilo a la interfaz de usuario de la aplicación web. Define los aspectos visuales de tu aplicación, como los diseños, los colores y las fuentes, lo que garantiza una interfaz más atractiva y amigable para el usuario.
    • tfjs.js: Otro archivo nuevo, este archivo JavaScript probablemente contiene la lógica para cargar el modelo TensorFlow.js, procesar imágenes y ejecutar predicciones dentro del navegador. Este script es central para la interactividad de tu aplicación, manejando las operaciones del lado del cliente relacionadas con el modelo TensorFlow.js.
  • templates/: Este directorio contiene archivos HTML que definen la estructura y el diseño de tu aplicación web. En este caso, incluye:
    • tfjs.html: La plantilla HTML principal de tu aplicación, tfjs.html incluye la marca necesaria para mostrar imágenes, resultados de predicción y posiblemente elementos de interacción del usuario, como botones de carga de archivos. Integra el modelo TensorFlow.js, aprovechando el script tfjs.js para las funcionalidades relacionadas con el modelo y tfjs.css para el estilo.

Esta estructura está diseñada para separar las preocupaciones, lo que hace que tu proyecto sea modular y más fácil de administrar. Los directorios static y templates son estándar en las aplicaciones Flask, lo que ayuda a organizar los activos estáticos y las plantillas HTML, respectivamente. La separación del script de conversión de modelo (model_convert.py) de la lógica principal de la aplicación (app.py) mejora la modularidad y la mantenibilidad de tu código.

A continuación, instala los paquetes necesarios:

## Instala los paquetes de Python requeridos
pip install tensorflow==2.14.0 tensorflowjs==4.17.0 flask==3.0.2 flask-cors==4.0.0

Los paquetes incluyen TensorFlow para el modelo de aprendizaje automático, TensorFlow.js para convertir el modelo para su uso en un entorno web, Flask para crear el servidor web y Flask-CORS para manejar solicitudes de origen cruzado, que son comunes en las aplicaciones web.

Exportando el modelo MobileNetV2 pre-entrenado al formato de TensorFlow.js

Para utilizar el modelo MobileNetV2 en el navegador, primero debemos exportarlo de Keras a un formato que TensorFlow.js pueda entender.

## Completa el archivo model_convert.py

## Exportando el modelo MobileNetV2
import tensorflowjs as tfjs
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2

## Carga el modelo MobileNetV2 pre-entrenado
model = MobileNetV2(weights='imagenet')

## Convierte y guarda el modelo en el formato de TensorFlow.js
tfjs.converters.save_keras_model(model,'static/model/')

En este paso, se aprovechan las bibliotecas TensorFlow y TensorFlow.js para cargar un modelo MobileNetV2 pre-entrenado y convertirlo en un formato compatible con TensorFlow.js.

Se elige MobileNetV2 por su eficiencia y tamaño relativamente pequeño, lo que lo hace adecuado para la implementación web. Esta conversión es necesaria porque el formato original del modelo utilizado en TensorFlow basado en Python no es directamente usable en un entorno web. La función tfjs.converters.save_keras_model toma el modelo de Keras y lo guarda en un directorio estructurado de manera que TensorFlow.js pueda cargarlo fácilmente más adelante en la aplicación web.

Luego puedes ejecutar:

python model_convert.py

El modelo convertido se guardará en la carpeta static/model/:

ls static/model

## group1-shard1of4.bin  group1-shard2of4.bin  group1-shard3of4.bin  group1-shard4of4.bin  model.json

Este proceso incluye guardar los pesos y la arquitectura del modelo en una serie de archivos de fragmentos y un archivo model.json, respectivamente.

✨ Revisar Solución y Practicar

Creando la aplicación Flask

Ahora, configuraremos una aplicación Flask simple para servir nuestra página web y el modelo TensorFlow.js.

## Completa el archivo app.py

## Configurando la aplicación Flask
from flask import Flask, render_template
from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app)  ## Habilita Compartir Recursos de Origen Cruzado

@app.route("/")
def hello():
    ## Sirve la página HTML
    return render_template('tfjs.html')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port='8080', debug=True)

Este paso implica configurar un servidor web Flask básico. Flask es un marco web micro escrito en Python, conocido por su simplicidad y facilidad de uso.

Comienza importando Flask y CORS (Compartir Recursos de Origen Cruzado) de sus respectivas bibliotecas. CORS es esencial para aplicaciones web que soliciten recursos de diferentes dominios, lo que garantiza que tu aplicación web pueda hacer solicitudes de manera segura al servidor Flask.

Defines una ruta simple ("/") que sirve una página HTML (tfjs.html), que contendrá tu código de TensorFlow.js del lado del cliente. La aplicación Flask está configurada para ejecutarse en tu máquina local (host='0.0.0.0') y escuchar en el puerto 8080. La configuración debug=True es útil durante el desarrollo ya que proporciona mensajes de error detallados y recarga automáticamente el servidor cuando se detectan cambios en el código.

Ahora, puedes ejecutar la aplicación web Flask:

python app.py
## * Sirviendo aplicación Flask 'app'
## * Modo de depuración: activado
## AVISO: Este es un servidor de desarrollo. No lo uses en una implementación de producción. Utiliza un servidor WSGI de producción en su lugar.
## * Ejecutando en todas las direcciones (0.0.0.0)
## * Ejecutando en http://127.0.0.1:8080
## * Ejecutando en http://172.18.0.7:8080
## Presiona CTRL+C para salir
✨ Revisar Solución y Practicar

Preparando la estructura HTML

Ahora, debemos crear la estructura HTML de nuestra aplicación en templates/tfjs.html. Esto incluye el diseño para la carga, vista previa y visualización de los resultados de predicción de imágenes.

<!-- Estructura HTML para la aplicación de predicción de imágenes -->
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Predicción de imágenes</title>
    <link
      href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css"
      rel="stylesheet"
    />
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
    <link rel="stylesheet" href="static/tfjs.css" />
  </head>
  <body class="flex flex-col items-center justify-center min-h-screen">
    <div class="card bg-white p-6 rounded-lg max-w-sm">
      <h1 class="text-xl font-semibold mb-4 text-center">
        Predicción de imágenes
      </h1>
      <div class="flex flex-col items-center">
        <label
          for="imageUpload"
          class="button-custom cursor-pointer mb-4 flex items-center justify-center"
        >
          <span>Sube una imagen</span>
          <input
            type="file"
            id="imageUpload"
            class="file-input"
            accept="image/*"
          />
        </label>
        <div
          id="imagePreviewContainer"
          class="mb-4 w-56 h-56 border border-dashed border-gray-300 flex items-center justify-center"
        >
          <img
            id="imagePreview"
            class="max-w-full max-h-full"
            style="display: none"
          />
        </div>
        <h5 id="output" class="text-md text-gray-700">
          Sube una imagen para comenzar la predicción
        </h5>
        <script type="module" src="static/tfjs.js"></script>
      </div>
    </div>
  </body>
</html>

Este paso implica crear la estructura básica de nuestra aplicación web utilizando HTML. Definimos el tipo de documento como HTML y establecemos el atributo de idioma en inglés.

En la sección head, incluimos metadatos como el conjunto de caracteres y la configuración de la vista previa para un diseño responsivo. También enlazamos con la biblioteca Tailwind CSS para utilizar sus clases de utilidad para dar estilo a nuestra aplicación. La sección body contiene un elemento div con una clase de card, que sirve como contenedor para el contenido de nuestra aplicación.

Dentro de este contenedor, tenemos una etiqueta h1 para el título de la aplicación, un elemento label para el botón de carga de imágenes (que está estilizado para parecer un botón utilizando Tailwind CSS y clases personalizadas), y un elemento div para servir como contenedor para la vista previa de la imagen. El elemento input de tipo file está oculto y se activa cuando se hace clic en el label, lo que permite al usuario subir una imagen. El elemento div con un id de imagePreviewContainer mostrará la imagen subida, y la etiqueta h5 se utilizará para mostrar mensajes al usuario.

✨ Revisar Solución y Practicar

Agregar estilo

En este paso, agregaremos algunos estilos básicos de CSS utilizando Tailwind CSS para el diseño y la estética en static/tfjs.css, junto con algunos estilos personalizados para nuestra aplicación.

body {
  background-color: #f0f2f5;
}
.card {
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.button-custom {
  background-color: #4f46e5; /* Índigo 600 */
  color: white;
  padding: 0.5rem 1.5rem;
  border-radius: 0.375rem; /* redondeado-md */
  transition: background-color 0.2s;
}
.button-custom:hover {
  background-color: #4338ca; /* Índigo 700 */
}
.file-input {
  opacity: 0;
  position: absolute;
  z-index: -1;
}

En este paso, agregamos estilos CSS personalizados para mejorar la apariencia de nuestra aplicación web.

Establecemos el color de fondo del cuerpo en un gris claro para un fondo neutral. La clase card agrega una sombra de caja para crear un efecto similar a una tarjeta para el contenedor. La clase button-custom estila el botón de carga con un color de fondo de índigo, texto blanco, relleno y esquinas redondeadas.

También incluimos un efecto al pasar el cursor para cambiar ligeramente el color de fondo del botón cuando se pasa el cursor por encima, proporcionando una retroalimentación visual al usuario. La clase file-input se utiliza para ocultar el elemento de entrada de archivo real, haciendo que la etiqueta con estilo personalizado sea el principal elemento interactivo para la carga de archivos.

✨ Revisar Solución y Practicar

Cargar el modelo de TensorFlow

En los pasos restantes, completaremos el archivo templates/tfjs.js.

Ahora, agreguemos TensorFlow.js a nuestro proyecto y luego escribamos código JavaScript para cargar nuestro modelo de TensorFlow. Usaremos una función asíncrona para esperar la carga del modelo antes de hacer cualquier predicción.

import { IMAGENET_CLASSES } from "./imagenet_classes.js";

const outputDiv = document.getElementById("output");
let model;

async function loadModel() {
  try {
    outputDiv.textContent = "Cargando modelo de TF...";
    model = await tf.loadLayersModel(
      "https://****.labex.io/static/model/model.json"
    ); // Actualiza la URL
    outputDiv.textContent = "Modelo de TF cargado.";
  } catch (error) {
    outputDiv.textContent = `Error al cargar el modelo: ${error}`;
  }
}

loadModel();

Nota: Debes reemplazar la URL en tf.loadLayersModel con la URL del entorno actual. Puedes encontrarla cambiando a la pestaña Web 8080.

Diagrama de carga del modelo de TensorFlow

Este paso implica agregar TensorFlow.js a nuestro proyecto incluyendo su etiqueta de script en nuestro documento HTML.

Luego, escribimos código JavaScript para cargar de manera asíncrona un modelo de TensorFlow pre-entrenado. Usamos la función tf.loadLayersModel, proporcionándole una URL a nuestro archivo JSON del modelo. Esta función devuelve una promesa que se resuelve con el modelo cargado. Actualizamos el contenido de texto del outputDiv para informar al usuario sobre el estado de carga del modelo. Si el modelo se carga correctamente, mostramos "Modelo de TF cargado".

De lo contrario, capturamos cualquier error y mostramos un mensaje de error al usuario. Este paso es crucial para permitir que nuestra aplicación realice predicciones, ya que el modelo debe estar cargado y listo antes de que se pueda procesar cualquier imagen.

✨ Revisar Solución y Practicar

Manejar la carga y la vista previa de imágenes

Este paso implica crear la funcionalidad para que los usuarios carguen imágenes y vean una vista previa antes de realizar una predicción. Usaremos un FileReader para leer el archivo cargado y mostrarlo.

// Continúa en static/tfjs.js
const imageUpload = document.getElementById("imageUpload");
const imagePreview = document.getElementById("imagePreview");

imageUpload.addEventListener("change", async (e) => {
  const file = e.target.files[0];
  if (file) {
    const reader = new FileReader();
    reader.onload = (e) => {
      const img = new Image();
      img.src = e.target.result;
      img.onload = async () => {
        imagePreview.src = img.src;
        imagePreview.style.display = "block";
        const processedImage = await preprocessImage(img);
        makePrediction(processedImage);
      };
    };
    reader.readAsDataURL(file);
  }
});

Este paso implica configurar un controlador de eventos para la entrada de carga de imágenes.

Cuando un usuario selecciona un archivo, usamos un FileReader para leer el archivo como una URL de datos. Luego creamos un objeto Image y establecemos su atributo src en el resultado del FileReader, cargando efectivamente la imagen en el navegador. Una vez que la imagen se ha cargado, la mostramos dentro del contenedor imagePreview estableciendo el atributo src de imagePreview en el src de la imagen y haciénd visible el elemento imagePreview.

Luego, la imagen es pre-procesada y predicha por nuestro modelo, completaremos esas funciones en pasos posteriores.

✨ Revisar Solución y Practicar

Preprocesar la imagen para la predicción

Antes de realizar una predicción, necesitamos preprocesar la imagen cargada para que coincida con los requisitos de entrada de nuestro modelo.

// Continúa en static/tfjs.js
async function preprocessImage(imageElement) {
  try {
    let img = tf.browser.fromPixels(imageElement).toFloat();
    img = tf.image.resizeBilinear(img, [224, 224]);
    const offset = tf.scalar(127.5);
    const normalized = img.sub(offset).div(offset);
    const batched = normalized.reshape([1, 224, 224, 3]);
    return batched;
  } catch (error) {
    outputDiv.textContent = `Error en la predicción del modelo: ${error}`;
  }
}

Antes de realizar una predicción, necesitamos preprocesar la imagen cargada para que coincida con el formato de entrada esperado por nuestro modelo de TensorFlow. Este preprocesamiento incluye redimensionar la imagen a las dimensiones requeridas (en este caso, 224x224 píxeles) y normalizar los valores de píxeles.

Usamos operaciones de TensorFlow.js como tf.browser.fromPixels para convertir la imagen en un tensor, tf.image.resizeBilinear para redimensionar y operaciones aritméticas para normalizar los valores de píxeles. Luego, la imagen preprocesada se redimensiona en un lote de uno (para coincidir con la forma de entrada esperada por el modelo), lo que la hace lista para la predicción.

✨ Revisar Solución y Practicar

Realizar una predicción

Una vez que la imagen está preprocesada, estamos listos para realizar una predicción. La función makePrediction toma la imagen procesada como entrada, la alimenta a través del modelo e interpreta la salida para determinar la etiqueta de clase más probable.

// Continúa en static/tfjs.js
async function makePrediction(processedImage) {
  try {
    const prediction = model.predict(processedImage);
    const highestPredictionIndex = await tf.argMax(prediction, 1).data();
    const label = IMAGENET_CLASSES[highestPredictionIndex];
    outputDiv.textContent = `Predicción: ${label}`;
  } catch (error) {
    outputDiv.textContent = `Error al realizar la predicción: ${error}`;
  }
}

En este paso, usamos la función model.predict(processedImage) para alimentar la imagen preprocesada al modelo de TensorFlow. La función tf.argMax(prediction, 1).data() se utiliza para encontrar el índice del valor más alto en el array de predicciones, que corresponde a la etiqueta de clase más probable para la imagen. Esta etiqueta se muestra luego al usuario.

Cambia a la pestaña "Web 8080" y recarga la página web para ver los siguientes efectos.

✨ Revisar Solución y Practicar

Resumen

En este proyecto, aprendiste cómo usar un modelo MobileNetV2 pre-entrenado en una aplicación web Flask utilizando TensorFlow.js. Comenzamos instalando las dependencias necesarias. Luego, exportamos el modelo MobileNetV2 a un formato compatible con TensorFlow.js y configuramos una aplicación Flask para servir nuestra página web. Finalmente, creamos una página HTML que utiliza TensorFlow.js para clasificar imágenes en el navegador con nuestro modelo MobileNetV2. Siguiendo estos pasos, has creado una aplicación web que utiliza el aprendizaje profundo para la clasificación de imágenes en tiempo real.

Este proyecto demuestra el poder de combinar tecnologías web tradicionales con modelos avanzados de aprendizaje automático para crear aplicaciones web interactivas e inteligentes. Puedes extender este proyecto agregando más funciones, como la capacidad de cargar diferentes imágenes, mejorando la interfaz de usuario o incluso integrando modelos más complejos para diferentes tareas.