Clase 9: Manipulación de Datos de Texto
🔔
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:
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?
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.
¿Por qué es tan importante el uso de Embeddings?
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.
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]]])
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:
🚩 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.
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.
Supongamos que necesitamos hacer la siguiente traducción:
Hi, my name is Alfonso
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.
Would you help me prepare something for tomorrow?
¿Me ayudarías a preparar algo para mañana?
⛔ Problemas
🔔
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
Desventajas
Este tipo de arquitecturas son quizás las más populares hoy en día y tienen aplicaciones en distintos dominios.
Una arquitectura Encoder-Decoder convolucional permite devolver una imagen como salida. Este ejemplo se conoce como Segmentación Semántica.
Una arquitectura recurrente permite devolver una secuencia como salida. La cual puede utilizarse para generación o traducción de texto.
Ventajas
Desventajas
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.
El entrenamiento de una RNN puede ser muy ineficiente y “trabado” si es que no se utilizan ciertos trucos. Algunos de estos trucos son:
☝️ 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
Al momento de generar texto, la salida de cada step del Decoder tendrá una distribución de probabilidad sobre el vocabulario. Existen distintas estrategias para escoger el siguiente token a utilizar:
🙂 En este caso Greedy Search escoge el Token con mayor probabilidad en cada step y lo utiliza como el siguiente input del Decoder.
En este caso, la probabilidad máxima en el primer step es p4, luego al ingresar p4 como input, la probabilidad máxima es p2, y así sucesivamente.
En este caso se pueden escoger múltiples caminos en vez de solamente el de mayor probabilidad. Por ejemplo, si se escogen 2 caminos (beam width = 2), en el primer step se escogen los tokens con probabilidad p4 y p3. Luego en el segundo step, se generan las siguientes probabilidades para los distintos caminos. Acá se escoge el camino con la mayor probabilidad conjunta.
Supongamos queremos traducir la frase “Good Night” al español.
| Token | Probabilidad |
|---|---|
| good | 0.45 |
| nice | 0.15 |
| well | 0.10 |
| hello | 0.30 |
Greedy Search diría que la predicción de la primera palabra es good (p=0.45)
Beam Search con width=2 diría lo siguiente:
| 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 |
| 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:
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.
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.
