TICS-579-Deep Learning

Clase 9: Manipulación de Datos de Texto

Alfonso Tobar-Arancibia

Natural Language Processing (NLP)

🔔

El Natural Language Processing (NLP) es el área que se dedica al análisis y procesamiento de Texto. Existe una variedad de tareaas que se pueden abordar utilizando técnicas de Deep Learning tales como:

Speech Recognition

Dada la naturaleza secuencial del lenguaje, el contexto ayuda a interpretar cuál es la manera correcta de interpretar el sonido emitido.

El problema

¿Cómo hacemos que una red neuronal entienda y procese el texto?

Proceso de Tokenización y Embedding

Tokenización

El proceso de Tokenización permite transformar texto en datos numéricos. Cada dato numérico se mapea con un “trozo de texto”. Normalmente los modelos van asociados a la tokenización con la que fueron entrenados. Cambiar la tokenización puede generar gran degradación.

Embedding

Corresponde el proceso en el que los Tokens se transforman en vectores densos en las cuales la distancia entre ellos representa una noción de similaridad.

  • En este caso la frase “Frog on a log” es separada en Tokens (en este caso cada token es una palabra).
  • Luego cada Token es mapeado a un Token id proveniente de un vocabulario. ¿Qué es un vocabulario?
  • Los embeddings en este caso representan una secuencia de largo 7 con 3 dimensiones.

Embeddings

¿Por qué es tan importante el uso de Embeddings?

  • Primero porque son entrenables. Es decir la red puede aprender cuál es la mejor manera de representar palabras.
  • Existen embeddings pre-entrenados, es decir, se puede hacer transfer learning de embeddings.
  • La red puede aprender relaciones semánticas entre palabras, algo imposible utilizando otras representaciones.

Un tensor de Texto

Tokenización

Suponiendo un Tensor de Entrada que representa 4 frases de 6 Tokens cada una:

X = torch.tensor([[42, 67, 76, 14, 26, 35],
        [20, 24, 50, 13, 78, 14],
        [10, 54, 31, 72, 15, 95],
        [67,  6, 49, 76, 73, 11]])
print(X.shape)
(4, 6)

👀 Una palabra no necesariamente es un solo Token. Ver acá

🚨 La tokenización depende del vocabulario utilizado. La Tokenización va de la mano con el embedding y con el modelo a utilizar.

Embedding

emb = nn.Embedding(100, 3)
output = emb(X)
print("Shape de un Embedding:", output.shape)
output
tensor([[[-1.4391,  0.5214,  1.0414],
         [-0.8293, -1.0809, -0.7839],
         [ 0.6427,  0.5742,  0.5867],
         [-1.0759,  0.5357,  1.1754],
         [ 0.2191,  0.5526, -0.6788],
         [ 0.5069, -0.4752, -0.4920]],

        [[-0.5644,  1.0563, -1.4692],
         [-0.1976,  1.2683,  1.2243],
         [-0.5855, -0.3900,  0.9812],
         [-0.4459, -1.2024,  0.7078],
         [-0.9109, -0.5291, -0.8051],
         [-1.0759,  0.5357,  1.1754]],

        [[-1.3864, -1.2862, -0.8371],
         [-1.4510, -0.7861, -0.9563],
         [ 0.2332,  4.0356,  1.2795],
         [-1.5754,  2.2508,  1.0012],
         [ 0.5612, -0.4527, -0.7718],
         [ 0.3714, -0.0047,  0.0795]],

        [[-0.8293, -1.0809, -0.7839],
         [ 1.5736, -0.8455,  1.3123],
         [ 1.1179, -1.2956,  0.0503],
         [ 0.6427,  0.5742,  0.5867],
         [ 1.3642,  0.6333,  0.4050],
         [-0.9224,  1.8113,  0.1606]]])

Tokens Especiales

