Comprendiendo la Atención Esparsa por Bloques de BigBird

'Understanding Sparse Attention with BigBird Blocks'

Introducción

Los modelos basados en transformadores han demostrado ser muy útiles para muchas tareas de procesamiento del lenguaje natural (NLP, por sus siglas en inglés). Sin embargo, una limitación importante de los modelos basados en transformadores es su complejidad temporal y de memoria de O(n^2) (donde n es la longitud de la secuencia). Por lo tanto, es computacionalmente muy costoso aplicar modelos basados en transformadores en secuencias largas n > 512. Varios artículos recientes, como Longformer, Performer, Reformer, Clustered attention, intentan remediar este problema aproximando la matriz de atención completa. Puedes leer la publicación reciente del blog de 🤗 si no estás familiarizado con estos modelos.

BigBird (presentado en el artículo ) es uno de esos modelos recientes para abordar este problema. BigBird se basa en atención dispersa por bloques en lugar de la atención normal (es decir, la atención de BERT) y puede manejar secuencias de hasta una longitud de 4096 con un costo computacional mucho menor en comparación con BERT. Ha logrado el estado del arte en varias tareas que involucran secuencias muy largas, como la sumarización de documentos largos y la pregunta-respuesta con contextos extensos.

El modelo BigBird similar a RoBERTa ahora está disponible en 🤗Transformers. El objetivo de esta publicación es brindar al lector una comprensión detallada de la implementación de BigBird y facilitar el uso de BigBird con 🤗Transformers. Pero antes de profundizar más, es importante recordar que la atención de BigBird es una aproximación de la atención completa de BERT y, por lo tanto, no se esfuerza por ser mejor que la atención completa de BERT, sino más bien ser más eficiente. Simplemente permite aplicar modelos basados en transformadores a secuencias mucho más largas, ya que el requisito de memoria cuadrática de BERT se vuelve rápidamente insoportable. En pocas palabras, si tuviéramos ∞ \infty ∞ cómputo y ∞ \infty ∞ tiempo, la atención de BERT sería preferible a la atención dispersa por bloques (que vamos a discutir en esta publicación).

Si te preguntas por qué necesitamos más cómputo al trabajar con secuencias más largas, ¡esta publicación de blog es perfecta para ti!


Algunas de las principales preguntas que uno puede tener al trabajar con la atención estándar similar a BERT incluyen:

  • ¿Realmente todos los tokens tienen que atender a todos los demás tokens?
  • ¿Por qué no calcular la atención solo sobre los tokens importantes?
  • ¿Cómo decidir qué tokens son importantes?
  • ¿Cómo atender solo a unos pocos tokens de manera muy eficiente?

En esta publicación de blog, intentaremos responder esas preguntas.

¿A qué tokens se debe prestar atención?

Daremos un ejemplo práctico de cómo funciona la atención considerando la frase “BigBird está ahora disponible en HuggingFace para responder preguntas extractivas”. En la atención similar a BERT, cada palabra simplemente prestaría atención a todos los demás tokens. Matemáticamente hablando, esto significaría que cada token consultado query-token ∈ { BigBird , is , now , available , in , HuggingFace , for , extractive , question , answering } \text{query-token} \in \{\text{BigBird},\text{is},\text{now},\text{available},\text{in},\text{HuggingFace},\text{for},\text{extractive},\text{question},\text{answering}\} query-token ∈ { BigBird , is , now , available , in , HuggingFace , for , extractive , question , answering } , prestaría atención a la lista completa de tokens clave = [ BigBird , is , now , available , in , HuggingFace , for , extractive , question , answering ] \text{key-tokens} = \left[\text{BigBird},\text{is},\text{now},\text{available},\text{in},\text{HuggingFace},\text{for},\text{extractive},\text{question},\text{answering} \right] key-tokens = [ BigBird , is , now , available , in , HuggingFace , for , extractive , question , answering ] .

Pensemos en una elección sensata de tokens clave a los que un token consultado realmente solo debería atender escribiendo un pseudo-código. Supondremos que el token available es el que se consulta y construiremos una lista sensata de tokens clave a los que atender.

>>> # consideremos la siguiente oración como ejemplo
>>> example = ['BigBird', 'is', 'now', 'available', 'in', 'HuggingFace', 'for', 'extractive', 'question', 'answering']

