Hay muchas aplicaciones para el aprendizaje automático, y una de ellas es el procesamiento del lenguaje natural o PNL.

PNL maneja cosas como respuestas de texto, descifrar el significado de las palabras dentro de un contexto y mantener conversaciones con nosotros. Ayuda a las computadoras a comprender el lenguaje humano para que podamos comunicarnos de diferentes maneras.

Desde los bots de chat hasta las solicitudes de empleo y la clasificación de tu correo electrónico en diferentes carpetas, PNL se utiliza en todas partes a nuestro alrededor.

En esencia, el procesamiento del lenguaje natural es una combinación de informática y lingüística. La lingüística nos brinda las reglas que debemos usar para entrenar nuestros modelos de aprendizaje automático y obtener los resultados que buscamos.

Hay muchas razones por las que el procesamiento del lenguaje natural se ha convertido en una parte importante del aprendizaje automático. Ayuda a las máquinas a detectar el sentimiento de los comentarios de un cliente, puede ayudar a clasificar los tickets de soporte para cualquier proyecto en el que estés trabajando y puede leer y comprender el texto de manera coherente.

Y dado que opera con un conjunto de reglas lingüísticas, no tiene los mismos prejuicios que los humanos.

Dado que PNL es un área de estudio tan grande, hay una serie de herramientas que puedes utilizar para analizar datos para tus propósitos específicos.

Existe el enfoque basado en reglas en el que se configuran muchas declaraciones si-entonces (if-then) para manejar cómo se interpreta el texto. Por lo general, un lingüista será responsable de esta tarea y lo que producen es muy fácil de entender para la gente.

Esto puede ser bueno para empezar, pero se vuelve muy complejo a medida que comienzas a trabajar con grandes conjuntos de datos.

Otro enfoque es utilizar aprendizaje automático donde no es necesario definir reglas. Esto es excelente cuando intentas analizar grandes cantidades de datos de forma rápida y precisa.

Elegir el algoritmo correcto para que el enfoque de aprendizaje automático funcione es importante en términos de eficiencia y precisión. Existen algoritmos comunes como Naïve Bayes y Support Vector Machines. Luego están los algoritmos más específicos como Google BERT

¿Qué es BERT?

BERT es una biblioteca de código abierto creada en 2018 en Google. Es una técnica nueva para PNL y adopta un enfoque de modelos de entrenamiento completamente diferente al de cualquier otra técnica.

BERT es un acrónimo de Representaciones de codificador bidireccional de Transformer. Eso significa que, a diferencia de la mayoría de las técnicas que analizan oraciones de izquierda a derecha o de derecha a izquierda, BERT va en ambas direcciones usando el codificador Transformer. Su objetivo es generar un modelo de lenguaje.

Esto le da una precisión y un rendimiento increíbles en conjuntos de datos más pequeños, lo que resuelve un gran problema en el procesamiento del lenguaje natural.

Si bien hay una gran cantidad de datos basados en texto disponibles, muy pocos de ellos se han etiquetado para usar en el entrenamiento de un modelo de aprendizaje automático. Dado que la mayoría de los enfoques para los problemas de PNL aprovechan el aprendizaje profundo (deep learning), necesita grandes cantidades de datos para entrenar.

Realmente se ven las grandes mejoras en un modelo cuando se ha entrenado con millones de datos. Para ayudar a solucionar este problema de no tener suficientes datos etiquetados, los investigadores encontraron formas de entrenar modelos de representación de lenguaje de propósito general a través del entrenamiento previo usando textos de Internet.

Estos modelos de representación previamente entrenados se pueden ajustar para que funcionen con conjuntos de datos específicos que son más pequeños que los que se usan comúnmente en el aprendizaje profundo. Estos conjuntos de datos más pequeños pueden ser para problemas como el análisis de opiniones o la detección de spam. Esta es la forma en que se abordan la mayoría de los problemas de PNL porque proporciona resultados más precisos que comenzar con un conjunto de datos más pequeño.

