En la entrega pasada vimos como clasificar textos usando la regresión logística. En la presente, discutiremos embeddings, que en términos simples, se define como una representación vectorial del significado de las palabras.
Aprender embeddings en el contexto de este proyecto es importante, porque son una piedra angular en los LLM contemporáneos. Como es usual, usaremos como referencia, el capítulo 5 de Jurafsky y Martin, 2025.
Lemma, wordform, y sense
Un LLM exitoso debería entender cómo se relacionan los significados de las palabras. Para eso, sería esperable que capture similitud, antonimia, connotación, distintas perspectivas sobre un mismo evento, y además permitir inferencias útiles para tareas como QA o diálogo. A continuación explicaremos en detalle cada una de ellas:
Similitud
El modelo debe ser capaz de reconocer qué palabras tienen un significado parecido aunque no sean idénticas. Por ejemplo, en Jurafsky y Martin, 2025, muestran que si bien, perro y gato no son sinónimos, son parecidas, debido a que, por ejemplo, ambos son animales. Esta noción de similitud es muy útil porque ayuda a estimar cuán parecidos son dos fragmentos más grandes, como frases u oraciones, algo central en tareas como question answering, paráfrasis y summarization.
Antonimia
La similitud nos permite identificar si dos palabras están relacionadas, pero no nos dice cómo se relacionan. Por ejemplo, caliente y frío están fuertemente relacionadas, pero no sólo porque estén asociadas a diferencias de temperatura, también porque son opuestos. Esto es importante porque una representación pobre podría tratar calor y frio como simplemente “palabras frecuentes del mismo tema”, cuando semánticamente cumplen funciones opuestas.
Connotación
Aquí el punto es capturar la carga afectiva o valorativa que lleva la palabra, esto es útil para tareas como sentiment analysis, stance detection y análisis de lenguaje político o reseñas.
Distintas perspectivas sobre un mismo evento
Jurafsky y Martin (2025) dice que palabras como buy, sell y pay ofrecen perspectivas distintas sobre un mismo evento subyacente: una transacción. Si yo compro algo, alguien me lo vende, y probablemente yo le pago.
Esto quiere decir que el significado no está solo en objetos aislados, sino también en roles dentro de una situación.
- comprar pone el foco en el comprador;
- vender pone el foco en el vendedor;
- pagar pone el foco en la transferencia de dinero.
No son sinónimos. Pero tampoco son eventos totalmente independientes. Son distintas “vistas” de la misma escena. Una teoría buena del significado debería poder representar esa estructura.
Permitir inferencias
Según los autores una buena representación debe permitir inferencias para resolver tareas relacionadas con el significado. Por ejemplo:
- Texto: “María compró un libro a Pedro.”
- Pregunta: “¿Pedro vendió un libro?”
Un sistema realmente semántico debería responder algo como “probablemente sí”, aunque la palabra vendió no aparezca literalmente. ¿Por qué? Porque entiende la relación entre comprar y vender como dos perspectivas del mismo evento. Ese tipo de salto es una inferencia semántica.
En resumen, el significado de una palabra no puede reducirse a una etiqueta. Una teoría útil debe modelar al menos parte de la red de relaciones que una palabra mantiene con otras palabras, con eventos, con valoraciones afectivas y con posibles inferencias.
Como veremos en la siguiente sección, el significado de una palabra puede representarse como un vector, y ese vector se obtiene a partir de los contextos en los que la palabra aparece.
Semántica vectorial
En la sección anterior vimos qué aspectos del significado de una palabra debería captar una buena teoría semántica. En esta sección veremos una forma de representar ese significado en NLP.
La idea principal es definir el significado de una palabra a partir de su distribución en el uso del lenguaje, es decir, de las palabras que suelen aparecer cerca de ella y de los entornos gramaticales en los que aparece.
Por ejemplo, supongamos que no sabemos el significado de la palabra faze, proveniente del castellano medieval. Está claro, que al extraer las siguientes frases del Libro de las animalias, de Moamyn,
E estos poluos q agora
diremos son pora la caletura q selesfazeen las
bocas.
los gusanos q seles
faze
en las moliellas.
dela seqdad q seles
fazedentro en los cuerpos
podemos ver que las oraciones sugieren que faze está relacionada con el verbo «hacer», en español moderno. En este sentido, podemos llevar este principio a la arena computacional, representando la palabra faze como un punto en un espacio semántico multidimensional; derivado usando la distribución de las palabras vecinas a ella. A esta representación vectorial del significado de faze, lo llamamos embedding.
Computando embeddings: modelo basado en el conteo
Empezaremos con el modelo vectorial de significado más simple. Para implementarlo, necesitamos llenar una matriz de co-occurrencia, que es una forma de representar cuán seguido las palabras co-occurren. Un tipo particular de matriz de co-occurrencia es la word-context matrix, en la que cada fila es una palabra del vocabulario, y cada columna indica cuán seguido aparecen las palabras vecinas de una fila particular. A modo de ejemplo, supongamos que disponemos de un corpus de dos oraciones, con una ventana de dos palabras vecinas:
q seles
fazedentro en
q seles
fazeen las
En base a esta información, una versión simplificada de la word-context matrix viene dada por:
| q | seles | dentro | en | las | |
faze | 2 | 2 | 1 | 2 | 1 |
Si bien la dimensión de esta matriz es 1×5, una word-context matrix debería tener dimensiones , esto, debido a que cada fila es una palabra del vocabulario, y cada columna, es una posible palabra vecina. Dicho esto, en nuestro caso, la matriz debería tener dimensión .
Como dijimos anteriormente, un embedding es una representación vectorial del significado de una palabra. En el caso de nuestra word-context matrix simplificada, faze es representada como el vector [2,2,1,2,1] -aunque la word-context matrix completa debería ser [2,2,1,2,1,0].
Puesto que el objetivo inicial de esta entrada es analizar cómo se relaciona el significado de dos palabras distintas, y ya sabemos cómo representarlo de forma vectorial, el siguiente paso lógico es medir qué tan similares son esas representaciones entre dos o más palabras. En la siguiente sección veremos cómo hacerlo.
Midiendo similitud entre vectores
La métrica que usaremos para medir similitud entre dos vectores, es la similitud coseno (puedes encontrar una definición acabada acá), cuya fórmula viene dada por:
donde y son representaciones vectoriales de las palabras v y w.
En teoría, puede devolver valores entre -1 y 1, con -1 para vectores apuntando en dirección opuesta, 1 para vectores apuntando a la misma dirección, y 0 para vectores ortogonales. Pero, debido a que y nunca serán negativos (porque son frecuencias), en esta aplicación, siempre estará entre 0 y 1.
Para ilustrar esta idea, tomaremos 20 textos medievales, y calculamos la word-context matrix correspondiente con una ventana de contexto de dos palabras. En este ejercicio, producimos un vocabulario de 35.340 palabras, con un vector de 35.340 elementos para cada palabra. En este sentido, si analizamos faze, podemos ver que los diez elementos más grandes del vector son
| Palabra | Frecuencia |
que | 437 |
se | 292 |
el | 196 |
en | 158 |
la | 124 |
por | 89 |
lo | 77 |
las | 75 |
seles | 75 |
lo | 74 |
indicando una buena señal, puesto que faze (hoy hace, del verbo hacer), suele estar acompañada de que y se.
Además, al calcular cosine similarity de faze contra el resto de las palabras del vocabulario, las diez que presentan mayor similitud son:
| Palabra | Cosine similarity |
fazie | 0.904950 |
fazen | 0.903953 |
mostraua | 0.897187 |
tornasse | 0.891229 |
yua | 0.885668 |
entienden | 0.885050 |
cumpliesse | 0.878845 |
cumpla | 0.876391 |
guardasse | 0.874317 |
nunqua | 0.871570 |
Vale la pena recordar que las palabras que aparecen en esta tabla son aquellas que ocurren en contextos parecidos a faze, y no necesariamente sus sinónimos. Por ejemplo, según estos resultados, fazie y fazen aparecen en entornos sintácticos similares. Esto resulta razonable, pues son formas cercanas a faze: fazie solía significar “hacía” y fazen, “hacen”. No obstante, aunque comparten contextos de uso similares, no son sinónimos estrictos.
Para visualizar de forma gráfica el concepto de similitud, utilizamos PCA para proyectar los vectores de palabras en dos dimensiones y, a continuación, graficamos algunas de ellas.