>>> # supongamos además que estamos tratando de entender la representación de 'available', es decir,
>>> query_token = 'available'

>>> # Inicializaremos un conjunto vacío y llenaremos los tokens de nuestro interés a medida que avancemos en esta sección.
>>> key_tokens = [] # => actualmente el token 'available' no tiene nada a lo que atender

Los tokens cercanos deberían ser importantes porque, en una oración (secuencia de palabras), la palabra actual depende en gran medida de los tokens vecinos pasados y futuros. Esta intuición es la idea detrás del concepto de sliding attention.

>>> # considerando `window_size = 3`, consideraremos 1 token a la izquierda y 1 a la derecha de 'available'
>>> # token izquierdo: 'now' ; token derecho: 'in'
>>> sliding_tokens = ["now", "available", "in"]

>>> # actualicemos nuestra colección con los tokens anteriores
>>> key_tokens.append(sliding_tokens)

Dependencias a largo plazo: Para algunas tareas, es crucial capturar relaciones a largo plazo entre los tokens. Por ejemplo, en `question-answering`, el modelo necesita comparar cada token del contexto con toda la pregunta para poder determinar qué parte del contexto es útil para una respuesta correcta. Si la mayoría de los tokens del contexto solo atendieran a otros tokens del contexto, pero no a la pregunta, sería mucho más difícil para el modelo filtrar los tokens importantes del contexto de los menos importantes.

Ahora, BigBird propone dos formas de permitir dependencias de atención a largo plazo manteniendo la eficiencia computacional.

  • Tokens globales: Introducir algunos tokens que atenderán a todos los tokens y a los que todos los tokens atenderán. Por ejemplo: “HuggingFace está construyendo bibliotecas agradables para un procesamiento de lenguaje natural sencillo”. Ahora, digamos que ‘building’ se define como un token global y el modelo necesita conocer la relación entre ‘NLP’ y ‘HuggingFace’ para alguna tarea (nota: estos 2 tokens están en dos extremos); ahora, si ‘building’ atiende globalmente a todos los demás tokens, probablemente ayudará al modelo a asociar ‘NLP’ con ‘HuggingFace’.
>>> # supongamos que el primer y último token son `globales`, entonces
>>> global_tokens = ["BigBird", "answering"]

>>> # agreguemos los tokens globales a nuestra colección de tokens clave
>>> key_tokens.append(global_tokens)
  • Tokens aleatorios: Seleccionar algunos tokens al azar que transferirán información transfiriéndose a otros tokens, que a su vez pueden transferirse a otros tokens. Esto puede reducir el costo de la transferencia de información de un token a otro.
>>> # ahora podemos elegir `r` token al azar de nuestra oración de ejemplo
>>> # elijamos 'is' asumiendo que `r=1`
>>> random_tokens = ["is"] # Nota: se elige completamente al azar; por lo que también podría ser cualquier otra cosa.

>>> # agreguemos los tokens aleatorios a nuestra colección
>>> key_tokens.append(random_tokens)

>>> # es hora de ver qué tokens hay en nuestra lista `key_tokens`
>>> key_tokens
{'now', 'is', 'in', 'answering', 'available', 'BigBird'}

# Ahora, 'available' (el token que elegimos en nuestro primer paso) solo atenderá a estos tokens en lugar de atender a toda la secuencia

De esta manera, el token consultado solo atiende a un subconjunto de todos los tokens posibles al tiempo que proporciona una buena aproximación de la atención completa. El mismo enfoque se utiliza para todos los demás tokens consultados. Pero recuerda, el objetivo principal aquí es aproximar la atención completa de BERT de la manera más eficiente posible. Simplemente hacer que cada token consultado atienda a todos los tokens clave, como se hace en BERT, se puede calcular de manera muy efectiva como una secuencia de multiplicaciones de matrices en hardware moderno, como las GPUs. Sin embargo, una combinación de atención deslizante, global y aleatoria parece implicar multiplicación de matrices dispersas, que es más difícil de implementar eficientemente en hardware moderno. Una de las principales contribuciones de BigBird es la propuesta de un mecanismo de atención block sparse que permite calcular la atención deslizante, global y aleatoria de manera efectiva. ¡Veámoslo!

