Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Incrustaciones de palabras

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Este tutorial contiene una introducción a las incrustaciones de palabras. Entrenará sus propias incrustaciones de palabras utilizando un modelo simple de Keras para una tarea de clasificación de sentimientos y luego las visualizará en el Proyector de incrustaciones (que se muestra en la imagen a continuación).

Captura de pantalla del proyector de incrustación

Representar texto como números

Los modelos de aprendizaje automático toman vectores (matrices de números) como entrada. Al trabajar con texto, lo primero que debe hacer es idear una estrategia para convertir cadenas en números (o "vectorizar" el texto) antes de alimentarlo al modelo. En esta sección, verá tres estrategias para hacerlo.

Codificaciones one-hot

Como primera idea, puede codificar "one-hot" cada palabra de su vocabulario. Considere la oración "El gato se sentó en la alfombra". El vocabulario (o palabras únicas) en esta oración es (cat, mat, on, sat, the). Para representar cada palabra, creará un vector cero con una longitud igual a la del vocabulario, luego colocará uno en el índice que corresponda a la palabra. Este enfoque se muestra en el siguiente diagrama.

Diagrama de codificaciones one-hot

Para crear un vector que contenga la codificación de la oración, puede concatenar los vectores one-hot para cada palabra.

Codifique cada palabra con un número único

Un segundo enfoque que podría intentar es codificar cada palabra con un número único. Continuando con el ejemplo anterior, podría asignar 1 a "gato", 2 a "tapete" y así sucesivamente. A continuación, podría codificar la oración "El gato se sentó en la alfombra" como un vector denso como [5, 1, 4, 3, 5, 2]. Este enfoque es eficaz. En lugar de un vector disperso, ahora tiene uno denso (donde todos los elementos están llenos).

Sin embargo, hay dos desventajas de este enfoque:

  • La codificación de números enteros es arbitraria (no captura ninguna relación entre palabras).

  • Una codificación de números enteros puede ser difícil de interpretar para un modelo. Un clasificador lineal, por ejemplo, aprende un solo peso para cada característica. Debido a que no existe una relación entre la similitud de dos palabras y la similitud de sus codificaciones, esta combinación de características y ponderaciones no es significativa.

Incrustaciones de palabras

Las incrustaciones de palabras nos brindan una forma de utilizar una representación densa y eficiente en la que palabras similares tienen una codificación similar. Es importante destacar que no tiene que especificar esta codificación a mano. Una incrustación es un vector denso de valores de punto flotante (la longitud del vector es un parámetro que usted especifica). En lugar de especificar los valores para la incrustación manualmente, son parámetros entrenables (pesos aprendidos por el modelo durante el entrenamiento, de la misma manera que un modelo aprende pesos para una capa densa). Es común ver incrustaciones de palabras que son de 8 dimensiones (para conjuntos de datos pequeños), hasta 1024 dimensiones cuando se trabaja con conjuntos de datos grandes. Una incrustación dimensional superior puede capturar relaciones detalladas entre palabras, pero requiere más datos para aprender.

Diagrama de una incrustación

Arriba hay un diagrama para una incrustación de palabras. Cada palabra se representa como un vector de 4 dimensiones de valores de coma flotante. Otra forma de pensar en una incrustación es como una "tabla de búsqueda". Una vez que se hayan aprendido estos pesos, puede codificar cada palabra buscando el vector denso al que corresponde en la tabla.

Preparar

import io
import os
import re
import shutil
import string
import tensorflow as tf

from datetime import datetime
from tensorflow.keras import Model, Sequential
from tensorflow.keras.layers import Activation, Dense, Embedding, GlobalAveragePooling1D
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization

Descarga el conjunto de datos de IMDb

Utilizará el conjunto de datos Large Movie Review a través del tutorial. Entrenará un modelo de clasificador de sentimientos en este conjunto de datos y, en el proceso, aprenderá las incorporaciones desde cero. Para obtener más información sobre cómo cargar un conjunto de datos desde cero, consulte el tutorial de texto Cargando .

Descargue el conjunto de datos usando la utilidad de archivo Keras y eche un vistazo a los directorios.

