BERT es un modelo de lenguaje de vanguardia para 104 idiomas. Tutorial para lanzar BERT localmente y en Google Colab

imagen


BERT es una red neuronal de Google, que mostró por un amplio margen resultados de vanguardia en una serie de tareas. Con BERT, puede crear programas de inteligencia artificial para procesar un lenguaje natural: responda preguntas formuladas de cualquier forma, cree bots de chat, traductores automáticos, analice texto, etc.


Google ha publicado modelos BERT previamente entrenados, pero como suele ser el caso con Machine Learning, carecen de documentación. Por lo tanto, en este tutorial aprenderemos cómo ejecutar la red neuronal BERT en la computadora local, así como en la GPU del servidor gratuito en Google Colab.


¿Por qué es necesario?


Para enviar texto a la entrada de una red neuronal, debe presentarlo de alguna manera en forma de números. Es más fácil hacer esta letra por letra, aplicando una letra a cada entrada de la red neuronal. Luego, cada letra se codificará con un número del 0 al 32 (más algún tipo de margen para los signos de puntuación). Este es el llamado nivel de personaje.


Pero se obtienen resultados mucho mejores si presentamos propuestas no por una letra, sino al enviar a cada entrada de la red neuronal inmediatamente una palabra completa (o al menos sílabas). Ya será un nivel de palabra. La opción más fácil es compilar un diccionario con todas las palabras existentes y alimentar a la red el número de palabras en este diccionario. Por ejemplo, si la palabra "perro" está en este diccionario en el lugar 1678, entonces ingresamos el número 1678 para la entrada de la red neuronal para esta palabra.


Pero solo en un lenguaje natural, con la palabra "perro", surgen muchas asociaciones a la vez en una persona: "esponjoso", "malvado", "amigo de una persona". ¿Es posible codificar de alguna manera esta característica de nuestro pensamiento en la presentación de la red neuronal? Resulta que puedes. Para hacer esto, es suficiente reordenar los números de palabras para que las palabras que tienen un significado cercano estén una al lado de la otra. Sea, por ejemplo, para "perro" el número 1678, y para la palabra "esponjoso" el número 1680. Y para la palabra "tetera" el número es 9000. Como puede ver, los números 1678 y 1680 están mucho más cerca entre sí que el número 9000.


En la práctica, a cada palabra se le asigna no un número, sino varios: un vector, digamos, de 32 números. Y las distancias se miden como las distancias entre los puntos a los que apuntan estos vectores en el espacio de la dimensión correspondiente (para un vector de 32 dígitos de largo, este es un espacio con 32 dimensiones o con 32 ejes). Esto le permite comparar una palabra a la vez con varias palabras que tienen un significado cercano (dependiendo de qué eje contar). Además, las operaciones aritméticas se pueden realizar con vectores. Un ejemplo clásico: si resta el vector "hombre" del vector que denota la palabra "rey" y agrega el vector para la palabra "mujer", obtendrá un determinado vector de resultado. Y él corresponderá milagrosamente a la palabra "reina". Y de hecho, "rey es hombre + mujer = reina". La magia! Y este no es un ejemplo abstracto, pero realmente sucede . Teniendo en cuenta que las redes neuronales están bien adaptadas para las transformaciones matemáticas sobre sus entradas, esto aparentemente proporciona una eficacia tan alta de este método.


Este enfoque se llama incrustaciones. Todos los paquetes de aprendizaje automático (TensorFlow, PyTorch) permiten que la primera capa de la red neuronal coloque una capa especial de Capa de incrustación, que lo hace automáticamente. Es decir, en la entrada de la red neuronal, enviamos el número de palabra habitual en el diccionario, y Embedded Layer, el autoaprendizaje, traduce cada palabra en un vector de la longitud especificada, digamos, 32 números.


Pero rápidamente se dieron cuenta de que es mucho más rentable entrenar previamente una representación de palabras de este tipo en un corpus de textos enorme, por ejemplo, en toda Wikipedia, y usar vectores de palabras ya preparados en redes neuronales específicas en lugar de entrenarlos nuevamente.


Hay varias formas de representar palabras como vectores; evolucionaron gradualmente: word2vec, GloVe, Elmo.