Comprendiendo la necesidad de llaves globales, deslizantes y aleatorias con Gráficos

Primero, vamos a tener una mejor comprensión de la atención global, deslizante y aleatoria utilizando gráficos y tratar de entender cómo la combinación de estos tres mecanismos de atención produce una muy buena aproximación de la atención estándar Bert-like.

La figura anterior muestra las conexiones globales (izquierda), deslizantes (medio) y aleatorias (derecha) respectivamente como un gráfico. Cada nodo corresponde a un token y cada línea representa un puntaje de atención. Si no se realiza ninguna conexión entre 2 tokens, se asume que el puntaje de atención es 0.

La atención esparsa en bloques de BigBird es una combinación de conexiones deslizantes, globales y aleatorias (total de 10 conexiones) como se muestra en el gif de la izquierda. Mientras que un gráfico de atención normal (derecha) tendrá todas las 15 conexiones (nota: hay un total de 6 nodos). Puedes pensar simplemente en la atención normal como todos los tokens que asisten globalmente 1 {}^1 1.

Atención normal: El modelo puede transferir información directamente de un token a otro token en una sola capa, ya que cada token se consulta sobre todos los demás tokens y es atendido por todos los demás tokens. Consideremos un ejemplo similar al que se muestra en las figuras anteriores. Si el modelo necesita asociar ‘going’ con ‘now’, simplemente puede hacerlo en una sola capa ya que hay una conexión directa que une ambos tokens.

Atención esparsa en bloques: Si el modelo necesita compartir información entre dos nodos (o tokens), la información tendrá que viajar a través de varios otros nodos en el camino para algunos de los tokens; ya que todos los nodos no están directamente conectados en una sola capa. Por ejemplo, supongamos que el modelo necesita asociar ‘going’ con ‘now’, entonces si solo hay atención deslizante presente, el flujo de información entre esos 2 tokens está definido por el camino: going -> am -> i -> now (es decir, tendrá que viajar sobre 2 tokens adicionales). Por lo tanto, es posible que necesitemos múltiples capas para capturar toda la información de la secuencia. La atención normal puede capturar esto en una sola capa. En un caso extremo, esto podría significar que se necesitan tantas capas como tokens de entrada. Sin embargo, si introducimos algunos tokens globales, la información puede viajar a través del camino: going -> i -> now (que es más corto). Si además introducimos conexiones aleatorias, puede viajar a través de: going -> am -> now. Con la ayuda de las conexiones aleatorias y las conexiones globales, la información puede viajar rápidamente (con solo unas pocas capas) de un token al siguiente.

En caso de que tengamos muchos tokens globales, entonces es posible que no necesitemos conexiones aleatorias ya que habrá múltiples rutas cortas a través de las cuales la información puede viajar. Esta es la idea detrás de mantener num_random_tokens = 0 cuando se trabaja con una variante de BigBird llamada ETC (más sobre esto en secciones posteriores).

1 {}^1 1 En estas gráficas, asumimos que la matriz de atención es simétrica, es decir, A i j = A j i \mathbf{A}_{ij} = \mathbf{A}_{ji} A i j ​ = A j i ​ ya que en un gráfico si algún token A asiste a B, entonces B también asistirá a A. Puedes ver en la figura de la matriz de atención mostrada en la siguiente sección que esta suposición se cumple para la mayoría de los tokens en BigBird

original_full representa la atención de BERT, mientras que block_sparse representa la atención de BigBird. ¿Te preguntas qué es el block_size? Lo cubriremos en secciones posteriores. Por ahora, considéralo como 1 para simplificar.

Atención dispersa por bloques de BigBird

La atención dispersa por bloques de BigBird es simplemente una implementación eficiente de lo que discutimos anteriormente. Cada token está atendiendo a algunos tokens globales, tokens deslizantes y tokens aleatorios en lugar de atender a todos los demás tokens. Los autores codificaron la matriz de atención para múltiples componentes de consulta por separado; y utilizaron un truco genial para acelerar el entrenamiento/inferencia en GPU y TPU.