url = "https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz"

dataset = tf.keras.utils.get_file("aclImdb_v1.tar.gz", url,
                                    untar=True, cache_dir='.',
                                    cache_subdir='')

dataset_dir = os.path.join(os.path.dirname(dataset), 'aclImdb')
os.listdir(dataset_dir)
Downloading data from https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
84131840/84125825 [==============================] - 7s 0us/step

['imdbEr.txt', 'README', 'test', 'imdb.vocab', 'train']

Eche un vistazo al directorio train/ . Tiene carpetas pos y neg con reseñas de películas etiquetadas como positivas y negativas respectivamente. Utilizará revisiones de carpetas pos y neg para entrenar un modelo de clasificación binaria.

train_dir = os.path.join(dataset_dir, 'train')
os.listdir(train_dir)
['labeledBow.feat',
 'urls_pos.txt',
 'urls_neg.txt',
 'urls_unsup.txt',
 'unsup',
 'neg',
 'pos',
 'unsupBow.feat']

El directorio de train también tiene carpetas adicionales que deben eliminarse antes de crear un conjunto de datos de entrenamiento.

remove_dir = os.path.join(train_dir, 'unsup')
shutil.rmtree(remove_dir)

A continuación, cree un tf.data.Dataset utilizando tf.keras.preprocessing.text_dataset_from_directory . Puede leer más sobre el uso de esta utilidad en este tutorial de clasificación de texto .

Utilice el directorio de train para crear conjuntos de datos de entrenamiento y de validación con una división del 20% para la validación.

batch_size = 1024
seed = 123
train_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', batch_size=batch_size, validation_split=0.2, 
    subset='training', seed=seed)
val_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', batch_size=batch_size, validation_split=0.2, 
    subset='validation', seed=seed)
Found 25000 files belonging to 2 classes.
Using 20000 files for training.
Found 25000 files belonging to 2 classes.
Using 5000 files for validation.

Eche un vistazo a algunas reseñas de películas y sus etiquetas (1: positive, 0: negative) del conjunto de datos del tren.

for text_batch, label_batch in train_ds.take(1):
  for i in range(5):
    print(label_batch[i].numpy(), text_batch.numpy()[i])