Es por eso que BERT es un gran descubrimiento. Proporciona una forma de pre-entrenar con mayor precisión tus modelos con menos datos. El enfoque bidireccional que utiliza significa que obtiene más contexto para una palabra que si solo estuviera entrenando en una dirección. Con este contexto adicional, puede aprovechar otra técnica llamada LM enmascarada.

En qué se diferencia de otros algoritmos de aprendizaje automático

El LM enmascarado enmascara al azar el 15% de las palabras en una oración con un símbolo o token [MASK] y luego trata de predecirlas basándose en las palabras que rodean a la palabra enmascarada. Así es como BERT puede ver las palabras de izquierda a derecha y de derecha a izquierda.

Esto es completamente diferente de cualquier otro modelo de lenguaje existente porque mira las palabras antes y después de una palabra enmascarada, al mismo tiempo. Gran parte de la precisión que tiene BERT se puede atribuir a esto.

Para que BERT funcione con tu conjunto de datos, debes agregar un poco de metadatos. Deberá haber incrustaciones de tokens (token embeddings) para marcar el principio y el final de las oraciones. Deberá tener incrustaciones de segmentos (segment embeddings) para poder distinguir diferentes oraciones. Por último, necesitará incrustaciones posicionales (positional embeddings) para indicar la posición de las palabras en una oración.

Se verá similar a esto.

[CLS] the [MASK] has blue spots [SEP] it rolls [MASK] the parking lot [SEP]

Con los metadatos agregados a tus puntos de datos (data points), LM enmascarado está listo para funcionar.

Una vez que ha terminado de predecir palabras, BERT aprovecha la predicción de la siguiente oración. Esto analiza la relación entre dos oraciones. Hace esto para comprender mejor el contexto de todo el conjunto de datos al tomar un par de oraciones y predecir si la segunda oración es la siguiente en función del texto original.

Para que la predicción de la siguiente oración funcione en la técnica BERT, la segunda oración se envía a través del modelo basado en Transformer.

Hay cuatro versiones diferentes de BERT previamente entrenadas según la escala de datos con la que estés trabajando. Puedes aprender más sobre ellos aquí: https://github.com/google-research/bert#bert

El inconveniente de este enfoque es que la función de pérdida solo considera las predicciones de palabras enmascaradas y no las predicciones de las demás. Eso significa que la técnica BERT converge más lentamente que las otras técnicas de derecha a izquierda o de izquierda a derecha.

BERT se puede aplicar a cualquier problema de PNL que se te ocurra, incluida la predicción de intenciones, las aplicaciones de respuesta a preguntas y la clasificación de texto.

Ejemplo de Código

Preparándote

Ahora veremos un ejemplo de BERT en acción. Lo primero que deberás hacer es clonar el repositorio de Bert.

git clone https://github.com/google-research/bert.git

Ahora necesita descargar los archivos de modelo BERT previamente entrenados desde la página BERT en GitHub. A lo largo del resto de este tutorial, me referiré al directorio de este repositorio como directorio raíz.

Estos archivos te brindan los hiperparámetros, pesos y otras cosas que necesitas con la información que Bert aprendió durante el entrenamiento previo. Usaré el modelo BERT-Base, Uncased, pero encontrarás varias otras opciones en diferentes idiomas en la página de GitHub.

Algunas de las razones por las que elegirías el modelo BERT-Base, Uncased es si no tienes acceso a una TPU de Google, en cuyo caso normalmente elegirías un modelo Base.

Si cree que el texto que estás tratando de analizar distingue entre mayúsculas y minúsculas (esa distinción le da un significado contextual real), entonces optarías por un modelo de tipo Cased.

Si la distinción entre mayúsculas y minúsculas no es importante o aún no está muy seguro, entonces un modelo de tipo Uncased sería una opción válida.

Trabajaremos con algunas reseñas de Yelp como nuestro conjunto de datos. Recuerda, BERT espera los datos en un formato determinado utilizando esas incrustaciones de tokens y otros. Necesitaremos agregarlos a un archivo .tsv. Este archivo será similar a un .csv, pero tendrá cuatro columnas y ninguna fila de encabezado.

