Majid Al-RaimiDense vectors and the skip-gram classifier

ICS 582Lecture 04Part 07

Dense vectors and the skip-gram classifier

Why short dense vectors beat long sparse ones, the main ways to get them, and how word2vec turns embedding learning into a self-supervised binary task scored by the sigmoid of a dot product.

Concepts
6
Slides
61-74
Reading
36 min
Understood
0/6 concepts

Why this part matters

This is where the lecture switches from counting to learning. Until now every vector was a row of a count table, reweighted by tf-idf or PPMI. From here on the vectors are parameters that a small classifier learns, and the classifier is trained on a task that running text answers for free. Skip-gram with negative sampling is an early, influential template for the pretext tasks that followed in NLP, including the masked-word objective of BERT, and it is a staple exam item: explain self-supervision, compute σ(c·w).

It also matters for research and real systems. The downloadable static vectors you will reach for (GoogleNews 300-d, GloVe 6B) and the gensim switches you will set (sg=1, negative=5, window=5) all come from the ideas below. The argument runs in six steps: why short dense vectors beat long sparse ones, where dense vectors come from, the idea of predicting instead of counting, how a window turns text into pairs, how a dot product becomes a probability, and how one window is scored as a whole. How the vectors are actually learned is the next part.

By the end you can

  1. Contrast sparse and dense vectors by length, zeros and value range, and give three reasons dense vectors help, including the car and automobile argument.
  2. Name the main sources of dense vectors (word2vec, GloVe, SVD/LSA, contextual models) and distinguish static from contextual embeddings.
  3. Explain self-supervision and the four-step skip-gram recipe, and say why the classifier is discarded while its weights are kept.
  4. Generate the positive (target, context) pairs for a ±m window, and relate m to the slides' L = 2m context words per target.
  5. Compute P(+|w,c) = σ(c·w) and P(-|w,c) = σ(-c·w) for given vectors.
  6. Score a whole window with the product of sigmoids and its log sum, and state the independence assumption behind it.

Short dense vectors versus long sparse ones

One sentence says "she drove the car to work"; another says "he parked the automobile outside". In a count space, drove collects weight on the car dimension and parked collects weight on the automobile dimension. Those are two different coordinates. If those are their only informative neighbors, the dot product of the two verbs is exactly 0, so their cosine is 0 too, even though any reader sees that the two sentences describe the same kind of event.

Worked example

Two verbs, two synonyms, zero similarity

  1. Keep only the two relevant dimensions

    Use the axes (car, automobile). drove = [1, 0] and parked = [0, 1].
  2. Dot product

    1×0 + 0×1 = 0.
  3. Cosine

    0 / (1 × 1) = 0. The vectors are orthogonal: as far as the space can tell, the two verbs share nothing.
  4. Result

    Sparse vectors treat car and automobile as unrelated axes, so words that differ only in which synonym they co-occur with look completely dissimilar.

Part 03 previewed this contrast on slide 30; here it gets its full argument. The vectors of the last three parts were sparse vectors. Built from a tf-idf or Pointwise mutual information weighting, they have one dimension per vocabulary word, so their length is |V|, typically 20,000 to 50,000, and nearly every entry is zero. A Dense vector is the opposite on every count. It has a small fixed number of dimensions d, usually between 50 and 1000; almost all of its entries are non-zero; and they are real numbers that can be negative. The price is interpretability: the d dimensions do not correspond to context words or to anything else nameable (SLP 5.5). Such a vector is still an Embedding, just a learned one rather than a counted one.

Car and automobile light up separate cells of a forty-cell sparse row. In a dense space both words land on the same few dimensions, so their cosine is high.
PropertySparse (tf-idf, PPMI)Dense (word2vec)
Length|V| ≈ 20,000 to 50,000d ≈ 50 to 1000
ZerosAlmost every entryAlmost none
ValuesCounts or non-negative weightsReal numbers, positive or negative
Dimension meaningEach axis is one context wordNo clear interpretation
Weights a one-word classifier needs50,000300
SynonymsSeparate, orthogonal axesCan share the same directions
Sparse count vectors and dense learned vectors side by side (SLP 5.5)