0 b"Oh My God! Please, for the love of all that is holy, Do Not Watch This Movie! It it 82 minutes of my life I will never get back. Sure, I could have stopped watching half way through. But I thought it might get better. It Didn't. Anyone who actually enjoyed this movie is one seriously sick and twisted individual. No wonder us Australians/New Zealanders have a terrible reputation when it comes to making movies. Everything about this movie is horrible, from the acting to the editing. I don't even normally write reviews on here, but in this case I'll make an exception. I only wish someone had of warned me before I hired this catastrophe"
1 b'This movie is SOOOO funny!!! The acting is WONDERFUL, the Ramones are sexy, the jokes are subtle, and the plot is just what every high schooler dreams of doing to his/her school. I absolutely loved the soundtrack as well as the carefully placed cynicism. If you like monty python, You will love this film. This movie is a tad bit "grease"esk (without all the annoying songs). The songs that are sung are likable; you might even find yourself singing these songs once the movie is through. This musical ranks number two in musicals to me (second next to the blues brothers). But please, do not think of it as a musical per say; seeing as how the songs are so likable, it is hard to tell a carefully choreographed scene is taking place. I think of this movie as more of a comedy with undertones of romance. You will be reminded of what it was like to be a rebellious teenager; needless to say, you will be reminiscing of your old high school days after seeing this film. Highly recommended for both the family (since it is a very youthful but also for adults since there are many jokes that are funnier with age and experience.'
0 b"Alex D. Linz replaces Macaulay Culkin as the central figure in the third movie in the Home Alone empire. Four industrial spies acquire a missile guidance system computer chip and smuggle it through an airport inside a remote controlled toy car. Because of baggage confusion, grouchy Mrs. Hess (Marian Seldes) gets the car. She gives it to her neighbor, Alex (Linz), just before the spies turn up. The spies rent a house in order to burglarize each house in the neighborhood until they locate the car. Home alone with the chicken pox, Alex calls 911 each time he spots a theft in progress, but the spies always manage to elude the police while Alex is accused of making prank calls. The spies finally turn their attentions toward Alex, unaware that he has rigged devices to cleverly booby-trap his entire house. Home Alone 3 wasn't horrible, but probably shouldn't have been made, you can't just replace Macauley Culkin, Joe Pesci, or Daniel Stern. Home Alone 3 had some funny parts, but I don't like when characters are changed in a movie series, view at own risk."
0 b"There's a good movie lurking here, but this isn't it. The basic idea is good: to explore the moral issues that would face a group of young survivors of the apocalypse. But the logic is so muddled that it's impossible to get involved.<br /><br />For example, our four heroes are (understandably) paranoid about catching the mysterious airborne contagion that's wiped out virtually all of mankind. Yet they wear surgical masks some times, not others. Some times they're fanatical about wiping down with bleach any area touched by an infected person. Other times, they seem completely unconcerned.<br /><br />Worse, after apparently surviving some weeks or months in this new kill-or-be-killed world, these people constantly behave like total newbs. They don't bother accumulating proper equipment, or food. They're forever running out of fuel in the middle of nowhere. They don't take elementary precautions when meeting strangers. And after wading through the rotting corpses of the entire human race, they're as squeamish as sheltered debutantes. You have to constantly wonder how they could have survived this long... and even if they did, why anyone would want to make a movie about them.<br /><br />So when these dweebs stop to agonize over the moral dimensions of their actions, it's impossible to take their soul-searching seriously. Their actions would first have to make some kind of minimal sense.<br /><br />On top of all this, we must contend with the dubious acting abilities of Chris Pine. His portrayal of an arrogant young James T Kirk might have seemed shrewd, when viewed in isolation. But in Carriers he plays on exactly that same note: arrogant and boneheaded. It's impossible not to suspect that this constitutes his entire dramatic range.<br /><br />On the positive side, the film *looks* excellent. It's got an over-sharp, saturated look that really suits the southwestern US locale. But that can't save the truly feeble writing nor the paper-thin (and annoying) characters. Even if you're a fan of the end-of-the-world genre, you should save yourself the agony of watching Carriers."
0 b'I saw this movie at an actual movie theater (probably the $2.00 one) with my cousin and uncle. We were around 11 and 12, I guess, and really into scary movies. I remember being so excited to see it because my cool uncle let us pick the movie (and we probably never got to do that again!) and sooo disappointed afterwards!! Just boring and not scary. The only redeeming thing I can remember was Corky Pigeon from Silver Spoons, and that wasn\'t all that great, just someone I recognized. I\'ve seen bad movies before and this one has always stuck out in my mind as the worst. This was from what I can recall, one of the most boring, non-scary, waste of our collective $6, and a waste of film. I have read some of the reviews that say it is worth a watch and I say, "Too each his own", but I wouldn\'t even bother. Not even so bad it\'s good.'

Configurar el conjunto de datos para el rendimiento

Estos son dos métodos importantes que debe utilizar al cargar datos para asegurarse de que la E / S no se bloquee.

.cache() mantiene los datos en la memoria después de que se cargan del disco. Esto asegurará que el conjunto de datos no se convierta en un cuello de botella mientras entrena su modelo. Si su conjunto de datos es demasiado grande para caber en la memoria, también puede usar este método para crear una caché en disco de alto rendimiento, que es más eficiente de leer que muchos archivos pequeños.

.prefetch() superpone el preprocesamiento de datos y la ejecución del modelo durante el entrenamiento.

Puede obtener más información sobre ambos métodos, así como sobre cómo almacenar datos en caché en el disco en la guía de rendimiento de datos .

AUTOTUNE = tf.data.experimental.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

Usando la capa de incrustación

Keras facilita el uso de incrustaciones de palabras. Eche un vistazo a la capa de incrustación .

La capa de incrustación puede entenderse como una tabla de búsqueda que mapea desde índices enteros (que representan palabras específicas) a vectores densos (sus incrustaciones). La dimensionalidad (o ancho) de la incrustación es un parámetro con el que puede experimentar para ver qué funciona bien para su problema, de la misma manera que experimentaría con la cantidad de neuronas en una capa Densa.