Cada modelo puede incluir el tipo de Tokenización que más le acomode. Además cada tokenización suele incluir tokens especiales que ayudan a la red a entender mejor el contexto o a resolver problemas intrínsecos del modelamiento de secuencias. Algunos de estos Tokens especiales son:

  • <PAD> : Token utilizado para rellenar secuencias más cortas y que todas tengan el mismo largo.
  • <SOS> o <BOS> : Start of Sequence/Beginning of Sequence. Token que indica el inicio de una secuencia.
  • <EOS> : End of Sequence. Token que indica el final de una secuencia.
  • <UNK> : Unknown Token. Token utilizado para representar palabras fuera del vocabulario.
  • <MASK> : Token utilizado en tareas de Masked Language Modeling (MLM) para indicar palabras que deben ser predichas por el modelo.
  • <SEP> : Separator Token. Utilizado para separar diferentes partes de una secuencia, como en tareas de preguntas y respuestas.
  • <CLS> : Classification Token. Utilizado en tareas de clasificación para representar toda la secuencia.

🚩 Ojo

Exiten tantos tokens especiales como tokenizadores y modelos existen. Siempre revisar la documentación del modelo a utilizar. Algunos también indican roles como por ejemplo en el caso de un asistente, se indica el rol del asistente, del usuario, y prompts de sistemas.

Problema de las RNN comunes

A pesar de las habilidades de las RNN, estas no son suficientes para distintas tareas de NLP.

Las RNN inicialmente toman cada elemento de una secuencia y generan un output para cada entrada. Esto genera ciertas limitantes en tareas como Machine Translation, donde por ejemplo, el modelo asume que la traducción es uno a uno, lo cuál no es necesariamente cierto.

Machine Translation: Ejemplo del Inglés

Supongamos que necesitamos hacer la siguiente traducción:

Inglés

Hi, my name is Alfonso

Español

Hola, mi nombre es Alfonso

Este tipo de traducción es uno a uno. Cada input puede tener asociado una salida de manera directa puede realizarse de manera directa con una RNN.

Machine Translation: Ejemplo del Inglés

Inglés

Would you help me prepare something for tomorrow?

Español

¿Me ayudarías a preparar algo para mañana?

⛔ Problemas

  • La traducción no es uno. De hecho en inglés se utilizan 8 palabras y 1 signo de puntuación. En español se traduce en 7 palabras y 2 signos de puntuación.
  • “Would” no tiene equivalente en español.
  • “a” no tiene equivalente en el inglés.
  • “Me” se traduce como “me” en inglés pero en vez de ir al inicio, va continuación de “help”.
  • ¿” no existe en inglés.

🔔

  • Otros idiomas como el Alemán o el Ruso, tienen fusión de palabras o declinaciones que hacen la traducción mucho más difícil.
  • Es por ello que se requiere una cierta libertad entre los tokens de entradas y los tokens de salida.

Soluciones: Redes Convolucionales

Una potencial solución se puede dar por medio de Redes Convolucionales de 1D. En este caso las redes convolucionales tienen la ventaja de poder mirar tanto al pasado como al futuro de manera móvil.

Ventajas

  • Pueden tomar contexto desde el inicio y desde el final.

Desventajas

  • Su campo receptivo es mucho más acotado y depende del número de capas y el largo del Kernel lo cual repercute directamente en el número de parámetros del modelo.
  • No tienen estado latente (o memoria) que almacena contexto.
  • No es útil para modelos de generación (ya que ve contexto desde el futuro).

Soluciones: Arquitecturas Encoder-Decoder

Encoder
Corresponde a una arquitectura que permitirá tomar datos de entrada y codificarlos en una representación numérica (normalmente como hidden states, embeddings o logits).
Decoder
Corresponde a una arquitectura que toma una representación codificada de datos (normalmente generado por un encoder) y la transforma nuevamente en una salida con un formato comprensible y no solamente una “simple etiqueta”.

Este tipo de arquitecturas son quizás las más populares hoy en día y tienen aplicaciones en distintos dominios.

Soluciones: Arquitecturas Encoder-Decoder

Una arquitectura Encoder-Decoder convolucional permite devolver una imagen como salida. Este ejemplo se conoce como Segmentación Semántica.

Soluciones: Arquitecturas Encoder-Decoder

Una arquitectura recurrente permite devolver una secuencia como salida. La cual puede utilizarse para generación o traducción de texto.