Nota: en la parte superior, tenemos 2 oraciones adicionales. Como puedes notar, cada token simplemente se intercambia por un lugar en ambas oraciones. Así es como se implementa la atención deslizante. Cuando se multiplica q[i] con k[i,0:3], obtendremos un puntaje de atención deslizante para q[i] (donde i es el índice del elemento en la secuencia).

Puedes encontrar la implementación real de la atención block_sparse aquí . Esto puede parecer muy intimidante 😨😨 ahora. Pero este artículo seguramente facilitará tu vida al entender el código.

Atención global

Para la atención global, cada consulta simplemente está atendiendo a todos los demás tokens en la secuencia y es atendida por cada otro token. Supongamos que Vasudev (primer token) y them (último token) son globales (en la figura anterior). Puedes ver que estos tokens están conectados directamente a todos los demás tokens (recuadros azules).

# pseudocódigo

Q -> Matriz de consulta (longitud_secuencia, dim_cabeza)
K -> Matriz de clave (longitud_secuencia, dim_cabeza)

# El primer y último token atienden a todos los demás tokens
Q[0] x [K[0], K[1], K[2], ......, K[n-1]]
Q[n-1] x [K[0], K[1], K[2], ......, K[n-1]]

# El primer y último token son atendidos por todos los demás tokens
K[0] x [Q[0], Q[1], Q[2], ......, Q[n-1]]
K[n-1] x [Q[0], Q[1], Q[2], ......, Q[n-1]]

Atención deslizante

La secuencia de tokens clave se copia 2 veces, con cada elemento desplazado a la derecha en una de las copias y a la izquierda en la otra copia. Ahora, si multiplicamos los vectores de la secuencia de consulta por estos 3 vectores de secuencia, cubriremos todos los tokens deslizantes. La complejidad computacional es simplemente O(3xn) = O(n). Refiriéndonos a la imagen anterior, los recuadros naranjas representan la atención deslizante. Puedes ver 3 secuencias en la parte superior de la figura, con 2 de ellas desplazadas en un token (1 a la izquierda, 1 a la derecha).

# lo que queremos hacer
Q[i] x [K[i-1], K[i], K[i+1]] para i = 1:-1

# implementación eficiente en código (supongamos multiplicación de producto punto 👇)
[Q[0], Q[1], Q[2], ......, Q[n-2], Q[n-1]] x [K[1], K[2], K[3], ......, K[n-1], K[0]]
[Q[0], Q[1], Q[2], ......, Q[n-1]] x [K[n-1], K[0], K[1], ......, K[n-2]]
[Q[0], Q[1], Q[2], ......, Q[n-1]] x [K[0], K[1], K[2], ......, K[n-1]]

# Cada secuencia se multiplica solo por 3 secuencias para mantener `window_size = 3`.
# Algunos cálculos pueden faltar; esta es solo una idea aproximada.

Atención aleatoria

La atención aleatoria asegura que cada token de consulta atienda también a algunos tokens aleatorios. Para la implementación real, esto significa que el modelo recopila algunos tokens al azar y calcula su puntaje de atención.

# r1, r2, r son algunos índices aleatorios; Nota: r1, r2, r3 son diferentes para cada fila 👇
Q[1] x [Q[r1], Q[r2], ......, Q[r]]
.
.
.
Q[n-2] x [Q[r1], Q[r2], ......, Q[r]]

# dejando el token 0 y el token (n-1) ya que ya son globales

Nota: La implementación actual divide aún más la secuencia en bloques y cada notación está definida con respecto al bloque en lugar de los tokens. Discutiremos esto con más detalle en la siguiente sección.

Implementación

Recapitulando: En la atención regular de BERT, una secuencia de tokens, es decir, X = x 1 , x 2 , . . . . , x n, se proyecta a través de una capa densa en Q , K , V y se calcula el puntaje de atención Z como Z = S o f t m a x ( Q K T ). En el caso de la atención dispersa por bloques de BigBird, se utiliza el mismo algoritmo pero solo con algunos vectores de consulta y clave seleccionados.

Echemos un vistazo a cómo se implementa la atención dispersa por bloques de BigBird. Para comenzar, asumamos que b , r , s , g representan block_size, num_random_blocks, num_sliding_blocks, num_global_blocks, respectivamente. Visualmente, podemos ilustrar los componentes de la atención dispersa por bloques de BigBird con b = 4 , r = 1 , g = 2 , s = 3 , d = 5 de la siguiente manera:

Los puntajes de atención para q 1 , q 2 , q 3 : n − 2 , q n − 1 , q n se calculan por separado de la siguiente manera:


El puntaje de atención para q 1 representado por a 1, donde a 1 = S o f t m a x ( q 1 ∗ K T ), no es más que el puntaje de atención entre todos los tokens en el primer bloque con todos los demás tokens en la secuencia.

q 1 representa el primer bloque, g i representa el bloque i. Simplemente estamos realizando una operación de atención normal entre q 1 y g (es decir, todas las claves).


Para calcular el puntaje de atención para los tokens en el segundo bloque, recopilamos los primeros tres bloques, el último bloque y el quinto bloque. Luego podemos calcular a 2 = S o f t m a x ( q 2 ∗ c o n c a t ( k 1 , k 2 , k 3 , k 5 , k 7 ) ).

Estoy representando los tokens por g, r, s solo para mostrar su naturaleza explícitamente (es decir, mostrar tokens globales, aleatorios, deslizantes), de lo contrario son solo k.


Para calcular el puntaje de atención para q 3 : n − 2, reuniremos las claves globales, deslizantes y aleatorias y calcularemos la operación de atención normal sobre q 3 : n − 2 y las claves reunidas. Tenga en cuenta que las claves deslizantes se recopilan utilizando el truco de desplazamiento especial como se discutió anteriormente en la sección de atención deslizante.


Para calcular el puntaje de atención para los tokens en el bloque anterior al último (es decir, q n − 1 {q}_{n-1} q n − 1 ​), estamos recopilando el primer bloque, los últimos tres bloques y el tercer bloque. Entonces podemos aplicar la fórmula a n − 1 = S o f t m a x ( q n − 1 ∗ c o n c a t ( k 1 , k 3 , k 5 , k 6 , k 7 ) ) {a}_{n-1} = Softmax({q}_{n-1} * concat(k_1, k_3, k_5, k_6, k_7)) a n − 1 ​ = S o f t m a x ( q n − 1 ​ ∗ c o n c a t ( k 1 ​ , k 3 ​ , k 5 ​ , k 6 ​ , k 7 ​) ). Esto es muy similar a lo que hicimos para q 2 q_2 q 2 ​ .


El puntaje de atención para q n \mathbf{q}_{n} q n ​ se representa por a n a_n a n ​ donde a n = S o f t m a x ( q n ∗ K T ) a_n=Softmax(q_n * K^T) a n ​ = S o f t m a x ( q n ​ ∗ K T ) , y no es más que el puntaje de atención entre todos los tokens en el último bloque con todos los demás tokens en la secuencia. Esto es muy similar a lo que hicimos para q 1 q_1 q 1 ​ .


Unamos las matrices anteriores para obtener la matriz de atención final. Esta matriz de atención se puede utilizar para obtener una representación de todos los tokens.

azul -> bloques globales , rojo -> bloques aleatorios , naranja -> bloques deslizantes Esta matriz de atención es solo para ilustración. Durante el paso hacia adelante, no estamos almacenando bloques blancos, sino que estamos calculando directamente una matriz de valores ponderados (es decir, una representación de cada token) para cada componente separado como se discutió anteriormente.

Ahora, hemos cubierto la parte más difícil de la atención dispersa por bloques, es decir, su implementación. Con suerte, ahora tienes un mejor contexto para entender el código real. Siéntete libre de sumergirte en él y conectar cada parte del código con uno de los componentes mencionados anteriormente.

Complejidad de tiempo y memoria

Comparación de la complejidad de tiempo y espacio de atención de BERT y atención dispersa por bloques de BigBird.

Expande este fragmento en caso de que quieras ver los cálculos

Complejidad de tiempo de BigBird = O(w x n + r x n + g x n)
Complejidad de tiempo de BERT = O(n^2)

Suposiciones:
    w = 3 x 64
    r = 3 x 64
    g = 2 x 64

Cuando seqlen = 512
=> **complejidad de tiempo en BERT = 512^2**

Cuando seqlen = 1024
=> complejidad de tiempo en BERT = (2 x 512)^2
=> **complejidad de tiempo en BERT = 4 x 512^2**