# Embed a 1,000 word vocabulary into 5 dimensions.
embedding_layer = tf.keras.layers.Embedding(1000, 5)

Cuando crea una capa de incrustación, los pesos para la incrustación se inicializan aleatoriamente (como cualquier otra capa). Durante el entrenamiento, se ajustan gradualmente mediante retropropagación. Una vez entrenado, las incrustaciones de palabras aprendidas codificarán aproximadamente similitudes entre palabras (como se aprendieron para el problema específico en el que está entrenado su modelo).

Si pasa un número entero a una capa de incrustación, el resultado reemplaza cada entero con el vector de la tabla de incrustación:

result = embedding_layer(tf.constant([1,2,3]))
result.numpy()
array([[ 0.04530729, -0.04243072,  0.0484405 ,  0.04020107,  0.03276834],
       [-0.03076278,  0.0217622 , -0.02262014,  0.02947016,  0.00353047],
       [ 0.02572921, -0.03171467,  0.03230127, -0.02082225, -0.02455133]],
      dtype=float32)

Para problemas de texto o secuencia, la capa de incrustación toma un tensor 2D de números enteros, de forma (samples, sequence_length) , donde cada entrada es una secuencia de números enteros. Puede incrustar secuencias de longitudes variables. Puede introducir en la capa de incrustación por encima de lotes con formas (32, 10) (lote de 32 secuencias de longitud 10) o (64, 15) (lote de 64 secuencias de longitud 15).

El tensor devuelto tiene un eje más que la entrada, los vectores de incrustación se alinean a lo largo del nuevo último eje. Pasarle un lote de entrada (2, 3) y la salida es (2, 3, N)

result = embedding_layer(tf.constant([[0,1,2],[3,4,5]]))
result.shape
TensorShape([2, 3, 5])

Cuando se le da un lote de secuencias como entrada, una capa de incrustación devuelve un tensor de punto flotante 3D, de forma (samples, sequence_length, embedding_dimensionality) . Para convertir de esta secuencia de longitud variable a una representación fija, hay una variedad de enfoques estándar. Puede usar una capa RNN, Atención o agrupación antes de pasarla a una capa Densa. Este tutorial usa la agrupación porque es el más simple. La clasificación de texto con un tutorial de RNN es un buen paso siguiente.

Preprocesamiento de texto

A continuación, defina los pasos de procesamiento previo del conjunto de datos necesarios para su modelo de clasificación de opiniones. Inicialice una capa TextVectorization con los parámetros deseados para vectorizar reseñas de películas. Puede obtener más información sobre el uso de esta capa en el tutorial de Clasificación de texto .

# Create a custom standardization function to strip HTML break tags '<br />'.
def custom_standardization(input_data):
  lowercase = tf.strings.lower(input_data)
  stripped_html = tf.strings.regex_replace(lowercase, '<br />', ' ')
  return tf.strings.regex_replace(stripped_html,
                                  '[%s]' % re.escape(string.punctuation), '')

# Vocabulary size and number of words in a sequence.
vocab_size = 10000
sequence_length = 100

# Use the text vectorization layer to normalize, split, and map strings to 
# integers. Note that the layer uses the custom standardization defined above. 
# Set maximum_sequence length as all samples are not of the same length.
vectorize_layer = TextVectorization(
    standardize=custom_standardization,
    max_tokens=vocab_size,
    output_mode='int',
    output_sequence_length=sequence_length)

# Make a text-only dataset (no labels) and call adapt to build the vocabulary.
text_ds = train_ds.map(lambda x, y: x)
vectorize_layer.adapt(text_ds)

Crea un modelo de clasificación

