Uso del modelo Clip de OpenAI para admitir la búsqueda en lenguaje natural en una colección de 70.000 portadas de libros
en un Publicación anterior Hice una pequeña prueba de concepto para ver si podía usar el modelo Clip de OpenAI para crear una búsqueda semántica de libros. En mi opinión, funcionó sorprendentemente bien, pero no pude evitar preguntarme si sería mejor con más datos. La versión anterior utilizaba sólo unos 3,5 mil libros, pero hay millones en la Conjunto de datos de biblioteca abiertay pensé que valía la pena intentar agregar más opciones al espacio de búsqueda.
Sin embargo, el conjunto de datos completo es de aproximadamente 40 GB, y tratar de manejar esa cantidad de datos en mi pequeña computadora portátil, o incluso en una computadora portátil Colab, fue demasiado, por lo que tuve que encontrar una canalización que pudiera administrar el filtrado e incrustar un conjunto de datos más grande. .
TLDR; ¿Mejoró la búsqueda? ¡Creo que sí! Hemos multiplicado 15 los datos, lo que le da a la búsqueda mucho más con qué trabajar. No es perfecto, pero pensé que los resultados fueron bastante interesantes; aunque no he realizado una medida de precisión formal.
Este fue un ejemplo que no pude poner a trabajar sin importar cómo lo expresé en la última iteración, pero funciona bastante bien en la versión con más datos.
Si tienes curiosidad puedes probarlo en colaboración!
En general, fue un viaje técnico interesante, con muchos obstáculos y oportunidades de aprendizaje a lo largo del camino. La pila tecnológica todavía incluye el modelo OpenAI Clip, pero esta vez aprovecho Apache Spark y AWS EMR para ejecutar el proceso de integración.
Esta parecía una buena oportunidad para usar Spark, ya que nos permite paralelizar el cálculo de incrustación.
Decidí ejecutar la canalización en EMR Serverless, que es una oferta de AWS bastante nueva que proporciona un entorno sin servidor para EMR y administra los recursos de escalamiento automáticamente. Sentí que funcionaría bien para este caso de uso, en lugar de poner en marcha un EMR en el clúster EC2, porque este es un proyecto bastante ad hoc, estoy paranoico con los costos del clúster e inicialmente no estaba seguro de qué recursos usaría el trabajo. requeriría. EMR Serverless hace que sea bastante fácil experimentar con los parámetros del trabajo.
A continuación se muestra el proceso completo por el que pasé para que todo estuviera en funcionamiento. Me imagino que hay mejores formas de gestionar ciertos pasos, esto es justo lo que terminó funcionando para mí, así que si tienes ideas u opiniones, ¡compártelas!
Creación de un trabajo de canalización de incorporación con Spark
El paso inicial fue escribir los trabajos de Spark. El proceso completo se divide en dos etapas: la primera toma el conjunto de datos inicial y filtra la ficción reciente (dentro de los últimos 10 años). Esto resultó en alrededor de 250.000 libros y alrededor de 70.000 con imágenes de portada disponibles para descargar e insertar en la segunda etapa.
Primero extraemos las columnas relevantes del archivo de datos sin procesar.
Luego, realice una transformación general de los tipos de datos y filtre todo menos la ficción en inglés con más de 100 páginas.
La segunda etapa toma el conjunto de datos de salida de la primera etapa y ejecuta las imágenes a través del modelo Clip, descargado de Hugging Face. El paso importante aquí es convertir las diversas funciones que necesitamos aplicar a los datos en Spark UDF. El principal de interés es get_image_embedding, que toma la imagen y devuelve la incrustación.
Lo registramos como UDF:
Y llame a esa UDF en el conjunto de datos:
Configurar la base de datos de vectores
Como último paso opcional en el código, podemos configurar una base de datos vectorial, en este caso Milvus, para cargar y consultar. Tenga en cuenta que no hice esto como parte del trabajo en la nube para este proyecto, ya que seleccioné mis incorporaciones para usarlas sin tener que mantener un clúster en funcionamiento indefinidamente. Sin embargo, es bastante sencillo configurar Milvus y cargar un Spark Dataframe en una colección.
Primero, cree una colección con un índice en la columna de incrustación de imágenes que la base de datos pueda usar para la búsqueda.
Luego podemos acceder a la colección en el script Spark y cargar las incrustaciones desde el marco de datos final.
Finalmente, podemos simplemente incrustar el texto de búsqueda con el mismo método utilizado en la UDF anterior y acceder a la base de datos con las incrustaciones. La base de datos hace el trabajo pesado de encontrar las mejores coincidencias.
Configurar la canalización en AWS
Requisitos previos
Ahora hay que realizar un poco de configuración para ejecutar estos trabajos en EMR Serverless.
Como requisitos previos necesitamos:
- Un depósito de S3 para scripts de trabajo, entradas y salidas, y otros artefactos que el trabajo necesita
- Un rol de IAM con permisos de lectura, lista y escritura para S3, así como lectura y escritura para Glue.
- Una política de confianza que permite que los trabajos de EMR accedan a otros servicios de AWS.
Hay excelentes descripciones de las políticas de roles y permisos, así como un resumen general de cómo comenzar a utilizar EMR Serverless en los documentos de AWS aquí: Introducción a Amazon EMR sin servidor
A continuación tenemos que configurar un EMR Studio: Crear un estudio EMR
Acceder a la web a través de una puerta de enlace de Internet
Otra parte de la configuración que es específica de este trabajo en particular es que debemos permitir que el trabajo acceda a Internet, lo cual la aplicación EMR no puede hacer de forma predeterminada. Como vimos en el script, el trabajo necesita acceder tanto a las imágenes para incrustar como a Hugging Face para descargar las configuraciones y los pesos del modelo.
Nota: Es probable que existan formas más eficientes de manejar el modelo que descargarlo a cada trabajador (difundirlo, almacenarlo en algún lugar local del sistema, etc.), pero en este caso, para una sola ejecución de los datos, esto es suficiente.
De todos modos, permitir que la máquina en la que se ejecuta el trabajo Spark acceda a Internet requiere una VPC con subredes privadas que tengan puertas de enlace NAT. Toda esta configuración comienza accediendo a la interfaz AWS VPC -> Crear VPC -> seleccionar VPC y más -> seleccionar la opción para al menos en la puerta de enlace NAT -> hacer clic en Crear VPC.
La VPC tarda unos minutos en configurarse. Una vez hecho esto, también debemos crear un grupo de seguridad en la interfaz del grupo de seguridad y adjuntar la VPC que acabamos de crear.
Creación de la aplicación EMR Serverless
¡Ahora la aplicación EMR Serverless que enviará el trabajo! La creación y el lanzamiento de un estudio EMR deberían abrir una interfaz de usuario que ofrezca algunas opciones, incluida la creación de una aplicación. En la interfaz de usuario de creación de la aplicación, seleccione Usar configuración personalizada -> Configuración de red. Aquí es donde entran en juego la VPC, las dos subredes privadas y el grupo de seguridad.
Construyendo un entorno virtual
Finalmente, el entorno no viene con muchas bibliotecas, por lo que para agregar dependencias adicionales de Python podemos usar Python nativo o crear y empaquetar un entorno virtual: Uso de bibliotecas de Python con EMR Serverless.
Seguí la segunda ruta, y la forma más sencilla de hacerlo es con Docker, ya que nos permite crear el entorno virtual dentro de la distribución de Amazon Linux que ejecuta los trabajos de EMR (hacerlo en cualquier otra distribución o sistema operativo puede resultar increíblemente complicado). .
Otra advertencia: tenga cuidado de elegir la versión de EMR que corresponda a la versión de Python que está utilizando y elija también las versiones de los paquetes en consecuencia.
El proceso Docker genera el entorno virtual comprimido como pyspark_dependencies.tar.gz, que luego va al depósito S3 junto con los scripts del trabajo.
Luego podemos enviar este entorno empaquetado junto con el resto de las configuraciones del trabajo de Spark.
¡Lindo! Tenemos el guión del trabajo, las dependencias ambientales, las puertas de enlace y una aplicación EMR, ¡podemos enviar el trabajo! ¡No tan rapido! Ahora viene la verdadera diversión: el ajuste Spark.
Como se mencionó anteriormente, EMR Serverless se escala automáticamente para manejar nuestra carga de trabajo, lo que normalmente sería excelente, pero descubrí (obviamente en retrospectiva) que no fue útil para este caso de uso en particular.
Unas pocas decenas de miles de registros no constituyen en absoluto “grandes datos”; Spark quiere terabytes de datos para procesar, y solo estaba enviando esencialmente unos pocos miles de URL de imágenes (ni siquiera las imágenes mismas). Si se lo deja solo, EMR Serverless enviará el trabajo a un nodo para que lo realice en un solo subproceso, anulando por completo el propósito de la paralelización.
Además, si bien los trabajos de incrustación toman una cantidad relativamente pequeña de datos, los expanden significativamente, ya que las incrustaciones son bastante grandes (512 en el caso de Clip). Incluso si deja ese nodo en funcionamiento durante unos días, se quedará sin memoria mucho antes de que termine de procesar el conjunto completo de datos.
Para ejecutarlo, experimenté con algunas propiedades de Spark para poder usar máquinas grandes en el clúster, pero dividí los datos en particiones muy pequeñas para que cada núcleo tuviera solo un poco para trabajar y generar:
- spark.executor.memory: cantidad de memoria a utilizar por proceso ejecutor
- spark.sql.files.maxPartitionBytes: la cantidad máxima de bytes para empaquetar en una sola partición al leer archivos.
- spark.executor.cores: la cantidad de núcleos que se usarán en cada ejecutor.
Tendrá que modificarlos dependiendo de la naturaleza particular de sus datos, y la incrustación aún no es un proceso rápido, pero fue capaz de trabajar con mis datos.
Conclusión
como con mi Publicación anterior Los resultados ciertamente no son perfectos y de ninguna manera reemplazan las sólidas recomendaciones de libros de otros humanos. Pero dicho esto, hubo algunas respuestas acertadas a varias de mis búsquedas, lo cual me pareció bastante interesante.
Si quieres jugar con la aplicación tú mismo, está en colaboracióny el código completo de la canalización está en GitHub!