En el verano de 2018, OpenAI notó que si pre-entrena una red neuronal en la arquitectura Transformer en grandes volúmenes de texto, inesperadamente y por un amplio margen muestra excelentes resultados en muchos tipos diferentes de tareas de procesamiento de lenguaje natural. De hecho, dicha red neuronal en su salida crea representaciones vectoriales de palabras e incluso frases completas. Y al colgar encima de un modelo de lenguaje de este tipo un pequeño bloque de un par de capas adicionales de neuronas, puede entrenar esta red neuronal para cualquier tarea.


BERT de Google es una red avanzada de GPA de OpenAI (bidireccional en lugar de unidireccional, etc.), también basada en la arquitectura Transformer. Por el momento, BERT es lo último en casi todos los puntos de referencia populares de PNL.


Como lo hicieron


La idea detrás de BERT es muy simple: alimentemos la red neuronal con frases en las que reemplazamos el 15% de las palabras con [MÁSCARA] y entrenemos la red neuronal para predecir estas palabras enmascaradas.


Por ejemplo, si enviamos la frase "Vine a [MASK] y compré [MASK]" a la entrada de la red neuronal, debería mostrar las palabras "store" y "milk" en la salida. Este es un ejemplo simplificado de la página oficial BERT; en oraciones más largas, el rango de opciones posibles se vuelve más pequeño, y la respuesta de la red neuronal es inequívoca.


Y para que la red neuronal aprenda a comprender la relación entre diferentes oraciones, también la entrenaremos para predecir si la segunda frase es una continuación lógica de la primera. ¿O es una frase aleatoria que no tiene nada que ver con la primera.


Entonces, para dos oraciones: "Fui a la tienda". y "Y compré leche allí", la red neuronal debería responder que esto es lógico. Y si la segunda frase es "Crucian sky Pluto", entonces debo responder que esta propuesta no tiene nada que ver con la primera. Vamos a jugar con estos dos modos BERT a continuación.


Habiendo entrenado así la red neuronal en el cuerpo de textos de Wikipedia y la colección de libros BookCorpus durante 4 días a 16 TPU, obtuvimos BERT.


Instalación y configuración


Nota : en esta sección iniciaremos y jugaremos con BERT en la computadora local. Para ejecutar esta red neuronal en una GPU local, necesitará una NVidia GTX 970 con 4 GB de memoria de video o superior. Si solo desea ejecutar BERT en un navegador (ni siquiera necesita una GPU en su computadora para esto), vaya a la sección Google Colab.


Primero instale TensorFlow, si aún no lo tiene, siguiendo las instrucciones de https://www.tensorflow.org/install . Para admitir la GPU, primero debe instalar CUDA Toolkit 9.0, luego cuDNN SDK 7.2, y solo luego TensorFlow con soporte de GPU:


pip install tensorflow-gpu 

Básicamente, esto es suficiente para ejecutar BERT. Pero no hay instrucciones como tales, puede componerlo usted mismo ordenando las fuentes en el archivo run_classifier.py (la situación habitual en Machine Learning es cuando tiene que ir a las fuentes en lugar de la documentación). Pero lo haremos más fácil y usaremos el shell Keras BERT (también puede ser útil para ajustar la red más adelante, ya que proporciona una interfaz Keras conveniente).


Para hacer esto, instale Keras:


 pip install keras 

Y después de Keras BERT:


 pip install keras-bert 

También necesitaremos el archivo tokenization.py del github BERT original. Haga clic en el botón Sin procesar y guárdelo en la carpeta con el script futuro, o descargue todo el repositorio y tome el archivo desde allí, o tome una copia del repositorio con este código https://github.com/blade1780/bert .


Ahora es el momento de descargar la red neuronal pre-entrenada. Hay varias opciones para BERT, todas las cuales se enumeran en la página oficial github.com/google-research/bert . Tomaremos la "Base BERT universal multilingüe", con funda multilingüe, para 104 idiomas. Descargue el archivo multi_cased_L-12_H-768_A-12.zip (632 Mb) y descomprímalo en la carpeta con el script futuro.


Todo está listo, cree el archivo BERT.py, luego habrá un poco de código.


Importar bibliotecas necesarias y establecer rutas


 # coding: utf-8 import sys import codecs import numpy as np from keras_bert import load_trained_model_from_checkpoint import tokenization # ,     BERT folder = 'multi_cased_L-12_H-768_A-12' config_path = folder+'/bert_config.json' checkpoint_path = folder+'/bert_model.ckpt' vocab_path = folder+'/vocab.txt' 