Utilice la API secuencial de Keras para definir el modelo de clasificación de opiniones. En este caso se trata de un modelo estilo "Bolsa continua de palabras".

  • La capa TextVectorization transforma cadenas en índices de vocabulario. Ya ha inicializado vectorize_layer como una capa de TextVectorization y ha creado su vocabulario llamando a adapt en text_ds . Ahora vectorize_layer se puede utilizar como la primera capa de su modelo de clasificación de extremo a extremo, alimentando cadenas transformadas en la capa de incrustación.
  • La capa de Embedding toma el vocabulario codificado con números enteros y busca el vector de incrustación para cada índice de palabras. Estos vectores se aprenden a medida que se entrena el modelo. Los vectores agregan una dimensión a la matriz de salida. Las dimensiones resultantes son: (batch, sequence, embedding) .

  • La capa GlobalAveragePooling1D devuelve un vector de salida de longitud fija para cada ejemplo promediando la dimensión de la secuencia. Esto permite que el modelo maneje entradas de longitud variable, de la manera más simple posible.

  • El vector de salida de longitud fija se canaliza a través de una capa completamente conectada ( Dense ) con 16 unidades ocultas.

  • La última capa está densamente conectada con un solo nodo de salida.

embedding_dim=16

model = Sequential([
  vectorize_layer,
  Embedding(vocab_size, embedding_dim, name="embedding"),
  GlobalAveragePooling1D(),
  Dense(16, activation='relu'),
  Dense(1)
])

Compilar y entrenar el modelo

Utilizará TensorBoard para visualizar métricas, incluidas la pérdida y la precisión. Cree un tf.keras.callbacks.TensorBoard .

tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir="logs")

Compile y entrene el modelo utilizando el optimizador de Adam y la pérdida de BinaryCrossentropy .

model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.fit(
    train_ds,
    validation_data=val_ds, 
    epochs=15,
    callbacks=[tensorboard_callback])
Epoch 1/15
 1/20 [>.............................] - ETA: 0s - loss: 0.6933 - accuracy: 0.4961WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/summary_ops_v2.py:1277: stop (from tensorflow.python.eager.profiler) is deprecated and will be removed after 2020-07-01.
Instructions for updating:
use `tf.profiler.experimental.stop` instead.
20/20 [==============================] - 2s 96ms/step - loss: 0.6919 - accuracy: 0.5028 - val_loss: 0.6897 - val_accuracy: 0.4886
Epoch 2/15
20/20 [==============================] - 1s 73ms/step - loss: 0.6867 - accuracy: 0.5028 - val_loss: 0.6832 - val_accuracy: 0.4886
Epoch 3/15
20/20 [==============================] - 1s 72ms/step - loss: 0.6779 - accuracy: 0.5028 - val_loss: 0.6724 - val_accuracy: 0.4886
Epoch 4/15
20/20 [==============================] - 1s 73ms/step - loss: 0.6640 - accuracy: 0.5028 - val_loss: 0.6566 - val_accuracy: 0.4886
Epoch 5/15
20/20 [==============================] - 1s 73ms/step - loss: 0.6444 - accuracy: 0.5028 - val_loss: 0.6357 - val_accuracy: 0.4890
Epoch 6/15
20/20 [==============================] - 1s 73ms/step - loss: 0.6193 - accuracy: 0.5267 - val_loss: 0.6105 - val_accuracy: 0.5480
Epoch 7/15
20/20 [==============================] - 1s 73ms/step - loss: 0.5895 - accuracy: 0.6035 - val_loss: 0.5823 - val_accuracy: 0.6154
Epoch 8/15
20/20 [==============================] - 1s 74ms/step - loss: 0.5568 - accuracy: 0.6758 - val_loss: 0.5532 - val_accuracy: 0.6644
Epoch 9/15
20/20 [==============================] - 1s 73ms/step - loss: 0.5233 - accuracy: 0.7263 - val_loss: 0.5251 - val_accuracy: 0.7028
Epoch 10/15
20/20 [==============================] - 1s 73ms/step - loss: 0.4910 - accuracy: 0.7606 - val_loss: 0.4995 - val_accuracy: 0.7338
Epoch 11/15
20/20 [==============================] - 1s 73ms/step - loss: 0.4611 - accuracy: 0.7844 - val_loss: 0.4771 - val_accuracy: 0.7502
Epoch 12/15
20/20 [==============================] - 1s 73ms/step - loss: 0.4343 - accuracy: 0.8032 - val_loss: 0.4581 - val_accuracy: 0.7642
Epoch 13/15
20/20 [==============================] - 1s 73ms/step - loss: 0.4104 - accuracy: 0.8171 - val_loss: 0.4422 - val_accuracy: 0.7718
Epoch 14/15
20/20 [==============================] - 1s 73ms/step - loss: 0.3893 - accuracy: 0.8297 - val_loss: 0.4289 - val_accuracy: 0.7826
Epoch 15/15
20/20 [==============================] - 1s 73ms/step - loss: 0.3705 - accuracy: 0.8401 - val_loss: 0.4178 - val_accuracy: 0.7900

