Generando Texto Guiado con B煤squeda Restringida de Haz en 馃 Transformers

'Generando Texto Guiado con B煤squeda Restringida de Haz en Transformers 馃'

Introducci贸n

Esta publicaci贸n de blog asume que el lector est谩 familiarizado con los m茅todos de generaci贸n de texto utilizando las diferentes variantes de b煤squeda de haz, como se explica en la publicaci贸n de blog: “C贸mo generar texto: utilizando diferentes m茅todos de decodificaci贸n para la generaci贸n de lenguaje con Transformers”

A diferencia de la b煤squeda de haz ordinaria, la b煤squeda de haz restringida nos permite tener control sobre la generaci贸n de texto. Esto es 煤til porque a veces sabemos exactamente lo que queremos dentro de la salida. Por ejemplo, en una tarea de Traducci贸n Autom谩tica Neuronal, podr铆amos saber qu茅 palabras deben incluirse en la traducci贸n final con una b煤squeda en el diccionario. A veces, las salidas de generaci贸n que son casi igualmente posibles para un modelo de lenguaje pueden no ser igualmente deseables para el usuario final debido al contexto particular. Ambas situaciones podr铆an resolverse permitiendo a los usuarios indicar al modelo qu茅 palabras deben incluirse en la salida final.

Por qu茅 es dif铆cil

Sin embargo, este es en realidad un problema muy complejo. Esto se debe a que la tarea requiere que forcemos la generaci贸n de ciertas subsecuencias en alg煤n lugar de la salida final, en alg煤n momento durante la generaci贸n.

Supongamos que queremos generar una oraci贸n S que debe incluir la frase p 1 = { t 1 , t 2 } p_1=\{ t_1, t_2 \} p 1 鈥 = { t 1 鈥 , t 2 鈥 } con los tokens t 1 , t 2 t_1, t_2 t 1 鈥 , t 2 鈥 en orden. Definamos la oraci贸n esperada S S S como:

S e x p e c t e d = { s 1 , s 2 , . . . , s k , t 1 , t 2 , s k + 1 , . . . , s n } S_{expected} = \{ s_1, s_2, …, s_k, t_1, t_2, s_{k+1}, …, s_n \} S e x p e c t e d 鈥 = { s 1 鈥 , s 2 鈥 , . . . , s k 鈥 , t 1 鈥 , t 2 鈥 , s k + 1 鈥 , . . . , s n 鈥 }

El problema es que la b煤squeda de haz genera la secuencia token por token . Aunque no es del todo exacto, se puede pensar en la b煤squeda de haz como la funci贸n B ( s 0 : i ) = s i + 1 B(\mathbf{s}_{0:i}) = s_{i+1} B ( s 0 : i 鈥 ) = s i + 1 鈥 , donde se analiza la secuencia actualmente generada de tokens desde 0 0 0 hasta i i i y luego se predice el siguiente token en i + 1 i+1 i + 1 . Pero 驴c贸mo puede esta funci贸n saber, en un paso arbitrario i < k i < k i < k , que los tokens deben generarse en alg煤n paso futuro k k k ? O cuando est谩 en el paso i = k i=k i = k , 驴c贸mo puede saber con certeza que este es el mejor momento para forzar los tokens, en lugar de alg煤n paso futuro i > k i>k i > k ?

驴Y qu茅 sucede si tiene m煤ltiples restricciones con requisitos variables? 驴Qu茅 sucede si desea forzar la frase p 1 = { t 1 , t 2 } p_1=\{t_1, t_2\} p 1 鈥 = { t 1 鈥 , t 2 鈥 } y tambi茅n la frase p 2 = { t 3 , t 4 , t 5 , t 6 } p_2=\{ t_3, t_4, t_5, t_6\} p 2 鈥 = { t 3 鈥 , t 4 鈥 , t 5 鈥 , t 6 鈥 } ? 驴Qu茅 sucede si desea que el modelo elija entre las dos frases? 驴Qu茅 sucede si queremos forzar la frase p 1 p_1 p 1 鈥 y forzar solo una frase entre la lista de frases { p 21 , p 22 , p 23 } \{p_{21}, p_{22}, p_{23}\} { p 2 1 鈥 , p 2 2 鈥 , p 2 3 鈥 } ?