Como tendremos que traducir líneas de texto ordinarias a un formato especial de tokens, crearemos un objeto especial para esto. Presta atención a do_lower_case = False, ya que estamos usando el modelo Cased BERT, que distingue entre mayúsculas y minúsculas.


 tokenizer = tokenization.FullTokenizer(vocab_file=vocab_path, do_lower_case=False) 

Modelo de carga


 model = load_trained_model_from_checkpoint(config_path, checkpoint_path, training=True) model.summary() 

BERT puede funcionar en dos modos: adivinar las palabras perdidas en la frase o adivinar si la segunda frase es lógica después de la primera. Haremos ambas opciones.


Para el primer modo, debe enviar una frase en el formato:


 [CLS]    [MASK]   [MASK]. [SEP] 

La red neuronal debería devolver una oración completa con las palabras completadas en lugar de las máscaras: "Vine a la tienda y compré leche".


Para el segundo modo, ambas frases separadas por un separador deben alimentarse a la entrada de la red neuronal:


 [CLS]    . [SEP]   . [SEP] 

La red neuronal debe responder si la segunda frase es una continuación lógica de la primera. ¿O es una frase aleatoria que no tiene nada que ver con la primera.


Para que BERT funcione, debe preparar tres vectores, cada uno con una longitud de 512 números: token_input, seg_input y mask_input.


Token_input almacenará nuestro código fuente traducido a tokens usando tokenizer. La frase en forma de índices en el diccionario estará al comienzo de este vector, y el resto estará lleno de ceros.


En mask_input, debemos poner 1 para todas las posiciones donde está la máscara [MASK], y completar el resto con ceros.


En seg_input, debemos denotar la primera frase (incluyendo el CLS inicial y el separador SEP) como 0, la segunda frase (incluyendo el SEP final) como 1, y completar el resto hasta el final del vector con ceros.


BERT no usa un diccionario de palabras completas, sino de las sílabas más comunes. Aunque también tiene palabras completas. Puede abrir el archivo vocab.txt en la red neuronal descargada y ver qué palabras usa la red neuronal en su entrada. Hay palabras enteras como Francia. Pero la mayoría de las palabras rusas deben dividirse en sílabas. Por lo tanto, la palabra "vino" debe dividirse en "con" y "## fue". Para ayudar a convertir líneas de texto regulares al formato requerido por BERT, utilizamos el módulo tokenization.py.


Modo 1: Predicción de palabras cerradas por token [MÁSCARA] en una frase


La frase de entrada que se alimenta a la entrada de la red neuronal


 sentence = '   [MASK]   [MASK].' print(sentence) 

Conviértelo en tokens. El problema es que el tokenizer no puede procesar marcas de servicio como [CLS] y [MASK], aunque están en vocab.txt. Por lo tanto, tendremos que romper manualmente nuestra línea con marcadores [MÁSCARA] y extraer fragmentos de texto sin formato para convertirla en tokens BERT utilizando el tokenizador. Agregue también [CLS] al principio y [SEP] al final de la frase.


 sentence = sentence.replace(' [MASK] ','[MASK]'); sentence = sentence.replace('[MASK] ','[MASK]'); sentence = sentence.replace(' [MASK]','[MASK]') #    sentence = sentence.split('[MASK]') #     tokens = ['[CLS]'] #      [CLS] #        tokenizer.tokenize(),    [MASK] for i in range(len(sentence)): if i == 0: tokens = tokens + tokenizer.tokenize(sentence[i]) else: tokens = tokens + ['[MASK]'] + tokenizer.tokenize(sentence[i]) tokens = tokens + ['[SEP]'] #      [SEP] 

Los tokens ahora tienen tokens que están garantizados para convertirse en índices en el diccionario. Hagámoslo:


 token_input = tokenizer.convert_tokens_to_ids(tokens) 

Ahora en token_input hay una serie de números (números de palabras en el diccionario vocab.txt) que se deben alimentar a la entrada de la red neuronal. Solo queda extender este vector a una longitud de 512 elementos. La construcción Python [0] * length crea una matriz de longitud, llena de ceros. Simplemente agréguelo a nuestros tokens, que en Python combina dos matrices en una.


 token_input = token_input + [0] * (512 - len(token_input)) 