Así es como se verán las cuatro columnas.

  • Columna 0: ID de la fila
  • Columna 1: Etiqueta de la fila (debe ser un número entero)
  • Columna 2: Una columna de la misma letra para todas las filas (no se usa para nada, pero BERT lo espera)
  • Columna 3: El texto que queremos clasificar

Deberás crear una carpeta llamada datos en el directorio donde clonaste BERT y agregar tres archivos allí: train.tsv, dev.tsv, test.tsv.

En los archivos train.tsv y dev.tsv, tendremos las cuatro columnas de las que hablamos anteriormente. En el archivo test.tsv, solo tendremos el ID de fila y el texto que queremos clasificar como columnas. Estos serán los archivos de datos que usaremos para entrenar y probar nuestro modelo.

Preparando los datos

Primero necesitamos obtener los datos con los que trabajaremos. Puedes descargar las reseñas de Yelp aquí: https://course.fast.ai/datasets#nlp Estará en la sección NLP y querrás la versión Polarity.

La razón por la que trabajaremos con esta versión es porque los datos ya tienen una polaridad, lo que significa que ya tienen un sentimiento asociado. Guarda este archivo en el directorio de datos.

Ahora estamos listos para comenzar a escribir código. Crea un nuevo archivo en el directorio raíz llamado pre_processing.py y agrega el siguiente código.

import pandas as pd
# esto es para extraer los datos de ese archivo .tgz
import tarfile
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split

# obtener todos los datos de ese .tgz
yelp_reviews = tarfile.open('data/yelp_review_polarity_csv.tgz')
yelp_reviews.extractall('data')
yelp_reviews.close()

# comprueba cómo se ven los datos antes de empezar
# mira el conjunto de datos de entrenamiento
train_df = pd.read_csv('data/yelp_review_polarity_csv/train.csv', header=None)
print(train_df.head())

# mira el conjunto de datos de prueba
test_df = pd.read_csv('data/yelp_review_polarity_csv/test.csv', header=None)
print(test_df.head())

En este código, hemos importado algunos paquetes de Python y descomprimimos los datos para ver cómo se ven. Notarás que los valores asociados con las reseñas son 1 y 2, siendo 1 una mala reseña y 2 una buena reseña. Necesitamos convertir estos valores a etiquetas más estándar, es decir 0 y 1. Puedes hacerlo con el siguiente código.

train_df[0] = (train_df[0] == 2).astype(int)
test_df[0] = (test_df[0] == 2).astype(int)

Siempre que realizes cambios a tus datos, es importante comprobar si todo salió bien. Entonces lo haremos con los siguientes comandos.

print(train_df.head())
print(test_df.head())

Cuando veas que tus valores de polaridad han cambiado para ser lo que esperabas. Ahora los datos deberían tener unos y ceros.

Dado que hemos limpiado los datos iniciales, es hora de preparar las cosas para BERT. Tendremos que hacer que nuestros datos se ajusten a los formatos de columna de los que hablamos anteriormente. Comencemos con los datos de entrenamiento.

Los datos de entrenamiento tendrán las cuatro columnas: ID de fila, etiqueta de fila, letra única, texto que queremos clasificar.

BERT espera dos archivos para entrenamiento llamados train y dev. Crearemos esos archivos dividiendo el archivo de entrenamiento inicial en dos archivos después de formatear nuestros datos con los siguientes comandos.

bert_df = pd.DataFrame({
    'id': range(len(train_df)),
    'label': train_df[0],
    'alpha': ['q']*train_df.shape[0],
    'text': train_df[1].replace(r'\n', ' ', regex=True)
})

train_bert_df, dev_bert_df = train_test_split(bert_df, test_size=0.01)

Con la variable bert_df, hemos formateado los datos para que sean los que espera BERT. Puedes elegir cualquier otra letra para el valor alpha si lo deseas. El método train_test_split que importamos al principio se encarga de dividir los datos de entrenamiento en los dos archivos que necesitamos.

Observa cómo se formatearon los datos con este comando.

print(train_bert_df.head())

