Blog
Cómo aprender y cargar incrustaciones de palabras (word embbeddings) en Keras
- Publicado por: Rafael Fernandez
- Categoría: Uncategorized
Las incrustaciones de palabras (word embbeddings) proporcionan una representación densa de palabras y sus significados relativos. Constituyen una mejora con respecto a las escasas representaciones que se utilizan en las representaciones de modelos de palabras más simples. Las word embbeddings pueden aprenderse a partir de datos de texto y reutilizarse en otros proyectos. También se pueden aprender como parte de la adaptación de una red neuronal en datos de texto. En este tutorial, descubrirás cómo usar incrustaciones de palabras para un Deep Learning en Python utilizando Keras. Después de completar este tutorial sabrás:
- Incrustaciones de palabras (word embbeddings)
- Keras admite incrustaciones de palabras a través de la capa de incrustación.
- Cómo aprender a incrustar o embeber una palabra mientras se adapta a una red neuronal.
- Cómo usar una palabra pre-entrenada incrustada o embebida en una red neuronal.
Descripción general del tutorial incrustaciones de palabras (word embbeddings) en Keras
Este tutorial está dividido en las siguientes partes:
- Incrustación de palabras
- Capa de incrustación Keras
- Ejemplo de aprendizaje e integración
- Ejemplo de uso de GloVe Embedding pre-entrenado
- Consejos para la limpieza de texto para incrustación de palabras
Incrustación de palabras
Una incrustación de palabras o word embeddings, son una clase de enfoques para representar palabras y documentos usando una representación vectorial densa. Se trata de una mejora con respecto a los esquemas tradicionales de codificación de modelos de Bag-Of- Words, en los que se utilizaban grandes vectores dispersos para representar cada palabra o para puntuar cada palabra dentro de un vector con el fin de representar un vocabulario completo. Estas representaciones eran escasas porque los vocabularios eran vastos y una palabra o documento dado sería representado por un gran vector compuesto en su mayoría de valores cero.
En cambio, en una incrustación, las palabras son representadas por vectores densos donde un vector representa la proyección de la palabra en un espacio vectorial continuo. La posición de una palabra dentro del espacio vectorial se aprende del texto y se basa en las palabras que rodean a la palabra cuando se usa. La posición de una palabra en el espacio vectorial aprendido se denomina incrustación. Dos ejemplos populares de métodos de aprendizaje de incrustaciones de palabras a partir de texto, incluyen:
- Word2Vec.
- GloVe.
Además de estos métodos cuidadosamente diseñados, se puede aprender a incrustar una palabra como parte de un modelo de Deep Learning. Este puede ser un enfoque más lento, pero adapta el modelo a un conjunto de datos de capacitación específico.
Capa de incrustación o embebida de Keras
Keras ofrece una capa de incrustación que se puede utilizar para redes neuronales en datos de texto. Requiere que los datos de entrada estén codificados en números enteros, de modo que cada palabra esté representada por un número entero único. Este paso de preparación de datos puede ser realizado usando la API de Tokenizer también provista con Keras.
La capa de incrustación se inicializa con pesos aleatorios y aprenderá una incrustación para todas las palabras del conjunto de datos de formación. Es una capa flexible que puede ser utilizada en una variedad de formas, tales como:
- Se puede usar solo para aprender una palabra incrustada que se puede guardar y usar en otro modelo más tarde.
- Se puede utilizar como parte de un modelo de Deep Learning en el que se aprende la incrustación junto con el propio modelo.
- Se puede utilizar para cargar un modelo de incrustación de palabras pre-entrenado, como un tipo de aprendizaje de transferencia.
La capa de incrustación se define como la primera capa oculta de una red. Debe especificar tres argumentos:
- entrada dim (input dim): Este es el tamaño del vocabulario en los datos de texto. Por ejemplo, si sus datos están codificados en números enteros con valores entre 0-10, entonces el tamaño del vocabulario sería de 11 palabras.
- atenuación de salida (output dim): Este es el tamaño del espacio vectorial en el que las palabras serán incrustadas. Define el tamaño de los vectores de salida de esta capa para cada palabra. Por ejemplo, podría ser 32 o 100 o incluso más grande. Intenta probar diferentes valores para tu problema.
- longitud de entrada (input length): Esta es la longitud de las secuencias de entrada, como definiría para cualquier capa de entrada de un modelo Keras. Por ejemplo, si todos los documentos de entrada constan de 1.000 palabras, serían 1.000.
Por ejemplo, a continuación definimos una capa de incrustación con un vocabulario de 200 (por ejemplo, palabras enteras codificadas de 0 a 199, inclusive), un espacio vectorial de 32 dimensiones en el que se incrustarán las palabras y documentos de entrada de 50 palabras cada uno.
e = Embedding(200, 32, input_length=50)
La capa de incrustación tiene pesos que aprenden. Si guardas tu modelo en un archivo, esto incluirá pesos para la capa de incrustación. La salida de la capa de incrustación es un vector 2D con una incrustación para cada palabra en la secuencia de entrada de palabras (documento de entrada). Si deseas conectar una capa densa directamente a una capa de incrustación, primero debe aplanar la matriz de salida 2D a un vector 1D utilizando la capa aplanada. Ahora, veamos cómo podemos usar una capa de incrustación en la práctica.
Ejemplo de aprendizaje e integración
En esta sección, veremos cómo podemos aprender a incrustar una palabra mientras adaptamos una red neuronal a un problema de clasificación de texto. Vamos a definir un pequeño problema donde tenemos 10 documentos de texto, cada uno con un comentario sobre un trabajo que un estudiante presentó. Cada documento de texto se clasifica como positivo 1 o negativo 0. Este es un simple problema de análisis de sentimientos. Primero, definiremos los documentos y sus etiquetas de clase.
# definir documentos docs = ['Well done!', 'Good work', 'Great effort', 'nice work', 'Excellent!', 'Weak', 'Poor effort!', 'not good', 'poor work', 'Could have done better.'] # definir rótulos de clase labels = array([1,1,1,1,1,0,0,0,0,0])
A continuación, podemos codificar cada documento en números enteros. Esto significa que como entrada la capa de incrustación tendrá secuencias de enteros. Podríamos experimentar con otra bolsa más sofisticada de codificación de modelos de palabras como conteos o TF-IDF. Keras proporciona una función one_hot() que crea un hash de cada palabra como una eficiente codificación entera. Estimaremos el tamaño del vocabulario de 50, que es mucho más grande de lo necesario para reducir la probabilidad de colisiones de la función hash.
# enteros codifican los documentos vocab_size = 50 encoded_docs = [one_hot(d, vocab_size) for d in docs] print(encoded_docs)
Las secuencias tienen diferentes longitudes y Keras prefiere que las entradas sean vectorizadas y que todas las entradas tengan la misma longitud. Vamos a rellenar todas las secuencias de entrada para tener la longitud de 4. De nuevo, podemos hacer esto con una función Keras incorporada, en este caso la función pad_sequences().
# documentos pad con una longitud máxima de 4 palabras max_length = 4 padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post') print(padded_docs)
Ahora estamos listos para definir nuestra capa de incrustación como parte de nuestro modelo de red neuronal. La capa de incrustación tiene un vocabulario de 50 y una longitud de entrada de 4. Escogeremos un pequeño espacio de incrustación de 8 dimensiones. El modelo, es un modelo simple de clasificación binaria. Es importante destacar que la salida de la capa de incrustación será de 4 vectores de 8 dimensiones cada uno; uno para cada palabra. Aplanamos esto a un vector de 32 elementos para pasar a la capa de salida densa.
# definir modelo model = Sequential() model.add(Embedding(vocab_size, 8, input_length=max_length)) model.add(Flatten()) model.add(Dense(1, activation='sigmoid')) # compilar modelo model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc']) # resumir modelo model.summary()
Finalmente, podemos ajustar y evaluar el modelo de clasificación.
# adaptarse al modelo model.fit(padded_docs, labels, epochs=50, verbose=0) # evaluar el modelo loss, accuracy = model.evaluate(padded_docs, labels, verbose=0) print('Precision: %f' % (accuracy*100))
La lista completa de códigos se proporciona a continuación.
from numpy import array from keras.preprocessing.text import one_hot from keras.preprocessing.sequence import pad_sequences from keras.models import Sequential from keras.layers import Dense from keras.layers import Flatten from keras.layers.embeddings import Embedding # definir documentos docs = ['Well done!', 'Good work', 'Great effort', 'nice work', 'Excellent!', 'Weak', 'Poor effort!', 'not good', 'poor work', 'Could have done better.'] # definir rótulos de clase labels = array([1,1,1,1,1,0,0,0,0,0]) # enteros codifican los documentos vocab_size = 50 encoded_docs = [one_hot(d, vocab_size) for d in docs] print(encoded_docs) # documentos pad con una longitud máxima de 4 palabras max_length = 4 padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post') print(padded_docs) # definir el modelo model = Sequential() model.add(Embedding(vocab_size, 8, input_length=max_length)) model.add(Flatten()) model.add(Dense(1, activation='sigmoid')) # compilar el modelo model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc']) # resumir el modelo model.summary() # adaptarse al modelo model.fit(padded_docs, labels, epochs=50, verbose=0) # evaluar el modelo loss, accuracy = model.evaluate(padded_docs, labels, verbose=0) print('Exactitud: %f'% (accuracy*100))
Ejecutando el ejemplo primero se imprimen los documentos enteros codificados.
[[37, 17], [46, 5], [1, 2], [46, 5], [17], [42], [24, 2], [31, 46], [24, 5], [31, 48, 17, 20]]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX por aqui xxxxxxxxxxxxxxxxxxxxxxx
Luego se imprimen las versiones acolchadas de cada documento, lo que hace que todos tengan una longitud uniforme.
[[ 6 16 0 0] [42 24 0 0] [ 2 17 0 0] [42 24 0 0] [18 0 0 0] [17 0 0 0] [22 17 0 0] [27 42 0 0] [22 24 0 0] [49 46 16 34]]
Después de definir la red, se imprime un resumen de las capas. Podemos ver que, como era de esperar, la salida de la capa de incrustación es una matriz de 4 x 8 y ésta es aplastada a un vector de 32 elementos por la capa de aplanamiento.
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding_1 (Embedding) (None, 4, 8) 400 _________________________________________________________________ flatten_1 (Flatten) (None, 32) 0 _________________________________________________________________ dense_1 (Dense) (None, 1) 33 ================================================================= Parametros totales: 433 Parametros entrenables: 433 Parametros no entrenables: 0 _________________________________________________________________
Finalmente, se imprime la precisión del modelo entrenado, mostrando que aprendió el conjunto de datos de entrenamiento perfectamente (lo cual no es sorprendente).
Exactitud: 100.000000
Puede guardar los pesos aprendidos de la capa de incrustación en un archivo para su uso posterior en otros modelos. También puede utilizar este modelo generalmente para clasificar otros documentos que tienen el mismo tipo de vocabulario visto en el conjunto de datos del examen. A continuación, veamos cómo cargar una palabra preentrenada incrustada en Keras.
Ejemplo de uso de GloVe Embedding pre-entrenado
La capa de incrustación de Keras también puede utilizar una palabra incrustada aprendida en otro lugar. Es común en el campo del Procesamiento del Lenguaje Natural aprender, guardar y hacer incrustaciones de palabras disponibles gratuitamente. Por ejemplo, los investigadores que están detrás del método GloVe proporcionan un conjunto de incrustaciones de palabras pre-aprendidas en su sitio web publicadas bajo una licencia de dominio público.
El paquete más pequeño de incrustaciones es de 822 Megabytes, llamado glove.6B.zip. Fue entrenado en un conjunto de datos de mil millones de tokens (palabras) con un vocabulario de 400 mil palabras. Existen diferentes tamaños de vectores de incrustación, incluyendo 50, 100, 200 y 300 dimensiones. Tú puedes descargar esta colección de incrustaciones y nosotros podemos sembrar la capa de incrustaciones Keras con pesos de la incrustación pre-entrenada para las palabras de su conjunto de datos de formación.
Este ejemplo está inspirado en un ejemplo del proyecto Keras: pretrained_word_embeddings.py. Después de descargar y descomprimir, veras algunos archivos, uno de los cuales es glove.6B.100d.txt, que contiene una versión de 100 dimensiones de la incrustación. Si miras dentro del archivo, verás un token (palabra) seguido de los pesos (100 números) en cada línea. Por ejemplo, a continuación se muestra la primera línea del archivo de texto ASCII de incrustación que muestra la incrustación del archivo.
the -0.038194 -0.24487 0.72812 -0.39961 0.083172 0.043953 -0.39141 0.3344 -0.57545 0.087459 0.28787 -0.06731 0.30906 -0.26384 -0.13231 -0.20757 0.33395 -0.33848 -0.31743 -0.48336 0.1464 -0.37304 0.34577 0.052041 0.44946 -0.46971 0.02628 -0.54155 -0.15518 -0.14107 -0.039722 0.28277 0.14393 0.23464 -0.31021 0.086173 0.20397 0.52624 0.17164 -0.082378 -0.71787 -0.41531 0.20335 -0.12763 0.41367 0.55187 0.57908 -0.33477 -0.36559 -0.54857 -0.062892 0.26584 0.30205 0.99775 -0.80481 -3.0243 0.01254 -0.36942 2.2167 0.72201 -0.24978 0.92136 0.034514 0.46745 1.1079 -0.19358 -0.074575 0.23353 -0.052062 -0.22044 0.057162 -0.15806 -0.30798 -0.41625 0.37972 0.15006 -0.53212 -0.2055 -1.2526 0.071624 0.70565 0.49744 -0.42063 0.26148 -1.538 -0.30223 -0.073438 -0.28312 0.37104 -0.25217 0.016215 -0.017099 -0.38984 0.87424 -0.72569 -0.51058 -0.52028 -0.1459 0.8278 0.27062
Como en la sección anterior, el primer paso es definir los ejemplos, codificarlos como enteros y luego rellenar las secuencias para que tengan la misma longitud. En este caso, necesitamos ser capaces de mapear palabras a enteros así como enteros a palabras. Keras proporciona una clase Tokenizer que puede caber en los datos de entrenamiento, puede convertir texto en secuencias consistentemente llamando al método texts_to_sequences() en la clase Tokenizer, y proporciona acceso al mapeo de palabras del diccionario a números enteros en un atributo word_index.
from numpy import array from keras.preprocessing.text import one_hot from keras.preprocessing.sequence import pad_sequences from keras.models import Sequential from keras.layers import Dense from keras.layers import Flatten from keras.layers.embeddings import Embedding # definir documentos docs = ['Well done!', 'Good work', 'Great effort', 'nice work', 'Excellent!', 'Weak', 'Poor effort!', 'not good', 'poor work', 'Could have done better.'] # definir rótulos de clase labels = array([1,1,1,1,1,0,0,0,0,0]) # preparar tokenizer t = Tokenizer() t.fit_on_texts(docs) vocab_size = len(t.word_index) + 1 # enteros codifican los documentos encoded_docs = t.texts_to_sequences(docs) print(encoded_docs) # documentos pad con una longitud máxima de 4 palabras max_length = 4 padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post') print(padded_docs)
A continuación, necesitamos cargar todo el archivo de incrustación de palabras de GloVe en la memoria como un diccionario de palabra a array de incrustación.
# cargar todo el incrustado en la memoria embeddings_index = dict() f = open('glove.6B.100d.txt') for line in f: values = line.split() word = values[0] coefs = asarray(values[1:], dtype='float32') embeddings_index[word] = coefs f.close() print('Cargando %s vectores de palabras.' % len(embeddings_index))
Esto es bastante lento. Puede que sea mejor filtrar la inserción de las palabras únicas en sus datos de entrenamiento. A continuación, necesitamos crear una matriz de una incrustación para cada palabra en el conjunto de datos de formación. Podemos hacerlo enumerando todas las palabras únicas en el índice Tokenizer.word_index y localizando el vector de peso de la incrustación desde la incrustación GloVe cargada. El resultado es una matriz de pesos sólo para las palabras que veremos durante el entrenamiento.
# crear una matriz de peso para las palabras en los documentos de formación embedding_matrix = zeros((vocab_size, 100)) for word, i in t.word_index.items(): embedding_vector = embeddings_index.get(word) if embedding_vector is not None: embedding_matrix[i] = embedding_vector
Ahora podemos definir nuestro modelo, ajustarlo y evaluarlo como antes. La diferencia clave es que la capa de incrustación puede ser sembrada con los pesos de incrustación de palabras de GloVe. Elegimos la versión de 100 dimensiones, por lo tanto la capa de incrustación debe definirse con la atenuación de salida ajustada a 100. Finalmente, no queremos actualizar los pesos de las palabras aprendidas en este modelo, por lo tanto estableceremos que el atributo entrenable para el modelo sea False (falso).
e = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False)
El ejemplo completo de trabajo se muestra a continuación.
from numpy import array from keras.preprocessing.text import one_hot from keras.preprocessing.sequence import pad_sequences from keras.models import Sequential from keras.layers import Dense from keras.layers import Flatten from keras.layers.embeddings import Embedding # definir documentos docs = ['Well done!', 'Good work', 'Great effort', 'nice work', 'Excellent!', 'Weak', 'Poor effort!', 'not good', 'poor work', 'Could have done better.'] # definir rótulos de clase labels = array([1,1,1,1,1,0,0,0,0,0]) # preparar tokenizer t = Tokenizer() t.fit_on_texts(docs) vocab_size = len(t.word_index) + 1 # enteros codifican los documentos encoded_docs = t.texts_to_sequences(docs) print(encoded_docs) # documentos pad con una longitud máxima de 4 palabras max_length = 4 padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post') print(padded_docs) # cargar todo el incrustado en la memoria embeddings_index = dict() f = open('glove.6B.100d.txt', mode='rt', encoding='utf-8') for line in f: values = line.split() word = values[0] coefs = asarray(values[1:], dtype='float32') embeddings_index[word] = coefs f.close() print('Cargando %s vectores de palabras.'% len(embeddings_index)) # crear una matriz de peso para las palabras en los documentos de formación embedding_matrix = zeros((vocab_size, 100)) for word, i in t.word_index.items(): embedding_vector = embeddings_index.get(word) if embedding_vector is not None: embedding_matrix[i] = embedding_vector # definir modelo model = Sequential() e = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False) model.add(e) model.add(Flatten()) model.add(Dense(1, activation='sigmoid')) # compilar el modelo model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc']) # resumir el modelo model.summary() # adaptarse al modelo model.fit(padded_docs, labels, epochs=50, verbose=0) #evaluar el modelo loss, accuracy = model.evaluate(padded_docs, labels, verbose=0) print('Exactitud: %f'% (accuracy*100))
Ejecutar el ejemplo puede tomar un poco más de tiempo, pero luego demuestra que es igual de capaz de encajar este simple problema.
... Exactitud: 100.000000
En la práctica, te animaría a experimentar con el aprendizaje de una incrustación de palabras usando una incrustación pre-entrenada que es fija y tratando de realizar el aprendizaje encima de una incrustación pre-entrenada. Vea qué es lo que mejor funciona para su problema específico.
Consejos para la limpieza de texto para incrustación de palabras
Recientemente, el campo del procesamiento del lenguaje natural se ha ido alejando de los modelos de Bag of Words y de la codificación de palabras hacia las incrustaciones de palabras. El beneficio de las incrustaciones de palabras es que codifican cada palabra en un vector denso que captura algo acerca de su significado relativo dentro del texto de capacitación. Esto significa que las variaciones de palabras como mayúsculas, minúsculas, ortografía, puntuación, etc. se aprenderán automáticamente a ser similares en el espacio de incrustación. A su vez, esto puede significar que la cantidad de limpieza requerida de su texto puede ser menor y quizás bastante diferente a la limpieza de texto clásica. Por ejemplo, puede que ya no tenga sentido detener las palabras o eliminar la puntuación de las contracciones.
Tomas Mikolov es uno de los desarrolladores de Word2Vec, un popular método de incrustación de palabras. Sugiere que sólo se requiere una limpieza mínima del texto cuando se aprende un modelo de incrustación de palabras.
➡ Aprende mucho mas de Procesamiento de Lenguaje Natural en nuestro curso:
Hola amigo, muchas gracias por tu trabajo, es EXCELENTE.
Soy algo nuevo en este campo y tengo una pregunta, cual modulo es mejor para incrustar las palabras KERAS o Gensim y por qué??
Nuevamente muchas gracias. Saludos desde Colombia.
Buenas Lucas, pues es una buena pregunta ya que veces es mejor de una forma u de otra todo se trata de probar y medir la eficiencia, saludos.