Ahora cree una máscara máscara de 512 de longitud, poniendo 1 en todas partes, donde el número 103 aparece en los tokens (que corresponde al marcador [MASK] en el diccionario vocab.txt), y llenando el resto con 0:


 mask_input = [0]*512 for i in range(len(mask_input)): if token_input[i] == 103: mask_input[i] = 1 

Para el primer modo de operación BERT, seg_input debe estar completamente lleno de ceros:


 seg_input = [0]*512 

El último paso, debe convertir las matrices de python en matrices numpy con forma (1,512), para lo cual las colocamos en una submatriz []:


 token_input = np.asarray([token_input]) mask_input = np.asarray([mask_input]) seg_input = np.asarray([seg_input]) 

OK, listo ¡Ahora ejecute la predicción de la red neuronal!


 predicts = model.predict([token_input, seg_input, mask_input])[0] predicts = np.argmax(predicts, axis=-1) predicts = predicts[0][:len(tokens)] #   ,    ,        

Ahora formatee el resultado de los tokens nuevamente en una cadena separada por espacios


 out = [] #   out     [MASK],    1  mask_input for i in range(len(mask_input[0])): if mask_input[0][i] == 1: # [0][i], ..   batch   (1,512),       out.append(predicts[i]) out = tokenizer.convert_ids_to_tokens(out) #     out = ' '.join(out) #       out = tokenization.printable_text(out) #    out = out.replace(' ##','') #   : " ##" -> "" 

Y muestra el resultado:


 print('Result:', out) 

En nuestro ejemplo, para la frase "Vine a [MASK] y compré [MASK]". la red neuronal produjo el resultado "casa" y "eso": "Vine a la casa y la compré". Bueno, no tan mal por primera vez. Comprar una casa es definitivamente mejor que la leche).


Otros ejemplos (no doy los que no tuvieron éxito, hay mucho más que los exitosos. En la mayoría de los casos, la red da una respuesta vacía):

La Tierra es la tercera [MÁSCARA] del Sol
Resultado: estrella


mejor sandwich [MÁSCARA] con mantequilla
Resultado: Cumple


después del almuerzo [MASK] se supone que debe dormir
Resultado: de esto


alejarse de [MÁSCARA]
Resultado: ## oh - ¿es algún tipo de maldición? )


[MÁSCARA] desde la puerta
Resultado: ver


Con [MASK] martillo y clavos pueden hacer gabinete
Resultado: ayuda


¿Y si mañana no es así? ¡Hoy, por ejemplo, no es [MÁSCARA]!
Resultado: será


¿Cómo te cansas de ignorar [MÁSCARA]?
Resultado: ella


Hay lógica cotidiana, hay lógica femenina, pero no se sabe nada sobre el hombre [MÁSCARA]
Resultado: filosofía


En las mujeres, a la edad de treinta años, se forma una imagen del príncipe, que se adapta a cualquier [MÁSCARA].
Resultado: hombre


Por mayoría de votos, Blancanieves y los siete enanos votaron a favor de [MÁSCARA], con un voto en contra.
Resultado: pueblo - la primera letra es correcta


Califique su tedio en una escala de 10 puntos: puntos [MÁSCARA]
Resultado: 10


¡Su [MÁSCARA], [MÁSCARA] y [MÁSCARA]!
Resultado: ámame, no, BERT, no quise decir nada


Puede ingresar frases en inglés (y cualquiera en 104 idiomas, una lista de los cuales está aquí )


[MÁSCARA] debe continuar!
Resultado: yo


Modo 2: verificar la consistencia de dos frases


Establecemos dos frases consecutivas que serán alimentadas a la entrada de la red neuronal


 sentence_1 = '   .' sentence_2 = '  .' print(sentence_1, '->', sentence_2) 

Crearemos tokens en el formato [CLS] frase_1 [SEP] frase_2 [SEP], convirtiendo texto plano en tokens usando el tokenizador:


 tokens_sen_1 = tokenizer.tokenize(sentence_1) tokens_sen_2 = tokenizer.tokenize(sentence_2) tokens = ['[CLS]'] + tokens_sen_1 + ['[SEP]'] + tokens_sen_2 + ['[SEP]'] 