Ahora necesitamos formatear los datos de prueba. Esto se verá diferente de cómo manejamos los datos de entrenamiento. BERT solo espera dos columnas para los datos de prueba: ID de fila, texto que queremos clasificar. No necesitamos hacer nada más con los datos de prueba una vez que los tengamos en este formato y lo haremos con el siguiente comando.

test_bert_df = pd.DataFrame({
    'id': range(len(test_df)),
    'text': test_df[1].replace(r'\n', ' ', regex=True)
})

Es similar a lo que hicimos con los datos de entrenamiento, solo que sin dos de las columnas. Echa un vistazo a los datos de prueba recién formateados.

test_bert_df.head()

Si todo se ve bien, puede guardar estas variables como los archivos .tsv con los que trabajará BERT.

train_bert_df.to_csv('data/train.tsv', sep='\t', index=False, header=False)
dev_bert_df.to_csv('data/dev.tsv', sep='\t', index=False, header=False)
test_bert_df.to_csv('data/test.tsv', sep='\t', index=False, header=False)

Entrenando el modelo

Una nota rápida antes de comenzar a entrenar el modelo: BERT puede consumir muchos recursos en las computadoras portátiles. Puede causar errores de memoria porque no hay suficiente RAM o algún otro hardware no es lo suficientemente potente. Podrías intentar hacer que training_batch_size sea más pequeño, pero eso hará que el entrenamiento del modelo sea realmente lento.

Agrega una carpeta al directorio raíz llamada model_output. Ahí es donde se guardará nuestro modelo una vez finalizado el entrenamiento. Ahora abre una terminal y ve al directorio raíz de este proyecto. Una vez que estés en el directorio correcto, ejecuta el siguiente comando y comenzará a entrenar tu modelo.

python run_classifier.py --task_name=cola --do_train=true --do_eval=true --data_dir=./data/ --vocab_file=./uncased_L-12_H-768_A-12/vocab.txt --bert_config_file=./uncased_L-12_H-768_A-12/bert_config.json --init_checkpoint=./uncased_L-12_H768_A-12/bert_model.ckpt.index --max_seq_length=128 --train_batch_size=32 --learning_rate=2e-5 --num_train_epochs=3.0 --output_dir=./model_output --do_lower_case=False

Deberías ver algunos resultados desplazándose a través de tu terminal. Una vez que esto termine de ejecutarse, tendrás un modelo entrenado que está listo para hacer predicciones.

Haciendo una predicción

Si echas un vistazo al directorio model_output, notarás que hay un montón de archivos model.ckpt. Estos archivos tienen los pesos del modelo entrenado en diferentes puntos durante el entrenamiento, por lo que deseas encontrar el que tenga el número más alto. Ese será el modelo entrenado final que querrás usar.

Ahora ejecutaremos run_classifier.py nuevamente con opciones ligeramente diferentes. En particular, cambiaremos el valor init_checkpoint al punto de control del modelo más alto y estableceremos un nuevo valor --do_predict en verdadero. Aquí está el comando que necesitas ejecutar en tu terminal.

python run_classifier.py --task_name=cola --do_predict=true --data_dir=./data --vocab_file=./uncased_L-12_H-768-A-12/bert_config.json --init_checkpoint=./model_output/model.ckpt-<highest checkpoint number> --max_seq_length=128 --output_dir=./model_output

Una vez que el comando termine de ejecutarse, debería ver un nuevo archivo llamado test_results.tsv. ¡Esto tendrá tus resultados predichos basados en el modelo que entrenaste!

Acabas de utilizar BERT para analizar algunos datos reales y, con suerte, todo esto tiene sentido.

Otros pensamientos

Sentí que era necesario pasar por el proceso de limpieza de datos aquí en caso de que alguien no lo haya pasado antes. A veces, el aprendizaje automático parece mágico, pero realmente se trata de tomarse el tiempo para que tus datos estén en las condiciones adecuadas para entrenar con un algoritmo.

BERT todavía es relativamente nuevo desde que se lanzó en 2018, pero hasta ahora ha demostrado ser más preciso que los modelos existentes, incluso si es más lento.

Traducido del artículo de Milecia McGregor - Google BERT NLP Machine Learning Tutorial