<tensorflow.python.keras.callbacks.History at 0x7fb7f045bc50>

Con este enfoque, el modelo alcanza una precisión de validación de alrededor del 84% (tenga en cuenta que el modelo está sobreajustado ya que la precisión del entrenamiento es mayor).

Puede consultar el resumen del modelo para obtener más información sobre cada capa del modelo.

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
text_vectorization (TextVect (None, 100)               0         
_________________________________________________________________
embedding (Embedding)        (None, 100, 16)           160000    
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 16)                272       
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 17        
=================================================================
Total params: 160,289
Trainable params: 160,289
Non-trainable params: 0
_________________________________________________________________

Visualiza las métricas del modelo en TensorBoard.

%tensorboard --logdir logs

embeddings_classifier_accuracy.png

Recupere las incrustaciones de palabras entrenadas y guárdelas en el disco

A continuación, recupere las incorporaciones de palabras aprendidas durante el entrenamiento. Las incrustaciones son pesos de la capa de incrustación en el modelo. La matriz de ponderaciones tiene forma (vocab_size, embedding_dimension) .

vocab = vectorize_layer.get_vocabulary()
print(vocab[:10])
# Get weights matrix of layer named 'embedding'
weights = model.get_layer('embedding').get_weights()[0]
print(weights.shape) 
['', '[UNK]', 'the', 'and', 'a', 'of', 'to', 'is', 'in', 'it']
(10000, 16)

Escribe los pesos en el disco. Para usar el Proyector de incrustación , deberá cargar dos archivos en formato separado por tabulaciones: un archivo de vectores (que contiene la incrustación) y un archivo de metadatos (que contiene las palabras).

  out_v = io.open('vecs.tsv', 'w', encoding='utf-8')
  out_m = io.open('meta.tsv', 'w', encoding='utf-8')

  for num, word in enumerate(vocab):
    if num == 0: continue # skip padding token from vocab
    vec = weights[num]
    out_m.write(word + "\n")
    out_v.write('\t'.join([str(x) for x in vec]) + "\n")
  out_v.close()
  out_m.close()

  try:
    from google.colab import files
  except ImportError:
    pass
  else:
    files.download('vecs.tsv')
    files.download('meta.tsv')

Si está ejecutando este tutorial en Colaboratory , puede utilizar el siguiente fragmento para descargar estos archivos en su máquina local (o utilizar el explorador de archivos, Ver -> Tabla de contenido -> Explorador de archivos ).

Visualiza las incrustaciones

Para visualizar las incrustaciones, cárguelas en el proyector de incrustaciones.

Abra el Proyector de incrustación (esto también se puede ejecutar en una instancia local de TensorBoard).

  • Haga clic en "Cargar datos".

  • Sube los dos archivos que creaste anteriormente: vecs.tsv y meta.tsv .

Ahora se mostrarán las incrustaciones que ha entrenado. Puede buscar palabras para encontrar a sus vecinos más cercanos. Por ejemplo, intente buscar "hermoso". Es posible que vea a los vecinos como "maravillosos".

Próximos pasos

Este tutorial le ha mostrado cómo entrenar y visualizar incrustaciones de palabras desde cero en un pequeño conjunto de datos.

  • Para obtener más información sobre las incrustaciones de palabras y sus representaciones matemáticas, consulte esta nota de Stanford.

  • Para obtener más información sobre el procesamiento de texto avanzado, lea el modelo Transformer para comprender el idioma .