Los ejemplos anteriores son casos de uso muy razonables, como se mostrar谩 a continuaci贸n, 隆y la nueva funci贸n de b煤squeda restringida de haz permite todos ellos!

Esta publicaci贸n repasar谩 r谩pidamente lo que la nueva caracter铆stica de b煤squeda restringida de haz puede hacer por ti y luego profundizar谩 en c贸mo funciona internamente.

Ejemplo 1: Forzar una palabra

Supongamos que estamos intentando traducir "How old are you?" al alem谩n.

"Wie alt bist du?" es lo que dir铆as en un entorno informal, y "Wie alt sind Sie?" es lo que dir铆as en un entorno formal.

Y dependiendo del contexto, es posible que queramos una forma de formalidad en lugar de la otra, pero 驴c贸mo le decimos al modelo eso?

As铆 es como har铆amos la traducci贸n de texto en el entorno de b煤squeda de haz tradicional.

!pip install -q git+https://github.com/huggingface/transformers.git

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM

tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")

encoder_input_str = "translate English to German: How old are you?"

input_ids = tokenizer(encoder_input_str, return_tensors="pt").input_ids

outputs = model.generate(
    input_ids,
    num_beams=10,
    num_return_sequences=1,
    no_repeat_ngram_size=1,
    remove_invalid_values=True,
)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

Output:
----------------------------------------------------------------------------------------------------
Wie alt bist du?

Pero, 驴qu茅 pasa si sabemos que queremos una salida formal en lugar de una informal? 驴Qu茅 pasa si sabemos por conocimiento previo lo que la generaci贸n debe incluir y podemos inyectarlo en la generaci贸n?

Lo siguiente es lo que ahora es posible con el argumento de palabra clave force_words_ids para model.generate() :

tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")

encoder_input_str = "translate English to German: How old are you?"

force_words = ["Sie"]

input_ids = tokenizer(encoder_input_str, return_tensors="pt").input_ids
force_words_ids = tokenizer(force_words, add_special_tokens=False).input_ids

outputs = model.generate(
    input_ids,
    force_words_ids=force_words_ids,
    num_beams=5,
    num_return_sequences=1,
    no_repeat_ngram_size=1,
    remove_invalid_values=True,
)