=> complejidad de tiempo en BigBird = (8 x 64) x (2 x 512)
=> **complejidad de tiempo en BigBird = 2 x 512^2**

Cuando seqlen = 4096
=> complejidad de tiempo en BERT = (8 x 512)^2
=> **complejidad de tiempo en BERT = 64 x 512^2**

=> complejidad de tiempo en BigBird = (8 x 64) x (8 x 512)
=> complejidad de tiempo en BigBird = 8 x (512 x 512)
=> **complejidad de tiempo en BigBird = 8 x 512^2**

ITC vs ETC

El modelo BigBird se puede entrenar utilizando 2 estrategias diferentes: ITC y ETC. ITC (construcción interna del transformador) es simplemente lo que discutimos anteriormente. En ETC (construcción extendida del transformador), algunos tokens adicionales se hacen globales para que atiendan a / sean atendidos por todos los tokens.

ITC requiere menos cómputo ya que muy pocas fichas son globales, al mismo tiempo que el modelo puede capturar suficiente información global (también con la ayuda de una atención aleatoria). Por otro lado, ETC puede ser muy útil para tareas en las que necesitamos muchas fichas globales, como la “pregunta-respuesta” para la cual toda la pregunta debe ser atendida globalmente por el contexto para poder relacionar correctamente el contexto con la pregunta.

Nota: Se muestra en el documento Big Bird que en muchos experimentos de ETC, el número de bloques aleatorios se establece en 0. Esto es razonable dadas nuestras discusiones anteriores en la sección del gráfico.

La siguiente tabla resume ITC & ETC:

Utilizando BigBird con 🤗Transformers

Puedes usar BigBirdModel como cualquier otro modelo de 🤗. Veamos un poco de código a continuación:

from transformers import BigBirdModel

# cargando bigbird desde su punto de control pre-entrenado
modelo = BigBirdModel.from_pretrained("google/bigbird-roberta-base")
# Esto inicializará el modelo con la configuración predeterminada, es decir, attention_type = "block_sparse" num_random_blocks = 3, block_size = 64.
# Pero puedes cambiar libremente estos argumentos con cualquier punto de control. Estos 3 argumentos solo cambiarán el número de fichas a las que cada ficha de consulta va a atender.
modelo = BigBirdModel.from_pretrained("google/bigbird-roberta-base", num_random_blocks=2, block_size=16)

# Al establecer attention_type en `original_full`, BigBird se basará en la atención completa de complejidad n^2. De esta manera, BigBird es 99.9% similar a BERT.
modelo = BigBirdModel.from_pretrained("google/bigbird-roberta-base", attention_type="original_full")

En total hay 3 puntos de control disponibles en 🤗Hub (en el momento de escribir este artículo): bigbird-roberta-base, bigbird-roberta-large, bigbird-base-trivia-itc. Los primeros dos puntos de control provienen del preentrenamiento BigBirdForPretraining con pérdida de masked_lm; mientras que el último corresponde al punto de control después de afinar BigBirdForQuestionAnswering en el conjunto de datos trivia-qa.

Echemos un vistazo al código mínimo que puedes escribir (en caso de que desees usar tu entrenador PyTorch) para usar el modelo BigBird de 🤗 para afinar tus tareas.

# consideremos nuestra tarea de pregunta-respuesta como ejemplo

from transformers import BigBirdForQuestionAnswering, BigBirdTokenizer
import torch

device = torch.device("cpu")
if torch.cuda.is_available():
    device = torch.device("cuda")

# inicialicemos el modelo bigbird con pesos pre-entrenados con una cabeza inicializada aleatoriamente en la parte superior
modelo = BigBirdForQuestionAnswering.from_pretrained("google/bigbird-roberta-base", block_size=64, num_random_blocks=3)
tokenizer = BigBirdTokenizer.from_pretrained("google/bigbird-roberta-base")
modelo.to(device)

conjunto_de_datos = "objeto DataLoader de torch.utils.data"
optimizador = "objeto torch.optim"
epochs = ...

# bucle de entrenamiento muy mínimo
for e in range(epochs):
    for lote in conjunto_de_datos:
        modelo.train()
        lote = {k: lote[k].to(device) for k in lote}

        # paso hacia adelante
        salida = modelo(**lote)

        # retro-propagación
        salida["loss"].backward()
        optimizador.step()
        optimizador.zero_grad()