Three reasons dense vectors win

  1. Fewer weights to learn. A classifier that uses one word as a feature needs one weight per dimension: 300 weights for a dense vector instead of 50,000 for a sparse one. Fewer parameters may generalize better and overfit less.
  2. Better Synonymy. In a dense space, car and automobile can occupy nearby directions, so a word whose neighbors include car is automatically close to a word whose neighbors include automobile. The Cosine similarity of drove and parked is no longer forced to zero.
  3. Empirically better. SLP states it bluntly: dense vectors work better in every NLP task than sparse vectors. The slide says the same more cautiously: in practice, they work better.

Recall

Why do sparse vectors fail on car and automobile, and give two other reasons dense vectors help.

Car and automobile are separate, orthogonal dimensions, so two words whose neighbors differ only in which synonym they use share nothing and get cosine 0. Dense vectors also need fewer weights (300 vs 50,000), which may generalize better, and they work better in practice.

Quick check

One word occurs only near car, another only near automobile. What cosine do their sparse count vectors give?

Suppose you need word vectors for a project tomorrow. You do not have to train anything. You can download the word2vec GoogleNews vectors, or one of the GloVe sets from Stanford, and have a dense vector for millions of words in a few minutes. Knowing where each set comes from tells you what it can and cannot do.

Pretrained static vectors you can download today

word2vec GoogleNews
300-d vectors for 3,000,000 words and phrases, trained on part of Google News (about 100 billion words); 1,662 MB as word2vec-google-news-300 in gensim-data
GloVe 6B
Wikipedia 2014 plus Gigaword 5, 400K vocabulary, in 50, 100, 200 and 300 dimensions
GloVe, larger sets
Common Crawl (42B and 840B tokens), Twitter (27B), and newer 2024 Dolma and Wikipedia plus Gigaword releases