Convertimos tokens de cadena en índices numéricos (números de palabras en el diccionario vocab.txt) y ampliamos el vector a 512:


 token_input = tokenizer.convert_tokens_to_ids(tokens) token_input = token_input + [0] * (512 - len(token_input)) 

La palabra máscara en este caso está completamente llena de ceros


 mask_input = [0] * 512 

Pero la máscara de la propuesta debe completarse bajo la segunda frase (incluido el SEP final) con unidades, y todo lo demás con ceros:


 seg_input = [0]*512 len_1 = len(tokens_sen_1) + 2 #   , +2 -   CLS   SEP for i in range(len(tokens_sen_2)+1): # +1, ..   SEP seg_input[len_1 + i] = 1 #   ,   SEP,  #   numpy   (1,) -> (1,512) token_input = np.asarray([token_input]) mask_input = np.asarray([mask_input]) seg_input = np.asarray([seg_input]) 

Pasamos las frases a través de la red neuronal (esta vez el resultado está en [1], y no en [0], como estaba arriba)


 predicts = model.predict([token_input, seg_input, mask_input])[1] 

Y derivamos la probabilidad de que la segunda frase sea un conjunto de palabras normal y no aleatorio


 print('Sentence is okey:', int(round(predicts[0][0]*100)), '%') 

En dos frases:


Yo vine a la tienda. -> Y compró leche.


Respuesta de red neuronal:


La oración es okey: 99%


Y si la segunda frase es "Crucian sky Pluto", entonces la respuesta será:


La oración es okey: 4%


Google colab


Google proporciona una GPU de servidor Tesla K80 gratuita con 12 Gb de memoria de video (las TPU ahora están disponibles, pero su configuración es un poco más complicada). Todo el código para Colab debe diseñarse como un cuaderno jupyter. Para iniciar BERT en un navegador, solo abra el enlace


http://colab.research.google.com/github/blade1780/bert/blob/master/BERT.ipynb


En el menú Tiempo de ejecución , seleccione Ejecutar todo , de modo que por primera vez se inicien todas las celdas, el modelo se descargue y se conecten las bibliotecas necesarias. Acepte restablecer todo el tiempo de ejecución si es necesario.


Si algo salió mal ...

Asegúrese de que GPU y Python 3 estén seleccionados en el menú Tiempo de ejecución -> Cambiar tipo de tiempo de ejecución


Si el botón de conexión no está activo, haga clic para conectarse.


Ahora cambie las líneas de entrada oración , oración_1 y oración_2 , y haga clic en el icono Reproducir a la izquierda para comenzar solo la celda actual. Ejecutar todo el portátil ya no es necesario.


Puede ejecutar BERT en Google Colab incluso desde un teléfono inteligente, pero si no se abre, es posible que deba habilitar la casilla de verificación Versión completa en la configuración de su navegador.


Que sigue


Para entrenar BERT para una tarea específica, debe agregar una o dos capas de una red de Feed Forward simple encima y solo entrenarla sin tocar la red BERT principal. Esto se puede hacer en TensorFlow desnudo o a través del shell Keras BERT. Dicha capacitación adicional para un dominio específico ocurre muy rápidamente y es completamente similar al Ajuste fino en redes de convolución. Entonces, para la tarea SQuAD, puede entrenar una red neuronal en un TPU en solo 30 minutos (en comparación con 4 días en 16 TPU para entrenar el BERT).


Para hacer esto, tendrá que estudiar cómo se representan las últimas capas en BERT, así como tener un conjunto de datos adecuado. En la página oficial de BERT https://github.com/google-research/bert hay varios ejemplos para diferentes tareas, así como instrucciones sobre cómo comenzar a readaptarse en TPU en la nube. Y todo lo demás tendrá que buscar en la fuente en los archivos run_classifier.py y extract_features.py .


PS


El código y el cuaderno jupyter para Google Colab presentados aquí están alojados en el repositorio .


No se deben esperar milagros. No esperes que BERT hable como una persona. El estado del estado de la técnica no significa en absoluto que el progreso en la PNL haya alcanzado un nivel aceptable. Simplemente significa que BERT es mejor que los modelos anteriores, que eran aún peores. La IA de conversación fuerte todavía está muy lejos. Además, BERT es principalmente un modelo de lenguaje, no un bot de chat listo, por lo que muestra buenos resultados solo después de volver a capacitarse para una tarea específica.

Source: https://habr.com/ru/post/es436878/


All Articles