# guardemos los pesos finales en un directorio local
modelo.save_pretrained("<TU-DIRECTORIO-DE-PESOS>")

# enviemos nuestros pesos a 🤗Hub
from huggingface_hub import ModelHubMixin
ModelHubMixin.push_to_hub("<TU-DIRECTORIO-DE-PESOS>", model_id="<TU-ID-AFINADO>")

# usando el modelo afinado para inferencia
pregunta = ["¿Cómo estás?", "¿Cómo va la vida?"]
contexto = ["<algún gran contexto que tenga ans-1>", "<algún gran contexto que tenga ans-2>"]
lote = tokenizer(pregunta, contexto, return_tensors="pt")
lote = {k: lote[k].to(device) for k in lote}

modelo = BigBirdForQuestionAnswering.from_pretrained("<TU-ID-AFINADO>")
modelo.to(device)
with torch.no_grad():
    start_logits, end_logits = modelo(**lote).to_tuple()
    # ahora decodifica start_logits, end_logits con la estrategia que desees.

# Nota:
# Este fue un código muy mínimo (en caso de que desees usar PyTorch puro) solo para mostrar cómo BigBird se puede usar fácilmente
# Sugeriría usar 🤗Trainer para tener acceso a muchas características

Es importante tener en cuenta los siguientes puntos al trabajar con Big Bird:

  • La longitud de la secuencia debe ser un múltiplo del tamaño del bloque, es decir, seqlen % block_size = 0. No tienes que preocuparte, ya que 🤗Transformers automáticamente agregará <pad> (al múltiplo más pequeño del tamaño del bloque que sea mayor que la longitud de la secuencia) si la longitud de la secuencia del lote no es un múltiplo de block_size.
  • Actualmente, la versión de HuggingFace no admite ETC y, por lo tanto, solo el primer y último bloque serán globales.
  • La implementación actual no admite num_random_blocks = 0.
  • Los autores recomiendan establecer attention_type = "original_full" cuando la longitud de la secuencia es menor que 1024.
  • Debe cumplirse lo siguiente: seq_length > global_token + random_tokens + sliding_tokens + buffer_tokens donde global_tokens = 2 x block_size, sliding_tokens = 3 x block_size, random_tokens = num_random_blocks x block_size y buffer_tokens = num_random_blocks x block_size. En caso de que no lo hagas, 🤗Transformers automáticamente cambiará attention_type a original_full con una advertencia.
  • Cuando se utiliza Big Bird como decodificador (o se utiliza BigBirdForCasualLM), attention_type debe ser original_full. Pero no tienes que preocuparte, 🤗Transformers cambiará automáticamente attention_type a original_full en caso de que olvides hacerlo.

¿Qué sigue?

@patrickvonplaten ha creado un cuaderno realmente genial sobre cómo evaluar BigBirdForQuestionAnswering en el conjunto de datos trivia-qa. Siéntete libre de jugar con BigBird usando ese cuaderno.

Pronto encontrarás un modelo similar a BigBird Pegasus en la biblioteca para resumen de documentos largos 💥.

Notas finales

La implementación original de la matriz de atención con bloques dispersos se puede encontrar aquí. Puedes encontrar la versión de 🤗 aquí.

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

Microsoft presenta Azure Custom Chips Revolucionando la computación en la nube y las capacidades de IA

En medio de persistentes rumores de la industria, la tan esperada revelación de Microsoft salió a la luz durante la c...

Inteligencia Artificial

Utilizando el lenguaje para dar a los robots una mejor comprensión del mundo abierto

El método de Campos de Características para la Manipulación Robótica ayuda a los robots a identificar objetos cercano...

Inteligencia Artificial

Equilibrando la innovación y la sostenibilidad Desentrañando el impacto ambiental de la IA generativa

La asociación francesa Data for Good publicó un documento blanco que explora los problemas sociales y ambientales que...

Inteligencia Artificial

Generación rápida y precisa de hologramas acústicos utilizando un marco basado en aprendizaje profundo

El equipo liderado por el profesor Hwang Jae-Yoon del Departamento de Ingeniería Eléctrica y Ciencias de la Computaci...