1. Introducción
(He publicado el código fuente en este repositorio de github).
La legibilidad es la facilidad con la que un lector puede comprender un texto. Depende de la complejidad del vocabulario de ese texto, de la longitud de las frases, de la sintaxis… etc. La legibilidad se usa por ejemplo en el colegio para que cada alumno trabaje con textos cada vez más complejos, acordes a su curso/progresión. Existen muchas fórmulas 🔗 para calcular la legibilidad siguiendo criterios tradicionales (sin IA).
Sin embargo, en este artículo nos vamos a inspirar en un reto de Kaggle 🔗 para calcular la legibilidad de un texto usando inteligencia artificial. Concretamente usaremos Natural Language Processing (NLP) y Transformers.
Una vez entrenado nuestro modelo de red neuronal, nos interesará «publicarlo«, para que nosotros mismos y terceros puedan comprobar si funciona correctamente.
Cuando pensé en escribir este artículo, una forma barata y fácil de publicar un modelo entrenado era usando AWS Lambda y API Gateway (es decir, una arquitectura Serverless). Pero vamos a publicarlo usando el nuevo servicio Amazon SageMaker Serverless Inference, que se presentó 🔗 en diciembre 2021 (re:Invent 2021).
2. El dataset
Usaremos el dataset del reto de Kaggle 🔗. Tiene la siguiente estructura:
Tiene 2.834 filas. Para cada fila, la columna «excerpt» contiene un ejemplo de texto y la columna «target» su puntuación de legibilidad (es la columna que queremos predecir). El resto de columnas no las voy a usar. Existe una columna «standard_error» porque los valores de legibilidad del dataset se han obtenido haciendo la media entre la puntuación dada manualmente por expertos, de modo que el «standard error» nos dice cuánto se han desviado esos expertos con respecto a la media.
Lo primero que hacemos es visualizar los datos, para ver qué «forma» tienen 👀.
Un histograma de los valores de target, nos dice que toma valores entre -4 y +2 aproximadamente, con esta distribución. Los textos más fáciles de leer (más legibles) tienen target cercano a +2; mientras que los textos más complejos tienen target más próximo a -4:
En la siguiente gráfica comparamos la longitud de los textos (en caracteres) con el target, sin aparente correlación:
(Tampoco vi correlación al comparar el nº de palabras con el target; o el nº de tokens con el target).
Al comparar el target con el error, vemos que el error es ligeramente mayor en los extremos. También vemos que hay un posible dato anómalo, que tiene target=standard_error=0. Pero creo que dicha fila no es un error sino un texto de referencia, que por consenso tomó target=0 y que los expertos usaban como ayuda para puntuar al resto de textos. Por tanto, no eliminaré dicho dato:
Y se puede hacer un análisis mucho más profundo del dataset. Por ejemplo, puedes calcular cuáles son las palabras menos frecuentes, o ver si hay correlación entre los textos fáciles y cómo usan de palabras del «Simple English 🔗«. También puedes ejecutar las fórmulas tradicionales de cálculo de la legibilidad, o contar el nº de frases de cada texto y ver si hay correlación con la columna target. La visualización de las correlaciones la pongo a modo curiosidad, como ejemplo de que se puede analizar el dataset todo lo que uno quiera:
3. Entrenamiento del modelo
En el repositorio 🔗 encontrarás el cuaderno de Jupyter que he usado para el entrenamiento. Puedes ejecutarlo en Amazon SageMaker 🔗 (como explico a continuación), en el nuevo SageMaker Studio Lab 🔗, en Google Colab o en otro entorno que tengas con Jupyter instalado y con GPU. La GPU es importante porque vamos a utilizar Transformers (una arquitectura de redes neuronales), que consumen muchos recursos de cómputo y memoria durante el entrenamiento.
El último paso de la parte de entrenamiento del cuaderno jupyter consiste en almacenar el modelo recién entrenado en un bucket de S3. En el ejemplo, ocupa aproximadamente 1GB comprimido en .tar.gz.
Para este proyecto he utilizado la librería 🤗 Transformers de Hugging Face 🔗, a través de la librería Simple Transformers 🔗. Esta última me pareció más sencilla de utilizar cuando la conocí, añadía integración instantánea con Weights & Biases 🔗 (librería para llevar control de los experimentos que realizas, qué hiperparámetros funcionan mejor; MLOps).
El uso de las 3 librerías es uno de los motivos por los cuales el listado de dependencias «no cabe» en una función AWS Lambda sin hacer nada raro. Por eso opto por utilizar Amazon SageMaker Serverless Inference (en lugar de AWS Lambda). Si volviera a empezar este proyecto, comprobaría cuánto peso se ahorra quitando Simple Transformers y W&B.
Utilizaré un modelo preentrenado de Transformer, el cual afinamos en el jupyter notebook con el dataset. De todos los modelos preentrenados que probé, los mejores resultados se consiguen con «roberta-large». Puedes usar «roberta-base» para conseguir resultados ligeramente inferiores pero consumiendo mucho menos tiempo y menos memoria.
Si utilizas Amazon SageMaker para ejecutar el jupyter notebook, recuerda estos 3 pasos:
1. Escoger un tipo de instancia de cómputo que tenga GPU (por ejemplo: ml.g4dn.xlarge) y un volumen con suficiente espacio (por ejemplo: 50GB).
2. Configurar un rol IAM, para que la instancia de SageMaker tenga permisos de escritura en el bucket S3.
3. Detener la instancia de cómputo cuando termines el entrenamiento (te facturan por cada minuto que esté encendida).
4. Inferencia (publicamos el modelo entrenado)
Hasta el mes pasado, una forma sencilla de publicar un modelo entrenado con SageMaker era crear un endpoint 🔗 y tener una instancia. Pero esto suponía tener en ejecución una instancia 24×7, independientemente del nº de invocaciones que realizaras a dicho endpoint. Esto es caro si no vamos a darle un uso continuado. Pero desde diciembre 2021 existe la opción Serverless, que ya no requiere un servidor 24×7. A continuación vamos a probar esta opción.
El jupyter notebook continúa, después de la sección del entrenamiento y después de la sección que envía el modelo entrenado a S3, con la sección de inferencia. En esta parte está el código que se encarga de configurar el endpoint (del nuevo tipo serverless), crear el contenedor a partir de una imagen (y en el que descomprime el modelo preentrenado), y finalmente crea el endpoint.
En el cuaderno de jupyter también hay una inferencia que puedes ejecutar para comprobar que la predicción del modelo recién entrenado. Dicha inferencia se ejecuta en la instancia que has creado para el entrenamiento, esto no es lo óptimo, ya que durante el entrenamiento se necesitan muchos más recursos de hardware que durante la inferencia. Por eso, para la inferencia queremos utilizar otro hardware más económico, una solución serverless en este caso.
La parte de configuración de Sagemaker Serverless Inference está basada en la explicación de Julien Simon 🔗 (Chief Evangelist @ Hugging Face).
A continuación, se realiza una invocación al endpoint. En el notebook actual me está dando el siguiente error, probablemente porque el modelo es de más de 512MB, como explican en este hilo 🔗. Me queda pendiente probar con modelos más pequeños para descartar que sea otro el problema. En CloudWatch aparece el error python: can’t open file ‘/usr/local/bin/deep_learning_container.py’: [Errno 13] Permission denied.
2022-01-10: He corregido un error en la creación del fichero `best_model.tar.gz` (¡Gracias @supercoco9 por el soporte!). Aún así, ahora la invocación da otro error. He probado a cambiar el Endpoint Serverless por un Endpoint no Serverless y el error era el mismo. Finalmente he llegado a la conclusión de que el modelo que guarda la librería SimpleTransformers no es compatible con el modelo que lee la librería Transformers (HuggingFace). Existen 2 posibles soluciones:
- En lugar de utilizar una imagen de contenedor de HuggingFace, crear una imagen personalizada para el contenedor de inferencia, que cargue el modelo y realice la predicción con la librería SimpleTransformers. Documentación aquí 🔗.
- (más difícil) Reimplementar el entrenamiento del modelo para usar la librería Transformers (HuggingFace), en lugar de SimpleTransformers.
Y al final del notebook se liberan los recursos creados para la inferencia (se elimina el modelo, la configuración de endpoint y el endpoint).
Importante: recuerda que al terminar también tendrás que eliminar:
- El modelo entrenado que almacenaste en el bucket de S3.
- La instancia de notebook, que creaste en la fase de entrenamiento y que has utilizado para ejecutar el cuaderno jupyter. Antes de eliminarla, descarga el fichero *.ipynb si has realizado cambios que quieras conservar.
Referencias:
SageMaker Serverless Inference (Preview) – Documentación oficial 🔗
Vídeo AWS re:Invent 2021 – {New Launch} Amazon SageMaker serverless inference (Preview) 🔗
Julien Simon (Chief Evangelist @ Hugging Face) explicando SageMaker Serverless Inference 🔗