print("Output:\n" + 100 * '-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

Output:
----------------------------------------------------------------------------------------------------
Wie alt sind Sie?

Como puedes ver, pudimos guiar la generaci贸n con conocimiento previo sobre nuestra salida deseada. Anteriormente tendr铆amos que generar una serie de posibles salidas y luego filtrar las que se ajusten a nuestros requisitos. Ahora podemos hacerlo en la etapa de generaci贸n.

Ejemplo 2: Restricciones disyuntivas

Mencionamos anteriormente un caso de uso en el que sabemos qu茅 palabras queremos que se incluyan en la salida final. Un ejemplo de esto podr铆a ser usar una b煤squeda en un diccionario durante la traducci贸n de m谩quina neuronal.

Pero, 驴qu茅 pasa si no sabemos qu茅 formas de palabras usar, donde queremos que salidas como ["raining", "rained", "rains", ...] sean igualmente posibles? En un sentido m谩s general, siempre hay casos en los que no queremos la palabra exacta textualmente, letra por letra, y podr铆amos estar abiertos a otras posibilidades relacionadas tambi茅n.

Las restricciones que permiten este comportamiento son las restricciones disyuntivas, que permiten al usuario ingresar una lista de palabras, cuyo prop贸sito es guiar la generaci贸n de modo que la salida final contenga al menos una de las palabras de la lista.

Aqu铆 tienes un ejemplo que utiliza una combinaci贸n de los dos tipos de restricciones anteriores:

from transformers import GPT2LMHeadModel, GPT2Tokenizer

model = GPT2LMHeadModel.from_pretrained("gpt2")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")

force_word = "scared"
force_flexible = ["scream", "screams", "screaming", "screamed"]

force_words_ids = [
    tokenizer([force_word], add_prefix_space=True, add_special_tokens=False).input_ids,
    tokenizer(force_flexible, add_prefix_space=True, add_special_tokens=False).input_ids,
]

starting_text = ["The soldiers", "The child"]

input_ids = tokenizer(starting_text, return_tensors="pt").input_ids

outputs = model.generate(
    input_ids,
    force_words_ids=force_words_ids,
    num_beams=10,
    num_return_sequences=1,
    no_repeat_ngram_size=1,
    remove_invalid_values=True,
)


print("Output:\n" + 100 * '-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
print(tokenizer.decode(outputs[1], skip_special_tokens=True))

Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.


Output:
----------------------------------------------------------------------------------------------------
The soldiers, who were all scared and screaming at each other as they tried to get out of the
The child was taken to a local hospital where she screamed and scared for her life, police said.

Como puedes ver, la primera salida utiliz贸 "screaming", la segunda salida utiliz贸 "screamed", y ambas utilizaron "scared" textualmente. La lista para elegir de ["screaming", "screamed", ...] no tiene que ser formas de palabras; esto puede satisfacer cualquier caso de uso donde solo necesitemos una palabra de una lista.

B煤squeda tradicional por haz

A continuaci贸n se muestra un ejemplo de b煤squeda tradicional por haz, tomado de una publicaci贸n anterior en el blog:

A diferencia de la b煤squeda greedy, la b煤squeda por haz funciona manteniendo una lista m谩s larga de hip贸tesis. En la imagen anterior, hemos mostrado tres posibles tokens siguientes en cada paso posible de la generaci贸n.

Aqu铆 hay otra forma de ver el primer paso de la b煤squeda por haz para el ejemplo anterior, en el caso de num_beams=3:

En lugar de elegir solo "The dog" como lo har铆a una b煤squeda greedy, una b煤squeda por haz permitir铆a considerar tambi茅n "The nice" y "The car".

En el siguiente paso, consideramos los posibles tokens siguientes para cada una de las tres ramas que creamos en el paso anterior.

Aunque terminamos considerando significativamente m谩s salidas que num_beams, las reducimos a num_beams al final del paso. No podemos seguir creando ramas indefinidamente, ya que el n煤mero de beams que tendr铆amos que tener en cuenta ser铆a de la forma beams n \text{beams}^{n} beams n para n n n pasos, lo cual se vuelve muy grande muy r谩pidamente (10 10 1 0 beams despu茅s de 10 10 1 0 pasos son 10,000,000,000 10,000,000,000 1 0 , 0 0 0 , 0 0 0 , 0 0 0 beams).

Para el resto de la generaci贸n, repetimos el paso anterior hasta que se cumpla el criterio de finalizaci贸n, como generar el token <eos> o alcanzar max_length, por ejemplo. Expandir, clasificar, reducir y repetir.

La b煤squeda por haz constre帽ida intenta cumplir las restricciones inyectando los tokens deseados en cada paso de la generaci贸n.

Supongamos que estamos tratando de forzar la frase "is fast" en la salida generada.

En el entorno de b煤squeda por haz tradicional, encontramos los k tokens siguientes m谩s probables en cada rama y los agregamos para su consideraci贸n. En el entorno constre帽ido, hacemos lo mismo pero tambi茅n agregamos los tokens que nos acercar谩n m谩s a cumplir nuestras restricciones. Aqu铆 hay una demostraci贸n:

Adem谩s de los tokens siguientes de alta probabilidad habituales como "dog" y "nice", forzamos el token "is" para acercarnos m谩s a cumplir nuestra restricci贸n de "is fast".

Para el siguiente paso, los candidatos ramificados a continuaci贸n son en su mayor铆a los mismos que los de la b煤squeda por haz tradicional. Pero, al igual que en el ejemplo anterior, la b煤squeda por haz constre帽ida agrega a los candidatos existentes forzando las restricciones en cada nueva rama:

Bancos

Antes de hablar sobre el siguiente paso, debemos pensar en el comportamiento indeseable resultante que podemos ver en el paso anterior.

El problema con simplemente forzar la frase deseada "is fast" en la salida es que, la mayor铆a de las veces, terminar铆amos con salidas sin sentido como "The is fast" arriba. Esto es lo que hace que este sea un problema no trivial de resolver. Se puede encontrar una discusi贸n m谩s profunda sobre las complejidades de resolver este problema en la solicitud original de caracter铆sticas que se plante贸 en huggingface/transformers.

Los bancos resuelven este problema al crear un equilibrio entre cumplir las restricciones y crear una salida razonable.

Banco n n n se refiere a la lista de haces que han avanzado n n n pasos en el cumplimiento de las restricciones . Despu茅s de ordenar todos los posibles haces en sus respectivos bancos, hacemos una selecci贸n de tipo round-robin. Con el ejemplo anterior, seleccionar铆amos la salida m谩s probable del Banco 2, luego la m谩s probable del Banco 1, una del Banco 0, la segunda m谩s probable del Banco 2, la segunda m谩s probable del Banco 1, y as铆 sucesivamente. Dado que estamos usando num_beams=3 , simplemente repetimos el proceso anterior tres veces para obtener ["El es r谩pido", "El perro es", "El perro y"] .

De esta manera, aunque estamos forzando al modelo a considerar la rama donde hemos a帽adido manualmente el token deseado, a煤n hacemos un seguimiento de otras secuencias altamente probables que probablemente tengan m谩s sentido. Aunque "El es r谩pido" cumple completamente nuestra restricci贸n, no es una frase muy sensata. Afortunadamente, tenemos "El perro es" y "El perro y" para trabajar en futuros pasos, lo que esperemos nos lleve a salidas m谩s sensatas m谩s adelante.

Este comportamiento se demuestra en el tercer paso del ejemplo anterior:

Observa c贸mo "El es r谩pido" no requiere agregar manualmente ning煤n token de restricci贸n, ya que ya est谩 cumplido (es decir, ya contiene la frase "es r谩pido" ). Tambi茅n, observa c贸mo los haces como "El perro es lento" o "El perro est谩 loco" est谩n en realidad en el Banco 0, ya que, aunque incluye el token "es" , debe reiniciar desde el principio para generar "es r谩pido" . Al agregar algo como "lento" despu茅s de "es" , ha reiniciado efectivamente su progreso .

Y finalmente, observa c贸mo llegamos a una salida sensata que contiene nuestra frase de restricci贸n: "El perro es r谩pido" !

Est谩bamos preocupados inicialmente porque agregar a ciegas los tokens deseados llevaba a frases sin sentido como "El es r谩pido" . Sin embargo, al usar la selecci贸n round-robin de los bancos, impl铆citamente nos deshicimos de las salidas sin sentido en preferencia por las salidas m谩s sensatas.

M谩s sobre las clases de restricci贸n y restricciones personalizadas

La idea principal de la explicaci贸n se puede resumir de la siguiente manera. En cada paso, seguimos insistiendo al modelo que considere los tokens que cumplen nuestras restricciones, al mismo tiempo que hacemos un seguimiento de los haces que no lo hacen, hasta que obtenemos secuencias con una alta probabilidad que contienen nuestras frases deseadas.

Entonces, una forma sistem谩tica de dise帽ar esta implementaci贸n fue representar cada restricci贸n como un objeto Constraint, cuyo prop贸sito era hacer un seguimiento de su progreso y decirle a la b煤squeda de haz qu茅 tokens generar a continuaci贸n. Aunque hemos proporcionado el argumento de palabra clave force_words_ids para model.generate() , esto es lo que realmente sucede en el backend:

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, PhrasalConstraint

tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")

encoder_input_str = "translate English to German: How old are you?"

constraints = [
    PhrasalConstraint(
        tokenizer("Sie", add_special_tokens=False).input_ids
    )
]

input_ids = tokenizer(encoder_input_str, return_tensors="pt").input_ids


outputs = model.generate(
    input_ids,
    constraints=constraints,
    num_beams=10,
    num_return_sequences=1,
    no_repeat_ngram_size=1,
    remove_invalid_values=True,
)


print("Output:\n" + 100 * '-')
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

Output:
----------------------------------------------------------------------------------------------------
Wie alt sind Sie?

Puedes definir uno por ti mismo e ingresarlo en el argumento de palabra clave constraints para dise帽ar tus restricciones 煤nicas. Solo tienes que crear una subclase de la clase de interfaz abstracta Constraint y seguir sus requisitos. Puedes encontrar m谩s informaci贸n en la definici贸n de Constraint que se encuentra aqu铆 .

Algunas ideas 煤nicas (a煤n no implementadas, 隆quiz谩s puedas intentarlo!) incluyen restricciones como OrderedConstraints, TemplateConstraints que pueden agregarse m谩s adelante. Actualmente, la generaci贸n se cumple incluyendo las secuencias en cualquier parte de la salida. Por ejemplo, un ejemplo anterior ten铆a una secuencia con asustado -> gritando y la otra con grit贸 -> asustado. OrderedConstraints podr铆a permitir al usuario especificar el orden en el que se cumplen estas restricciones.

TemplateConstraints podr铆a permitir un uso m谩s espec铆fico de la funci贸n, donde el objetivo puede ser algo como:

starting_text = "La mujer"
template = ["la", "", "Escuela de", "", "en"]

possible_outputs == [
   "La mujer asisti贸 a la Escuela de Negocios Ross en Michigan.",
   "La mujer fue administradora de la Escuela de Negocios de Harvard en MA."
]

o:

starting_text = "La mujer"
template = ["la", "", "", "Universidad", "", "en"]

possible_outputs == [
   "La mujer asisti贸 a la Universidad Carnegie Mellon en Pittsburgh.",
]
impossible_outputs == [
  "La mujer asisti贸 a la Universidad de Harvard en MA."
]

o si al usuario no le importa el n煤mero de tokens que pueden ir entre dos palabras, entonces uno puede simplemente usar OrderedConstraint.

Conclusi贸n

La b煤squeda restringida de haz nos brinda una forma flexible de inyectar conocimientos externos y requisitos en la generaci贸n de texto. Anteriormente, no hab铆a una forma f谩cil de indicar al modelo que 1. incluyera una lista de secuencias donde 2. algunas de ellas son opcionales y otras no, de manera que 3. se generen en alg煤n lugar de la secuencia en posiciones razonables respectivas. 隆Ahora podemos tener control total sobre nuestra generaci贸n con una combinaci贸n de diferentes subclases de objetos Constraint!

Esta nueva funci贸n se basa principalmente en los siguientes documentos:

  • Guided Open Vocabulary Image Captioning with Constrained Beam Search
  • Fast Lexically Constrained Decoding with Dynamic Beam Allocation for Neural Machine Translation
  • Improved Lexically Constrained Decoding for Translation and Monolingual Rewriting
  • Guided Generation of Cause and Effect

Al igual que los mencionados anteriormente, muchos nuevos documentos de investigaci贸n est谩n explorando formas de utilizar conocimientos externos (por ejemplo, KGs, KBs) para guiar las salidas de modelos grandes de aprendizaje profundo. Esperemos que esta funci贸n de b煤squeda restringida de haz se convierta en otra forma efectiva de lograr este prop贸sito.

Gracias a todos los que brindaron orientaci贸n para esta contribuci贸n de funci贸n: Patrick von Platen por su participaci贸n desde el problema inicial hasta la solicitud de extracci贸n final, y Narsil Patry, por brindar comentarios detallados sobre el c贸digo.

La miniatura de esta publicaci贸n utiliza un 铆cono con atribuci贸n: Iconos abreviados creados por Freepik – Flaticon

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

El mundo natural potencia el futuro de la visi贸n por computadora

Un sistema de software de c贸digo abierto tiene como objetivo mejorar el entrenamiento de sistemas de visi贸n por compu...

Inteligencia Artificial

Investigadores de IA de Salesforce presentan la evoluci贸n de los agentes aut贸nomos mejorados con LLM y la innovadora estrategia BOLAA

I had trouble accessing your link so I’m going to try to continue without it. Los recientes logros de los model...

Inteligencia Artificial

Descubriendo el impacto de la IA generativa en la narraci贸n de datos y el an谩lisis

Introducci贸n En el amplio campo de la anal铆tica de datos, uno de los desarrollos m谩s profundos que cambia el juego es...

Aprendizaje Autom谩tico

驴Qu茅 sucede si ejecutas un modelo Transformer con una red neuronal 贸ptica?

La escala exponencialmente creciente de los modelos de deep learning es una fuerza importante para avanzar en el esta...