Como podemos ver, palabras que cumplen una función similar, como fazia, fazie y fizo, se encuentran cerca, y palabras con un significado distinto, no comparten una región similar.
Word2vec: skip-gram con sampleo negativo
Los vectores que hemos visto hasta el momento tienen una dimensión equivalente a la del tamaño del vocabulario. En nuestro ejemplo, faze, tiene dimensión 35.340, donde muchos componentes son cero.
En esta sección presentaremos embeddings representados mediante vectores relativamente cortos y densos, cuyos valores pueden incluso ser negativos. Como señalan Jurafsky y Martin (2025), este tipo de representación suele funcionar mejor que los vectores dispersos, es decir, aquellos con una gran cantidad de ceros. Una de las intuiciones principales es que, al tener menor dimensionalidad, el modelo aprende menos parámetros, lo que puede favorecer la generalización y reducir el riesgo de overfitting. Además, los embeddings densos suelen capturar mejor la similitud entre palabras semánticamente cercanas.
Para ilustrarlo, supongamos que en nuestro corpus medieval encontramos dos contextos muy parecidos:
dixo aquel que fezo el libro.
dixo aql q fezo el libro.
Si representamos estos contextos mediante vectores dispersos, aquel y aql ocuparán dimensiones distintas del vocabulario. Así, desde el punto de vista del vector, ambos contextos diferirán en coordenadas distintas, aunque para nosotros resulten muy cercanos en contenido. En cambio, con embeddings densos ya no tenemos una dimensión por cada palabra del vocabulario, sino un vector corto de rasgos latentes aprendidos a partir de los contextos de uso.
La intuición del algoritmo que introduciremos ahora es la siguiente: en vez de limitarnos a contar cuántas veces aparece una palabra cerca de dixo, entrenaremos un clasificador que estime si una palabra candidata es o no un contexto probable de dixo. Los pesos aprendidos por ese clasificador serán precisamente los embeddings.
El clasificador
El clasificador que queremos programar es uno que, dada una palabra objetivo y una palabra candidata , entregue la probabilidad de que sea una palabra de contexto real de . Por ejemplo, si consideramos la oración
dixo aquel que fezo el libro
y usamos una ventana de contexto , entonces el par constituye un ejemplo positivo, ya que libro aparece realmente en la ventana de contexto de fezo. En cambio, si tomamos una palabra del vocabulario que no aparece en esa ventana, por ejemplo aql, entonces el par puede utilizarse como ejemplo negativo.
Para formalizar esta tarea, definimos una variable binaria tal que
Entonces, el objetivo del clasificador es estimar la probabilidad
es decir, la probabilidad de que el par observado corresponda a una co-ocurrencia real de la palabra objetivo con una palabra de contexto.
En términos prácticos, para calcular esa probabilidad, el modelo asigna un vector denso para la palabra objetivo, y otro vector denso para la palabra candidata. Luego, para ver si ambos vectores son similares, se calcula el producto punto entre ambos, es decir,
y finalmente, para convertirlo en una probabilidad, se pasa por la sigmoide
Recordar que la sigmoide es creciente en su argumento, por tanto un mayor producto punto -que indica una mayor similitud entre vectores-, implicará una mayor probabilidad de que la palabra de que (w,c) sea un par positivo. Al asumir que todas las palabras de contexto son independientes, tenemos:
que es la expresión para la probabilidad del contexto completo observado, dado el target , bajo la hipótesis de que las palabras de contexto son condicionalmente independientes, donde es el tamaño la ventana de contexto.
Aprendiendo los parámetros del modelo
El algoritmo de aprendizaje de skip-gram con sampleo negativo toma como entrada un corpus de texto y un tamaño de vocabulario . A continuación, asigna de manera aleatoria embeddings iniciales a las palabras del vocabulario. Más precisamente, el modelo almacena dos vectores por palabra: uno cuando la palabra actúa como palabra objetivo y otro cuando actúa como palabra de contexto.
Luego, a partir del corpus, extrae pares positivos formados por una palabra objetivo y una palabra de contexto real dentro de una ventana dada. Para cada uno de estos pares, genera además pares negativos , donde es una palabra de ruido muestreada aleatoriamente del léxico. A modo de ejemplo, consideremos la siguiente oración:
q fezo sus
cosasbien copuestas.
cuya palabra objetivo es cosas y ventana de contexto +-2 palabras, entonces, podemos construir la siguiente tabla:
| fezo | sus | cosas | bien | compuestas |
| w |
Luego, debemos seleccionar los ejemplos positivos y negativos. Para el primer grupo tenemos:
cosas | fezo |
cosas | sus |
cosas | bien |
cosas | compuestas |
Para caracterizar el segundo grupo, debemos fijar el valor de . En este caso, con tenemos:
cosas | limpia |
cosas | fablo |
cosas | della |
cosas | recibieron |
cosas | altos |
cosas | reyes |
cosas | assi |
cosas | dizen |
Cuando caracterizamos el segundo grupo en la tabla anterior, elegimos arbitrariamente las ‘palabas ruidosas’. No obstante, en la práctica, deben ser tomadas de forma aleatoria desde el lexicon (cuya única restricción es que no contengan la palabra objetivo). La principal función que tienen estas palabras, es proporcionar un ejemplo negativo de entrenamiento. De este modo, el modelo aprende no solo a acercar la palabra objetivo a sus contextos reales, sino también a alejarla de palabras muestreadas como ruido en los ejemplos negativos.
Dichas palabras son elegidas de acuerdo a la siguiente probabilidad:
Donde count(w) cuenta cuántas veces aparece en el corpus, y el denominador normaliza la suma de los conteos ponderados de todas las palabras del vocabulario. es un parámetro que cuando es menor que uno, permite que los eventos raros sean mas probables que cuando .
A modo de resumen parcial, hasta este punto tenemos:
- Conjunto inicial de embeddings: cada palabra del vocabulario tiene un vector para cuando actúa como palabra objetivo y palabra de contexto, inicializados de forma aleatoria, con elementos.
- Conjunto de ejemplos positivos y negativos: el conjunto de ejemplos positivos se obtuvo del corpus, y el negativo se sampleó acorde a .
Con esto en mente, la estrategia que debemos seguir, es hacer que el modelo aprenda la posición de las palabras objetivo en el espacio de embeddings, es decir, cuáles quedan “lejos”, y cuáles quedan “cerca”. En este sentido, “cerca” o “lejos”, dependerá de , que a su vez, como vimos, depende del producto punto entre y . Específicamente, si una palabra apareció en la ventana real de la palabra objetivo (), el modelo asignará pesos tal que el producto punto () sea alto, porque así, también dará un valor relativamente alto. Por otra parte, si fue muestreada como noise word, entonces, se asignarán pesos tal que sea bajo, para que el modelo considere improbable que ese par sea un contexto real. Este principio se puede formalizar con la siguiente loss function:
Finalmente, podemos resumir el algoritmo completo en los siguientes pasos:
- Se fija un tamaño de vocabulario y una ventana de contexto, por ejemplo .
- Inicializamos dos embeddings aleatorios por palabra.
- Construimos ejemplos positivos: Recorremos el texto, y para cada palabra objetivo , tomamos las palabras que están dentro de su ventana de contexto como pares positivos .
- Construimos ejemplos negativos: Para cada par positivo , generamos pares negativos . Cada es una noise word, es decir, una palabra aleatoria del vocabulario, con la única restricción explícita de no ser la palabra objetivo . Esas palabras negativas no se eligen uniformemente, se muestrean según .
- Definimos un clasificador binario: Dado un par , el modelo quiere estimar la probabilidad de que sea una palabra de contexto real de . Para eso, usamos .
- Definimos la siguiente loss function:
- Actualizamos los embeddings con descenso por gradiente estocástico: El modelo recorre el corpus y, en cada ejemplo, ajusta las filas relevantes de y para minimizar esa loss function.
- Repetir muchas veces.
- Finalmente, obtenemos el embedding final de cada palabra: Como el modelo aprendió dos vectores por palabra, algunos investigadores la representan como , o bien, solo como .
Como dijimos anteriormente, los vectores densos resultantes de este proceso suelen capturar mejor la similitud entre palabras semánticamente cercanas, y poseen menos dimensiones que los vectores calculados a partir del método basado en el conteo.
Notas finales, y próxima entrada…
En esta entrada revisamos el concepto de embeddings, es decir, representaciones vectoriales que capturan aspectos del uso y significado de las palabras. Vimos que estas representaciones pueden construirse tanto con vectores dispersos como con vectores densos, y analizamos las principales propiedades de cada enfoque.
En la próxima entrada nos adentraremos en las redes neuronales, un componente fundamental en la construcción de los LLM. Stay tuned!
José Miguel Muñoz Urra – jmunozu@pulki.es