Cómo implementar un modelo de preguntas y respuestas preentrenado en TensorFlow.js en la plataforma de aplicaciones

El autor seleccionó Código 2040 para recibir una donación como parte del programa Write for DOnations .
Introducción
A medida que crece el campo del aprendizaje automático (ML), también crece la lista de entornos para utilizar esta tecnología. Uno de estos entornos es el navegador web y, en los últimos años, ha habido un aumento en los marcos relacionados con los datos que apuntan a modelos de aprendizaje automático basados en la web. Un ejemplo de estos marcos es TensorFlow.js , la biblioteca equivalente de JavaScript de TensorFlow para entrenar, ejecutar e implementar modelos de aprendizaje automático en el navegador. En un intento por hacer que TensorFlow.js sea accesible para desarrolladores con experiencia limitada o nula en ML, la biblioteca viene con varios modelos entrenados previamente que funcionan de inmediato.
Un modelo de aprendizaje automático preentrenado es un modelo de aprendizaje automático listo para usar que no necesita entrenar. TensorFlow.js incluye 14 que se adaptan a una variedad de casos de uso. Por ejemplo, hay un modelo de clasificación de imágenes para identificar objetos comunes y un modelo de segmentación corporal para identificar partes del cuerpo. La principal ventaja de estos modelos es que, como indica el nombre, no es necesario entrenarlos. En cambio, los carga en su aplicación. Además de su facilidad de uso y su naturaleza preentrenada, estos son modelos seleccionados: son precisos y rápidos, a veces entrenados por los autores de los algoritmos y optimizados para el navegador web.
En este tutorial, creará una aplicación web que ofrece un modelo de preguntas y respuestas (QnA) previamente entrenado con TensorFlow.js. El modelo que implementará es un modelo de Representaciones de codificador bidireccional a partir de transformadores (BERT) que utiliza un pasaje y una pregunta como entrada, e intenta responder la pregunta a partir del pasaje.
Implementarás la aplicación en la plataforma de aplicaciones de DigitalOcean, una solución administrada para crear, implementar y escalar aplicaciones con unos pocos clics desde fuentes como GitHub. La aplicación que crearás consta de una página estática con dos campos de entrada, uno para el pasaje y otro para la pregunta. Al final, tendrás una aplicación de preguntas y respuestas escrita e implementada (desde GitHub) que utiliza uno de los modelos entrenados previamente de TensorFlow.js y la plataforma de aplicaciones de DigitalOcean.
Prerrequisitos
Para completar este tutorial, necesitarás:
- Una cuenta de DigitalOcean .
- Una cuenta en GitHub, que puedes crear yendo a la página Crea tu cuenta .
- Git configurado e instalado en tu máquina local. Consulta Cómo contribuir al código abierto: Introducción a Git y una guía de referencia en Cómo usar Git: una guía de referencia .
- También necesitarás conocimientos básicos de HTML, CSS y JavaScript, que puedes encontrar en nuestras series Cómo crear un sitio web con HTML , Cómo crear un sitio web con CSS y Cómo codificar en JavaScript .
Paso 1: creación de la interfaz de la aplicación e importación de las bibliotecas necesarias
En este paso, escribirás el código HTML de la aplicación, que definirá su interfaz e importará las bibliotecas para la aplicación. La primera de estas bibliotecas es TensorFlow.js y, en lugar de instalar el paquete localmente, lo cargarás desde una red de distribución de contenido o CDN. Una CDN es una red de servidores que abarca varias ubicaciones y que almacenan el contenido que proporcionan a Internet. Este contenido incluye archivos JavaScript, como la biblioteca TensorFlow.js, y cargarlo desde una CDN te ahorra tener que empaquetarlos en tu aplicación. De manera similar, importarás la biblioteca que contiene el modelo de preguntas y respuestas. En el siguiente paso, escribirás el código JavaScript de la aplicación, que utiliza el modelo para responder una pregunta determinada.
En este tutorial, estructurarás una aplicación que se verá así:
La aplicación tiene cinco elementos principales:
- Un botón que carga un pasaje predefinido que puedes usar para probar la aplicación.
- Un campo de texto de entrada para un pasaje (si elige escribir o copiar el suyo propio).
- Un campo de texto de entrada para la pregunta.
- Un botón que activa la predicción que responde a la pregunta.
- Un área para mostrar la salida del modelo debajo del botón ¡Responder! (actualmente espacio en blanco).
Comience por crear un nuevo directorio con el nombre tfjs-qna-do
de su ubicación preferida. En este directorio, utilizando un editor de texto de su elección, cree un nuevo archivo HTML con el nombre index.html
y pegue el siguiente código:
índice.html
!DOCTYPE htmlhtmlhead meta charset="utf-8" / !-- Load TensorFlow.js -- script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"/script !-- Load the QnA model -- script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/qna"/script link href="./style.css" rel="stylesheet"/headbody div h1TensorFlow.js Pre-trained "QnA" BERT model/h1 h3Introduction/h3 pThis application hosts TensorFlow.js' pre-trained Question and Answer model, and it attempts to answer the question using a given passage. To use it, write a passage (any!) in the input area below and a question. Then, click the "answer!" button to answer the question using the given passage as a reference. You could also click the test button to load a pre-defined input text./p h4Try the test passage!/h4 div id='test-buttons'/div div h4Enter the model's input passage here/h4 textarea id='input-text' rows="20" cols="100" placeholder="Write the input text..."/textarea /div div h4Enter the question to ask/h4 textarea id='question' rows="5" cols="100" placeholder="Write the input text..."/textarea /div h4Click to answer the question/h4 div/div h4The model's answers/h4 div id='answer'/div script src="./index.js"/script /div/body/html
Así es como se desglosa ese HTML:
- La etiqueta inicial
html
tiene lahead
etiqueta que se utiliza para definir metadatos, estilos y cargar scripts. Su primer elemento esmeta
, y aquí establecerá lacharset
codificación de la página enutf-8
. Después, hay dosscript
etiquetas para cargar tanto TensorFlow.js como el modelo de preguntas y respuestas desde una CDN. - Después de las dos
script
etiquetas, hay unalink
etiqueta que carga un archivo CSS (que crearás a continuación). - A continuación, está el HTML
body
, el contenido del documento. Dentro de él, hay unadiv
etiqueta de clasemain-centered-container
que contiene los elementos de la página. El primero es unh1
encabezado con el título de la aplicación y unh3
encabezado más pequeño, seguido de una breve introducción que explica cómo funciona. - Debajo de la introducción, hay un
h4
encabezado y undiv
lugar donde agregarás botones que completarán el campo de texto de entrada del pasaje con texto de muestra. - Luego están los campos de entrada de la aplicación: uno para el pasaje (lo que quieres que lea el modelo) y otro para la pregunta (lo que quieres que responda el modelo). Si deseas cambiar su tamaño, cambia los atributos
rows
y .cols
- Después de los campos de texto, hay un
div
idbutton
donde luego agregarás un botón que, al hacer clic, lee el texto de los campos de texto y los usa como entrada para el modelo. - Por último, hay un
div
idanswer
que se usa para mostrar la salida del modelo y unascript
etiqueta para incluir el código JavaScript que escribirás en la siguiente sección.
A continuación, agregará CSS al proyecto. En el mismo directorio donde agregó el index.html
archivo, cree un nuevo archivo llamado style.css
y agregue el siguiente código:
estilo.css
body { margin: 50px 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial;}button { margin: 10px 10px; font-size: 100%;}p { line-height: 1.8;}.main-centered-container { padding: 60px; display: flex; flex-direction: column; margin: 0 auto; max-width: 960px;}.header-border { border: solid #d0d0d0; border-width: 0 0 1px; padding: 0 0 5px;}
Este CSS añade estilo a tres elementos HTML: cuerpo, botones y párrafos ( p
). A body
, añade un margen, relleno y cambia la fuente predeterminada. A button
, añade margen y aumenta el tamaño de la fuente. A párrafo p
, modifica el line-height
atributo . El CSS tiene una clase main-centered-container
que centra el contenido y otra, header-border
, que añade una línea sólida a un elemento.
En este paso, escribiste el archivo HTML de la aplicación. Importaste la biblioteca TensorFlow.js y el modelo QnA, y definiste los elementos que usarás más adelante para agregar el pasaje y la pregunta que quieres responder. En el siguiente paso, escribirás el código JavaScript que lee los elementos y activa las predicciones.
Paso 2: Predicción con el modelo preentrenado
En esta sección, implementarás el código JavaScript de la aplicación web que lee los campos de entrada de la aplicación, realiza una predicción y escribe las respuestas predichas en HTML. Lo harás en una función que se activa cuando haces clic en el botón “responder”. Una vez que haces clic, hará referencia a ambos campos de entrada para obtener sus valores, los usará como entradas para el modelo y escribirá su salida en el div
ID output
que definiste en el Paso 1. Luego, ejecutarás la aplicación localmente para probarla antes de agregarla a GitHub.
En el directorio del proyecto tfjs-qna-do/
, cree un nuevo archivo llamado index.js
y declare las siguientes variables:
índice.js
let model;// The text field containing the input textlet inputText;// The text field containing the questionlet questionText;// The div where we will write the model's answerlet answersOutput;
La primera de las variables, model
, es donde almacenará el modelo QnA; inputText
y questionText
son referencias a los campos de entrada y texto de la pregunta; answersOutput
es una referencia a la salida div
.
Además de estas variables, necesitarás una constante para almacenar el texto de muestra que usarás para probar la aplicación. Usaremos el artículo de Wikipedia sobre DigitalOcean como pasaje de muestra. Con base en este pasaje, puedes hacerle preguntas al modelo como “¿Dónde se encuentra la sede de DigitalOcean?” y, con suerte, obtendrá como resultado “Nueva York”.
Copia este bloque en tu index.js
archivo:
índice.js
// Sample passage from Wikipedia.const doText = `DigitalOcean, Inc. is an American cloud infrastructure provider[2] headquartered in New York City with data centers worldwide.[3] DigitalOcean provides developers cloud services that help to deploy and scale applications that run simultaneously on multiple computers.DigitalOcean also runs Hacktoberfest which is a month-long celebration (October 1-31) of open source software run in partnership with GitHub and Twilio.`;
Ahora, definirás las funciones de la aplicación, comenzando con createButton()
. Esta función crea un botón y lo agrega a un elemento HTML:
índice.js
function createButton(innerText, id, listener, selector, disabled = false) { const btn = document.createElement('BUTTON'); btn.innerText = innerText; btn.id = id; btn.disabled = disabled; btn.addEventListener('click', listener); document.querySelector(selector).appendChild(btn);}
createButton()
es una función que crea los dos botones de la aplicación; dado que todos los botones funcionan de manera similar, esta función evita la repetición de código. La función tiene cinco parámetros:
innerText
:el texto del botón.id
: el id del botón.listener
:una función de devolución de llamada que se ejecuta cuando el usuario hace clic en el botón.selector
:eldiv
elemento donde agregarás el botón.disabled
: un valor booleano para deshabilitar o habilitar el botón. El valor predeterminado de este parámetro esfalse
.
createButton()
comienza creando una instancia de un botón y la asigna a la variable btn
. Luego, establece los atributos , y del botón innerText
. id
El disabled
botón utiliza un detector de eventos de clic que ejecuta una función de devolución de llamada cada vez que hace clic en él. La última línea de la función agrega el botón al div
elemento especificado en el selector
parámetro.
A continuación, creará una nueva función llamada setupButtons()
que se llamará createButton()
dos veces para crear los botones de la aplicación. Comience por crear el botón ¡Responder! de la aplicación:
índice.js
function setupButtons() { // Button to predict createButton('Answer!', 'answer-btn', () = { model.findAnswers(questionText.value, inputText.value).then((answers) = { // Write the answers to the output div as an unordered list. // It uses map create a new list of the answers while adding the list tags. // Then, we use join to concatenate the answers as an array with a line break // between answers. const answersList = answers.map((answer) = `li${answer.text} (confidence: ${answer.score})/li`) .join('br'); answersOutput.innerHTML = `ul${answersList}/ul`; }).catch((e) = console.log(e)); }, '#answer-button', true);}
El primer botón que crea la función es el que activa las predicciones. Sus dos primeros argumentos, innerText
y id
, son el texto del botón y el identificador que desea asignar al botón. El tercer argumento es la devolución de llamada del receptor (explicado a continuación). El cuarto argumento, selector
, es el id del div donde desea agregar el botón ( #answer-button
), y el quinto argumento, disabled
, se establece en true
, lo que deshabilita el botón (para evitar predecir antes de que la aplicación cargue el modelo).
La función de devolución de llamada del receptor es una función que se ejecuta una vez que hace clic en el botón ¡Responder!. Una vez que se hace clic, la función de devolución de llamada primero llama a la función del modelo entrenado previamente findAnswers()
. (Para obtener más información sobre la findAnswers()
función, consulte la documentación del producto ). findAnswers()
usa como argumentos el pasaje de entrada (leer desde questionText
) y la pregunta (leer desde inputText
). Devuelve la salida del modelo en una matriz que se ve de la siguiente manera:
Model's output[ { "text": "New York City", "score": 19.08431625366211, "startIndex": 84, "endIndex": 97 }, { "text": "in New York City", "score": 8.737937569618225, "startIndex": 81, "endIndex": 97 }, { "text": "New York", "score": 7.998648166656494, "startIndex": 84, "endIndex": 92 }, { "text": "York City", "score": 7.5290607213974, "startIndex": 88, "endIndex": 97 }, { "text": "headquartered in New York City", "score": 6.888534069061279, "startIndex": 67, "endIndex": 97 }]
Cada uno de los elementos de la matriz es un objeto de cuatro atributos:
text
:la respuesta.score
:el nivel de confianza del modelo.startIndex
:el índice del primer carácter del pasaje que responde a la pregunta.endIndex
:el índice de los últimos caracteres de la respuesta.
En lugar de mostrar el resultado tal como lo devuelve el modelo, la devolución de llamada utiliza una map()
función que crea una nueva matriz que contiene las respuestas y las puntuaciones del modelo mientras agrega las li
etiquetas HTML de lista. Luego, une los elementos de la matriz con un br
(salto de línea) entre las respuestas y asigna el resultado a para answer
div
mostrarlos como una lista.
A continuación, agregue una segunda llamada a createButton()
. Agregue la parte resaltada a la setupButtons
función debajo de la primera createButton
:
índice.js
function setupButtons() { // Button to predict createButton('Answer!', 'answer-btn', () = { model.findAnswers(questionText.value, inputText.value).then((answers) = { // Write the answers to the output div as an unordered list. // It uses map create a new list of the answers while adding the list tags. // Then, we use join to concatenate the answers as an array with a line break // between answers. const answersList = answers.map((answer) = `li${answer.text} (confidence: ${answer.score})/li`) .join('br'); answersOutput.innerHTML = `ul${answersList}/ul`; }).catch((e) = console.log(e)); }, '#answer-button', true); createButton('DigitalOcean', 'test-case-do-btn', () = { document.getElementById('input-text').value = doText; }, '#test-buttons', false);}
Esta nueva llamada agrega al test-buttons
div
botón que carga el texto de muestra de DigitalOcean que definiste anteriormente en la variable doText
. El primer argumento de la función es la etiqueta del botón ( DigitalOcean ), el segundo argumento es id
, el tercero es la devolución de llamada del receptor que escribe en el área de texto de entrada del pasaje el valor de la doText
variable, el cuarto es selector
, y el último es un false
valor (para evitar deshabilitar el botón).
A continuación, creará una función, denominada init()
, que llama a las otras funciones:
índice.js
async function init() { setupButtons(); answersOutput = document.getElementById('answer'); inputText = document.getElementById('input-text'); questionText = document.getElementById('question'); model = await qna.load(); document.getElementById('answer-btn').disabled = false;}
init()
Comienza llamando a setupButtons()
. Luego, asigna algunos de los elementos HTML de la aplicación a las variables que definiste en la parte superior del script. A continuación, carga el modelo QnA y cambia al false
atributo deshabilitado del answer-btn
botón de respuesta ( ).
Por último, llama init()
:
índice.js
init();
Ya has terminado la aplicación. Para probarla, abre tu navegador web y escribe la ruta absoluta del directorio del proyecto con /index.html
el código adjunto en la barra de direcciones. También puedes abrir tu aplicación de gestión de archivos (como Finder en Mac) y hacer clic en “index.html” para abrir la aplicación web. En este caso, la dirección se vería así your_filepath/tfjs-qna-do/index.html
.
Para encontrar la ruta absoluta, vaya a la terminal y ejecute el siguiente comando desde el directorio del proyecto:
- pwd
Su salida se verá así:
Output/Users/your_filepath/tfjs-qna-do
Después de iniciar la aplicación, deberás esperar unos segundos mientras se descarga y carga el modelo. Sabrás que está listo cuando la aplicación habilite el botón ¡Responder !. Luego, puedes usar el botón de pasaje de prueba ( DigitalOcean
) o escribir tu propio pasaje y luego ingresar una pregunta.
Para probar la aplicación, haz clic en el botón “DigitalOcean”. En el área de entrada de texto, verás el texto de muestra sobre DigitalOcean. En el área de entrada de preguntas, escribe “¿Dónde está la sede de DigitalOcean?”. En el texto, podemos ver que la respuesta es “Nueva York”. Pero, ¿el modelo dirá lo mismo? Haz clic en ¡ Responder! para averiguarlo.
El resultado debería ser similar a esto:
¡Correcto! Aunque hay ligeras diferencias, cuatro de las cinco respuestas indican que la sede de DigitalOcean se encuentra en la ciudad de Nueva York.
En este paso, completaste y probaste la aplicación web. El código JavaScript que escribiste lee el pasaje de entrada y la pregunta y los usa como entrada para el modelo de preguntas y respuestas para responder la pregunta. A continuación, agregarás el código a GitHub.
Paso 3: enviar la aplicación a GitHub
En esta sección, agregará la aplicación web a un repositorio de GitHub. Luego, conectará el repositorio a la plataforma de aplicaciones de DigitalOcean e implementará la aplicación.
Para comenzar, inicia sesión en GitHub. Desde la página principal, haz clic en el botón verde que se encuentra debajo de tu nombre o en el signo más en la esquina superior derecha de la pantalla para crear un nuevo repositorio.
Cualquiera de las opciones lo llevará a la pantalla Crear un nuevo repositorio . En el campo Nombre del repositorio (después de su nombre de usuario), asigne al repositorio el nombre tfjs-qna-do . Seleccione su configuración de privacidad y haga clic en Crear repositorio para crearlo.
Abra una terminal y vaya al directorio del proyecto tfjs-qna-do/
. Allí, ejecute el siguiente comando para crear un nuevo repositorio Git local:
- git init
A continuación, prepara los archivos que quieres rastrear con Git, que en este caso, es todo lo que hay en el directorio:
- git add .
Y comprometerlos:
- git commit -m "initial version of the app"
Cambie el nombre de la rama principal del repositorio a main
:
- git branch -M main
Luego vincula tu repositorio local con el remoto en GitHub:
- git remote add origin git@github.com:your-github-username/tfjs-qna-do.git
Por último, envíe el código base local al repositorio remoto:
- git push -u origin main
Le pedirá que ingrese sus credenciales de GitHub si es la primera vez que envía código.
Una vez que hayas enviado el código, vuelve al repositorio de GitHub y actualiza la página. Deberías ver el código.
En este paso, has enviado el código de tu aplicación web a un repositorio remoto de GitHub. A continuación, vincularás este repositorio a tu cuenta de DigitalOcean e implementarás la aplicación.
Paso 4: Implementación de la aplicación web en la plataforma de aplicaciones DigitalOcean
En esta última sección, implementará la aplicación de preguntas y respuestas en la plataforma de aplicaciones de DigitalOcean ) desde el repositorio de GitHub creado en el paso 3.
Comience iniciando sesión en su cuenta de DigitalOcean. Una vez que haya iniciado sesión, haga clic en el botón verde Crear en la esquina superior derecha y luego en Aplicaciones ; esto lo llevará a la pantalla Crear nueva aplicación :
Aquí, elija GitHub como la fuente donde reside el proyecto.
Si no ha vinculado su cuenta de DigitalOcean con GitHub, se le solicitará que autorice a DigitalOcean a acceder a su GitHub. Después de hacerlo, seleccione el repositorio que desea vincular: tfjs-qna-do .
De regreso en la ventana Plataforma de la aplicación, seleccione el repositorio de la aplicación ( tfjs-qna-do ), la rama desde donde se implementará la aplicación ( main ) y marque la casilla Implementar automáticamente cambios de código ; esta opción garantiza que la aplicación se vuelva a implementar cada vez que envíe código a la rama principal .
En la siguiente pantalla, Configurar la aplicación , utilice los valores de configuración predeterminados. Como paso adicional, si desea cambiar la ruta de las solicitudes HTTP de la aplicación web, por ejemplo, de la ruta predeterminada https://example.ondigitalocean.app/tfjs-qna-do a https://example.ondigitalocean.app/mi ruta personalizada, haga clic en Editar en Rutas HTTP y escribami ruta personalizadaen la entrada RUTAS .
A continuación, deberás nombrar el sitio. Nuevamente, puedes dejar el nombre predeterminado tfjs-qna-do o reemplazarlo por otro.
Al hacer clic en Siguiente, accederá a la última pantalla, Finalizar e iniciar , donde seleccionará el nivel de precios de la aplicación. Dado que la aplicación es una página web estática, App Platform seleccionará automáticamente el plan Starter gratuito. Por último, haga clic en el botón Iniciar aplicación Starter para crear e implementar la aplicación.
Mientras la aplicación está implementada, verás una pantalla similar a esta:
Y una vez implementado, verás:
Para acceder a la aplicación, haga clic en la URL de la aplicación para acceder a su aplicación, que ahora está implementada en la nube.
Conclusión
A medida que se expande el campo del aprendizaje automático, también lo hacen sus casos de uso junto con los entornos y plataformas a los que llega, incluido el navegador web.
En este tutorial, ha creado e implementado una aplicación web que utiliza un modelo preentrenado de TensorFlow.js. Su aplicación web de preguntas y respuestas toma como entrada un pasaje junto con una pregunta y utiliza un modelo BERT preentrenado para responder la pregunta de acuerdo con el pasaje. Después de desarrollar la aplicación, vinculó su cuenta de GitHub con DigitalOcean e implementó la aplicación en App Platform sin necesidad de código adicional.
Como trabajo futuro, podrías activar la implementación automática de la aplicación agregando un cambio y enviándolo a GitHub. También podrías agregar un nuevo pasaje de prueba y formatear el resultado de la respuesta como una tabla para mejorar su legibilidad.
Para obtener más información sobre TensorFlow.js, consulte su documentación oficial .
Deja una respuesta