The lecture sorts dense vectors into three families. The first is inspired by neural language models: learn vectors by predicting words from their neighbors. Word2vec is the flagship, and it is a toolkit with two algorithms, Skip-gram (predict the neighbors from the word) and Continuous bag of words (predict the word from its neighbors). The slide also places GloVe here, which is a simplification noted below. The second family is factorization: take a count matrix and compress it with singular value decomposition. Latent semantic analysis (LSA) is SVD applied to a term-document matrix with the first 300 or so dimensions kept (Deerwester et al. 1990, in SLP's history section). The slide then presents contextual models such as ELMo and BERT as an alternative to these static embeddings. Both the SVD bullet and the contextual bullet are greyed out, because this lecture concentrates on word2vec.

FamilyExampleLearns fromOne vector per
Prediction (neural-LM inspired)word2vec SGNS, CBOWLocal windows, by predicting neighborsWord type
Global co-occurrence regressionGloVeGlobal co-occurrence countsWord type
Matrix factorizationSVD, LSATerm-document (or PPMI) matrixWord type
ContextualELMo, BERTThe whole sentence, at run timeToken in context
Where dense vectors come from, and what each one is a vector of

The last column is the line that matters most. Word2vec, GloVe and LSA all produce a Static embedding: one fixed vector per word type, looked up from a table. The word bank gets the same vector in "river bank" and "bank loan", so Polysemy is averaged into a single point. A Contextual embedding is computed by running the whole sentence through a network, so each token occurrence gets its own vector (Peters et al. 2018; Devlin et al. 2019). Those models come later in the course; this lecture is about static vectors.

In practice you train your own vectors with gensim. Its defaults are worth memorizing because they bite: vector_size=100, window=5, negative=5 (the docs say usually between 5 and 20), ns_exponent=0.75, min_count=5, and sg=0, which means CBOW.

from gensim.models import Word2Vec
import gensim.downloader as api

model = Word2Vec(
    sentences=corpus,
    vector_size=300,
    window=5,
    sg=1,
    negative=5,
    min_count=5,
)

google_news = api.load("word2vec-google-news-300")
google_news.most_similar("automobile", topn=3)
Training skip-gram with gensim, and loading the GoogleNews vectors from gensim-data

Recall

Static versus contextual embeddings: give one example of each.

Static means one vector per word type, looked up from a table (word2vec, GloVe). Contextual means one vector per token, computed from its sentence (ELMo, BERT).

Read the phrase "...a tablespoon of apricot jam...". Without anyone annotating anything, it hands you a labeled fact: (apricot, jam) is a yes, these two words occur near each other. Now pick a random word from the lexicon, say aardvark. (apricot, aardvark) is almost certainly a no. Every sentence of every book and web page produces such facts by the dozen.

That is the whole idea behind Skip-gram with negative sampling. Instead of counting how often a word c occurs near apricot, train a binary classifier on the question "is c likely to show up near apricot?" Nobody actually cares about that question. What we keep are the weights the classifier learns in order to answer it, and those weights are the embeddings. Because the gold answers come from running text rather than from people, this is Self-supervision.

The four-step recipe

  1. Treat the target word and each neighboring context word as a positive example.
  2. Randomly sample other words from the lexicon to make negative examples.
  3. Train logistic regression to tell the two kinds of pair apart.
  4. Throw the classifier away and use its learned weights as the embeddings.

The idea has a lineage. Bengio et al. (2003) and Collobert et al. (2011) had already shown that the next word in running text is a free supervision signal for learning word vectors, and Collobert et al. stressed the "vast amounts of mostly unlabeled training data" this unlocks. Word2vec simplifies their neural language models in two ways (SLP 5.5). It replaces the hard task of predicting the next word over the whole vocabulary with a yes-or-no question about a single pair, and it replaces a multi-layer network with plain logistic regression. The payoff was speed: Mikolov et al. (2013a) learned high quality vectors from a 1.6 billion word data set in less than a day.

The binary framing is also what keeps training cheap. The basic skip-gram formulation defines its probability with a softmax over the whole vocabulary, whose cost grows with W, "often large (10^5 to 10^7 terms)" (Mikolov et al. 2013b). Negative sampling replaces that sum with a handful of k sampled noise words, 5 to 20 for small data sets and 2 to 5 for large ones. How those negatives are drawn and how the weights are updated is the subject of the next part.

Recall

What is self-supervision in word2vec, and why does it need no human labels?

Words that actually occur near the target in running text serve as gold positive answers to "is c a neighbor of w?", and randomly sampled words serve as negatives. The corpus supplies the labels; we keep the classifier's learned weights as the embeddings.

Recall

List the four steps of the skip-gram intuition.

(1) Target and neighbor pairs are positives. (2) Random lexicon samples are negatives. (3) Train logistic regression to separate them. (4) Use the learned weights as embeddings.

Quick check

In skip-gram training, where do the gold labels come from?

From a context window to (target, context) pairs

Take the running text "...lemon, a tablespoon of apricot jam, a pinch..." and put a window of two words on each side of apricot. The target is w = apricot, and the four context words are c1 = tablespoon, c2 = of, c3 = jam and c4 = a. Each one forms a positive training pair with the target.

A ±2 window around apricot: four arcs to real neighbors become positive pairs, while a randomly sampled word such as aardvark becomes a negative one.

Worked example

Positive pairs from a ±2 window

  1. Target apricot

    (apricot, tablespoon), (apricot, of), (apricot, jam), (apricot, a).
  2. Slide one word to the right: target jam

    (jam, of), (jam, apricot), (jam, a), (jam, pinch).
  3. Result

    Every token takes a turn as the target. A window of ±2 gives up to 4 positive pairs per target, and in general a half-width of m gives up to 2m. Fewer appear only at the edges of a text.

A note on letters: the slides and SLP write L for the number of context words being scored, so a ±2 window has L = 4. Keep that in mind when you meet c_1:L in the last concept of this part. The half-width is written m throughout this lecture, so L = 2m. Try the window yourself: click any word to make it the target and change the half-width.

SimulatorWindow to (target, context) pairs
Click any word to make it the target.
......
  • (apricot, tablespoon)
  • (apricot, of)
  • (apricot, jam)
  • (apricot, a)
Positive pairs4of up to 4A full window gives 2 pairs per unit of half-width.
Target wapricotEvery token takes this role in turn during training.

Once the pairs exist, the classifier's job is simple to state. Given a candidate pair (w, c), return the probability that c is a real context word of w. For (apricot, jam) that probability should be high; for (apricot, aardvark) it should be low. Since there are only two outcomes, the probability of the negative answer is whatever is left over:

P(+∣w,c)P(−∣w,c)=1−P(+∣w,c)\begin{gathered} P(+\mid w,c) \\ P(-\mid w,c)=1-P(+\mid w,c) \end{gathered}
The two outputs of the skip-gram classifier (SLP eqs 5.11 and 5.12)

Recall

How many positive pairs does a ±3 window give for a target in mid-sentence, and what is the slides' L for it?

6 pairs, so L = 6 (in general 2m).

Quick check

With a ±1 window over '...tablespoon of apricot jam, a pinch...', which positive pairs does target jam produce?

Give apricot a toy three-dimensional vector w = (1, 0.5, -1). Give jam the context vector c = (2, 1, -0.5) and aardvark c = (-1, 0.5, 1). Multiply apricot by jam elementwise and add: 2 + 0.5 + 0.5 = 3. Do the same with aardvark: -1 + 0.25 - 1 = -1.75. The real neighbor scores high, the random word scores low. The question is how to turn those two scores into probabilities.

The intuition the classifier uses is the one from the cosine parts: two vectors are similar when their Dot product is high, and the Cosine similarity is just a dot product divided by the two vector lengths. So skip-gram takes the dot product c·w as its similarity score. But neither a dot product nor a cosine is a probability. Because embedding entries can be negative, the dot product can be anything from -∞ to ∞ (SLP 5.5.1).

Logistic regression already has the fix. The sigmoid function maps any real number into the open interval (0, 1), so the classifier passes the dot product through it:

σ(x)=11+exp⁡(−x)\sigma(x)=\frac{1}{1+\exp(-x)}
The logistic sigmoid (SLP eq 5.14)
P(+∣w,c)=σ(c⋅w)=11+exp⁡(−c⋅w)\begin{aligned} P(+\mid w,c)&=\sigma(\mathbf{c}\cdot\mathbf{w}) \\ &=\frac{1}{1+\exp(-\mathbf{c}\cdot\mathbf{w})} \end{aligned}
Probability that c is a real context word of w (SLP eq 5.15)
P(−∣w,c)=1−P(+∣w,c)=σ(−c⋅w)=11+exp⁡(c⋅w)\begin{aligned} P(-\mid w,c)&=1-P(+\mid w,c) \\ &=\sigma(-\mathbf{c}\cdot\mathbf{w}) \\ &=\frac{1}{1+\exp(\mathbf{c}\cdot\mathbf{w})} \end{aligned}
Probability that c is not a context word of w (SLP eq 5.16)

The identity 1 - σ(x) = σ(-x) is worth checking once, because it is used constantly: the two cases always sum to 1, and flipping the sign of the score swaps them. A few anchor values make hand computation quick: σ(0) = 0.5, σ(2) = 0.8808, σ(-2) = 0.1192, σ(5) = 0.9933, σ(-5) = 0.0067.

The sigmoid squashes any dot product into (0, 1). Jam's score of 3 maps to 0.95; aardvark's -1.75 maps to 0.15.

Worked example

P(+) for jam and for aardvark, with w = (1, 0.5, -1)

  1. Multiply elementwise

    jam: (1×2, 0.5×1, -1×-0.5) = (2, 0.5, 0.5). aardvark: (1×-1, 0.5×0.5, -1×1) = (-1, 0.25, -1).
  2. Sum

    c·w = 3 for jam and c·w = -1.75 for aardvark.
  3. Exponentiate the negated score

    e^-3 = 0.0498 and e^1.75 = 5.7546.
  4. Invert one plus that

    jam: 1 / 1.0498 = 0.9526. aardvark: 1 / 6.7546 = 0.1480.
  5. Result

    P(+ | apricot, jam) = 0.9526 and P(+ | apricot, aardvark) = 0.1480, so P(- | apricot, aardvark) = 0.8520.
SimulatorFrom dot product to probability
c · w3.0000Any real number, not a probability.
P(+ | w, c)0.9526σ(c · w) = 1 / (1 + e-c·w)
P(- | w, c)0.0474σ(-c · w), so the two sum to 1.

Recall

Compute P(+|w,c) for w = (1, 0.5, -1) and c = (2, 1, -0.5).

The dot product is 2 + 0.5 + 0.5 = 3, so σ(3) = 1 / (1 + e^-3) = 0.9526.

Quick check

With w = (1, 0.5, -1) and c = (2, 1, -0.5), what is P(+|w,c)?

One pair at a time is not enough: apricot has four neighbors in its ±2 window, and the classifier should score the whole window. Keep w = (1, 0.5, -1) and give each of the four context words a toy vector.

Contextcc·wσ(c·w)log σ
tablespoon(0.5, 0, -0.5)1.00.7311-0.3133
of(0.2, -0.4, 0.1)-0.10.4750-0.7444
jam(2, 1, -0.5)3.00.9526-0.0486
a(0, 0.2, 0)0.10.5250-0.6444
Scoring apricot's ±2 window, one context word at a time (natural logs)

Skip-gram makes one simplifying move: it assumes the context words are independent of each other given the target. Under that assumption the probability that all of them are real neighbors is the product of the individual sigmoid probabilities, and its logarithm is a sum.

P(+∣w,c1:L)=∏i=1Lσ(ci⋅w)P(+\mid w,c_{1:L})=\prod_{i=1}^{L}\sigma(\mathbf{c}_i\cdot\mathbf{w})
Window probability under independence (SLP eq 5.17)
log⁡P(+∣w,c1:L)=∑i=1Llog⁡σ(ci⋅w)\log P(+\mid w,c_{1:L})=\sum_{i=1}^{L}\log\sigma(\mathbf{c}_i\cdot\mathbf{w})
The same quantity in log space (SLP eq 5.18)

Worked example

Product and log sum for the apricot window

  1. Multiply the four sigmoids

    0.7311 × 0.4750 × 0.9526 × 0.5250 = 0.1737.
  2. Add the four logs

    -0.3133 - 0.7444 - 0.0486 - 0.6444 ≈ -1.7507.
  3. Check they agree

    e^-1.7507 ≈ 0.1737. The log sum is the log of the product.
  4. Result

    Four true neighbors give a joint probability of only 0.1737, dragged down by the weakly scored function words of and a. With hundreds of factors the product would underflow, which is why training works in log space.

That last sentence hides a detail that sets up the next part. SLP's figure 5.6 shows that skip-gram stores two embeddings per word: one for when the word is a target and one for when it is a context. They live in a target matrix W and a context matrix C, the Target and context matrices, so the parameters are 2|V| vectors of dimension d. Learning those two matrices from positive and negative pairs is what part 8 is about.

Recall

Write P(+|w,c_1:L), say which assumption it relies on, and why we take logs.

P(+|w,c_1:L) = ∏ σ(c_i·w). It assumes the context words are independent given the target. Taking logs turns the product into a sum of log σ terms, which avoids underflow and does not change which window scores higher.

Quick check

Why does skip-gram multiply the sigmoid scores of the context words?

Recap

If you remember nothing else

  • Sparse tf-idf and PPMI vectors have length |V| (20,000 to 50,000) and are mostly zeros. Dense embeddings have 50 to 1000 dimensions with real values that can be negative.
  • Dense vectors need far fewer classifier weights (300 vs 50,000), capture synonymy that separate dimensions miss (car and automobile), and work better in practice.
  • The dense families are word2vec (skip-gram, CBOW), GloVe (global co-occurrence), SVD/LSA, and contextual models (ELMo, BERT). The first three are static: one vector per word type.
  • Word2vec predicts rather than counts. A binary classifier asks "is c near w?", and its learned weights become the embeddings.
  • Self-supervision: neighbors in running text are the gold positives and random lexicon words are the negatives, so no human labels are needed.
  • A ±2 window around apricot gives four positives: tablespoon, of, jam, a.
  • P(+|w,c) = σ(c·w) = 1/(1 + e^(-c·w)) and P(-|w,c) = σ(-c·w). σ(0) = 0.5.
  • Assuming independent context words, P(+|w,c_1:L) = ∏σ(c_i·w) and log P = Σ log σ(c_i·w).
  • SGNS stores two vectors per word: a target matrix W and a context matrix C.

Sources