1od9dpkakn590f6aba7d7hg.png

Extraer y estructurar elementos de texto con alta precisión utilizando modelos pequeños.

Imagen generada por una IA por el autor

En esta publicación, presentaré un paradigma desarrollado recientemente en Anaplan para extraer información temporal de texto en lenguaje natural, como parte de un proyecto NLQ (consulta en lenguaje natural). Si bien me centraré en la extracción de tiempo, el paradigma es versátil y aplicable para analizar varios textos no estructurados y extraer diversos patrones de información. Esto incluye reconocimiento de entidades con nombre, conversión de texto a SQL, extracción de cantidades y más.

El núcleo del paradigma radica en la construcción de una tubería flexible, que proporciona la máxima flexibilidad, facilitando el ajuste de un modelo para extraer el significado de cualquier expresión concebible en el lenguaje. Se basa en un modelo de aprendizaje profundo (transformadores), pero para nosotros logró una precisión del 99,98%, lo cual es relativamente raro en los métodos de aprendizaje automático. Además, no utiliza LLM (modelos de lenguaje grande), de hecho, requiere un modelo transformador mínimo. Esto produce un modelo de aprendizaje automático compacto y adaptable, que muestra la precisión de los sistemas basados ​​en reglas.

Para aquellos que buscan extraer tiempo, valor numérico o número de teléfono, la herramienta de Facebook Paquete patito ofrece una solución basada en reglas. Sin embargo, si Duckling no cumple con sus requisitos o está ansioso por explorar un nuevo paradigma de aprendizaje automático, siga leyendo.

¿Pueden los LLM captar el significado?

Los LLM, a pesar de sus capacidades, enfrentan desafíos al analizar este tipo de frases y extraer su significado de manera integral. Considere la expresión «las primeras 15 semanas del año pasado». Convertir esto en un rango de fechas requiere que el modelo determine el año actual, reste uno y calcule la posición de la semana 15 a medida que se ajusta a los años bisiestos. Los modelos de lenguaje no se construyeron para este tipo de cálculo.

En mi experiencia, los LLM pueden generar con precisión el rango de fechas correcto entre el 90% y el 95% de las veces, pero tienen dificultades con el 5% al ​​10% restante, sin importar las técnicas de indicación que utilice. Sin mencionar: los LLM consumen muchos recursos y son lentos.

Afortunadamente, siguiendo tres principios, los transformadores compactos pueden realizar la tarea con éxito.

  1. Separe la extracción de información de la deducción lógica.
  2. Genere automáticamente un conjunto de datos utilizando patrones estructurados.
  3. Limite la IA generativa a la estructura requerida.

En esta publicación, cubriré los dos primeros, ya que el tercero lo cubrí en una publicación anterior.

Separar la extracción de información de la deducción lógica.

El primer principio es garantizar que la función del modelo de lenguaje sea extraer información de texto libre, en lugar de hacer deducciones lógicas: las deducciones lógicas se pueden implementar fácilmente en el código.

Considere la frase: «¿Cuántas películas se estrenaron hace dos años?» La tarea del modelo de lenguaje debería ser identificar que el año relevante es: this_year - 2, sin calcular el año real (lo que significa que no necesita saber el año actual). Su objetivo es analizar el significado y estructurar el lenguaje no estructurado. Una vez extraída esa fórmula, podemos implementar su cálculo en código.

Para que esto funcione, introducimos un lenguaje de tiempo estructurado (STL) capaz de expresar elementos de tiempo. Por ejemplo, «en 2020» se traduce como «TIEMPO.año==2020» y «dentro de tres meses» se convierte en «AHORA.mes==3». Si bien no se detalla aquí todo el lenguaje STL, debería ser relativamente intuitivo: puede hacer referencia a atributos como año, trimestre y mes para un tiempo absoluto o relativo a AHORA. La traducción de “las últimas 12 semanas del año pasado” es “AHORA.año==-1 Y HORA.semana>=-12”

Al eliminar cualquier deducción o cálculo lógico de la tarea, le quitamos una gran carga al modelo de lenguaje y le permitimos centrarse en la extracción de información. Esta división del trabajo mejorará significativamente su precisión. Una vez completado el proceso de traducción, es sencillo desarrollar código para un analizador que lea el lenguaje estructurado y recupere el rango de fechas necesario.

Dado que se trata de una tarea de traducción, del lenguaje natural a STL, utilizamos un transformador codificador-decodificador. Usamos el Modelo de Bart de Hugging Faceque se puede ajustar fácilmente para esta tarea.

Pero, ¿cómo obtenemos los datos para entrenar el modelo?

Generar automáticamente un conjunto de datos usando patrones estructurados

Dado que no existe un conjunto de datos de entrenamiento para esta tarea de traducción, debemos generarlo nosotros mismos. Esto se hizo siguiendo estos pasos:

Paso uno: Escriba funciones para asignar objetos de fecha y hora tanto a formatos de “lenguaje natural” como STL:

def since_year(datetime):
free_text = f“since {datetime.year}”
answer = f”TIME.year >= {datetime.year}”
return free_text, answer

def half_literal(datetime):
free_text = datetime.strftime(“%-d, %B %Y”)
answer = f”TIME.date >= {datetime}”
return free_text, answer

def until_quarter_year(datetime):
q = datetime.month//3
free_text = f”until Q{q}-{datetime.year}”
answer = f”TIME.year=={datetime.year} AND TIME.quarter=={q}”

Dado un objeto de fecha y hora, estas funciones devuelven una tupla de texto libre y su STL correspondiente, por ejemplo: “desde 2020”, “TIME.year >= 2020”.

Segundo paso: Muestreo de una función aleatoria y muestreo de una fecha aleatoria dentro de un rango específico:

date = np.random.choice(pd.date_range('1970/1/1', '2040/12/31'))

ahora inserte la fecha y hora en la función.

Paso tres: agregue el texto libre a una pregunta aleatoria (podemos generar preguntas fácilmente al azar o extraerlas de algún conjunto de datos de preguntas, su calidad y significado no son muy importantes).

Con esta canalización, podemos generar rápidamente miles de pares de texto-STL, por ejemplo:

  • “¿Cuál fue el crecimiento del PIB en el segundo trimestre de 2019?”, “TIME.trimestre==2 AND TIME.year==2019”
  • “Desde 2017, ¿quién ganó más premios Oscar?”, “TIME.year>=2017”
  • “¿Quién era el presidente el 3 de mayo de 2020?”, “TIME.date==2020/05/03”

Este enfoque garantiza flexibilidad para agregar nuevos patrones sin esfuerzo. Si encuentra una expresión de tiempo que no está cubierta por una de estas funciones (por ejemplo, “En N años”), puede escribir una función que genere ejemplos para este patrón en segundos.

En la práctica, podemos optimizar aún más la eficiencia del código. En lugar de funciones separadas para cada patrón como “desde 2020” y “hasta 2020”, podemos muestrear aleatoriamente palabras conectivas como “desde”, “hasta”, “en”, etc. Este lote inicial de funciones puede requerir algo de tiempo para desarrollarse , pero puedes escalar rápidamente a cientos de patrones. Posteriormente, abordar cualquier expresión faltante se vuelve trivial, ya que el proceso ya está establecido. Con unas pocas iteraciones, se pueden cubrir casi todas las expresiones relevantes.

Además, no necesitamos cubrir todas las expresiones.: Dado que el modelo de transformador que utilizamos está previamente entrenado en un enorme corpus de texto, se generalizará a partir de los patrones proporcionados a otros nuevos.

Finalmente, podemos usar un LLM para generar más ejemplos.. Simplemente pregunte a un LLM:

Hey, what's another way to write "What was the revenue until Aug 23"

Y puede regresar:

"How much did we make before August 2023".

Este proceso de aumento de datos también se puede automatizar: enviando numerosos ejemplos a un LLM, agregando así variedad a nuestro conjunto de datos. Dado que el papel del LLM es únicamente la creación de conjuntos de datos, las consideraciones de costo y velocidad se vuelven intrascendentes.

Combinando la flexibilidad de agregar nuevos patrones, la generalización del modelo previamente entrenado y el aumento de datos mediante un LLM, podemos cubrir de manera efectiva casi cualquier expresión.

El principio final de este paradigma es restringir la IA generativa para que produzca solo consultas STL, asegurando el cumplimiento de la estructura requerida. Se discutió el método para lograr esto, así como un método para optimizar el proceso de tokenización. en una publicación anterior.

Al cumplir con estos tres principios, logramos una precisión impresionante del 99,98 % en nuestro conjunto de datos de prueba. Además, este paradigma nos dio la flexibilidad de abordar rápidamente expresiones de tiempo nuevas y sin soporte.

Resumen

Los modelos de lenguaje grandes (LLM) no siempre son la solución óptima para las tareas lingüísticas. Con el enfoque correcto, los modelos de transformadores menos profundos pueden extraer eficientemente información del lenguaje natural con alta precisión y flexibilidad, en un tiempo y costo reducidos.

Los principios clave a recordar son:

  1. Centrar el modelo únicamente en la extracción de información, evitando deducciones lógicas complejas. Esto puede requerir generar un lenguaje mediador e implementar un analizador y una deducción lógica en el código.
  2. Establecer una canalización para generar un conjunto de datos y entrenar un modelo, de modo que agregar nuevas funciones (nuevos patrones de lenguaje) sea sencillo y rápido. Este proceso puede incluir el uso de un LLM, agregando más variedad al conjunto de datos.
  3. Limitar la generación del modelo a las limitaciones de un lenguaje estructurado.

Si bien esta publicación se centró en extraer elementos de tiempo, el paradigma se aplica a extraer cualquier información de texto libre y estructurarla en varios formatos. Con este paradigma, se puede lograr la precisión de un motor basado en reglas, con la flexibilidad de un modelo de aprendizaje automático.