Ventajas

  • Permite “desligarse” de la predicción uno a uno. El Encoder resuelve una tarea many (la secuencia) to one (un hidden state) y el Decoder resuelve una tarea one (hidden state) to many (secuencia de salida).
  • La salida de este tipo de modelos depende principalmente del contexto almacenado en el Hidden State/Bottleneck ya que se utiliza como Hidden State inicial del Decoder.

Desventajas

  • Dado los problemas de Vanishing/Exploding Gradients es ingenuo pensar que todo el contexto de una frase vive en el último hidden state.
  • Aún así, son una buena primera aproximación al problema.

Ejemplo: Traducción de Texto

Supongamos que queremos traducir la frase How are you? al español.

Para comenzar el Proceso de Traducción se debe ingresar la Frase a Traducir al Encoder y luego dar inicio a la Traducción en el Decoder mediante el Token Especial <SOS>.

<SOS> genera como primera predicción el token ¿ el cuál será utilizado como segundo input del Decoder. Esto nos entrega como predicción el token Cómo. Que a su vez se utiliza como el tercer input del Decoder y nos entrega el Token estás.

Este proceso de conoce como Predicción/Generación Autoregresiva.

Este proceso de repite hasta que nos encontramos con el Token Especial <EOS>, el cuál nos indica que debemos dejar de generar.

Trucos de Entrenamiento

El entrenamiento de una RNN puede ser muy ineficiente y “trabado” si es que no se utilizan ciertos trucos. Algunos de estos trucos son:

Teacher Forcing

☝️ Dado que al momento de comenzar el entrenamiento el modelo no tiene por qué traducir correctamente, es que al Decoder se le entrega el Token correcto en vez de la predicción del modelo. Esto permite que el modelo aprenda más rápido y de mejor manera.

🚨 Normalmente esto se hace de manera pseudoaleatoria utilizando un teacher_forcing_ratio. Ojo con el Exposure Bias

Ejemplo: Greedy vs Beam Search

Prediciendo para “good”

Secuencia Cálculo Resultado
good night 0.45 × 0.40 0.18
good evening 0.45 × 0.58 0.261
good bye 0.45 × 0.02 0.009


Prediciendo para “hello”

Secuencia Cálculo Resultado
hello night 0.30 × 0.10 0.03
hello evening 0.30 × 0.15 0.045
hello there 0.30 × 0.5 0.15

Greedy Search diría que la predicción de la segunda palabra es

Beam Search con width=2 diría lo siguiente:

  • Beam 1: good night (p=0.18)
  • Beam 2: good evening (p=0.261)

En este caso, ambas opciones son traducciones válidas. Además, puede combinarse con un muestreo probabilístico para introducir mayor diversidad en los resultados.

Trucos de Inferencia: Top-k Sampling

Supongamos que tenemos la siguiente distribución de Probabilidad sobre un vocabulario:

Top-k Sampling

Se escogerá aleatoriamente entre los k tokens con mayor probabilidad. Esto introduce diversidad en la generación.

Temperatura

Corresponde a un parámetro que permite controlar la “concentración” de la distribución de probabilidad. A mayor temperatura, más uniforme será la distribución. A menor temperatura, más concentrada estará la distribución en los tokens con mayor probabilidad.

token logit logit/T=1.5 prob T=1.5 logit/T=4 prob T=4
the 5.0 3.33 0.53 1.25 0.32
and 4.0 2.67 0.27 1 0.25
a 3.0 2.00 0.14 0.75 0.20
dog 1.0 0.67 0.04 0.25 0.12
fast 0.5 0.33 0.02 0.13 0.11

Note

Se puede ver que a medida que la temperatura aumenta, la distribución de probabilidad se vuelve más uniforme. Es decir la probabilidad de cualquiera de los tokens aparezca aumenta.

🚨Otra forma de verlo es que la probabilidad de que no ocurra el más token más probable es mucho mayor.

Por ejemplo con T=1.5 la probabilidad de que no ocurra “the” es 0.47, mientras que con T=4 es 0.68.

Terminamos RNNs 😊