Course contents 08 / 37

08 / 37 · Distributed Representations

Word2Vec

A prediction task on unlabelled text (guess the neighbours from the centre word, or the centre from its neighbours) trains an embedding table; the full softmax over the vocabulary makes each step touch tens of millions of weights, and negative sampling cuts that to a few thousand while still learning co-occurrence statistics.

On this page 14

The previous note found that library-trained embedding tables give similar vectors to words used in similar contexts, without explaining why. Words that occur in the same contexts tend to have similar meanings (Harris, 1954; Firth, 1957), and a model that must predict a word’s neighbours through a narrow bottleneck has to give words with the same neighbours similar bottleneck vectors. Word2Vec (Mikolov et al., 2013a, 2013b) turns that into two small networks, made trainable on billions of tokens by hierarchical softmax or negative sampling; this note develops negative sampling, the one used in practice.

Notation. The corpus is a token sequence w1,…,wTw_1, \dots, w_T over a vocabulary VV; dd is the embedding dimension. For a position tt the centre word is wtw_t and the context is the window Ct=(wt+j)j∈JtC_t = (w_{t+j})_{j \in J_t} with Jt={j:1≤∣j∣≤m, 1≤t+j≤T}J_t = \{j : 1 \le |j| \le m,\ 1 \le t + j \le T\}, up to 2m2m neighbours with repeats kept; mm is the window radius. Each word ww has two vectors: an input (centre) vector vw∈Rdv_w \in \mathbb R^d, a row of Win∈R∣V∣×dW_{\text{in}} \in \mathbb R^{|V| \times d}, and an output (context) vector uw∈Rdu_w \in \mathbb R^d, a row of Wout∈R∣V∣×dW_{\text{out}} \in \mathbb R^{|V| \times d}. WinW_{\text{in}} is the embedding table EE of the previous note. σ(x)=1/(1+e−x)\sigma(x) = 1/(1 + e^{-x}); kk is the number of negative samples and PnP_n the distribution they are drawn from.

Baseline: fit the embeddings with a labelled task#

The previous note listed sources for the table. Training it as a layer of a classifier works (the CNN note measures it) but learns only about words in the labelled set and only what helps predict the label. Labelled text is scarce; unlabelled text is almost unlimited. What should a model predict when there is no label?

A network whose first layer is the table#

The key idea needs only a two-layer linear network. For an input word cc and a target word oo:

  1. take the one-hot vector ec∈{0,1}∣V∣e_c \in \{0, 1\}^{|V|} of cc;
  2. multiply by the first layer: h=Win⊤ec=vc∈Rdh = W_{\text{in}}^\top e_c = v_c \in \mathbb R^d, the row of cc (no bias, no non-linearity);
  3. score every vocabulary word against hh: s=Wout h∈R∣V∣s = W_{\text{out}}\, h \in \mathbb R^{|V|}, so sw=uw⋅vcs_w = u_w \cdot v_c;
  4. turn the scores into a distribution with a softmax:
p(o∣c)=exp⁡(uo⋅vc)∑w∈Vexp⁡(uw⋅vc).p(o \mid c) = \frac{\exp(u_o \cdot v_c)}{\sum_{w \in V}\exp(u_w \cdot v_c)}.

The network is fitted with the cross-entropy −log⁡p(o∣c)-\log p(o \mid c) on (input, target) pairs cut from the corpus; then all but the first layer is thrown away, and the row vcv_c is the embedding. In code the one-hot product is a lookup: a batch of ids [B][B] becomes [B,d][B, d], then [B,∣V∣][B, |V|]. The model has 2∣V∣d2|V|d parameters.

Figure

The Word2Vec network: a row lookup, a dot product with every output vector, a softmax

Word2Vec network with shapesFrom left to right: a column of eight cells with a single 1 at the position of coffee; the input matrix W in, eight rows by three columns, with the row of coffee highlighted and marked as the embedding table that is kept; the hidden vector h of three cells, equal to that row; the output matrix W out, eight rows by three columns, with the row of drink highlighted; a column of eight scores; and horizontal bars for the softmax probabilities of the eight words, with drink the longest. The output part is marked as used only during training.ec00010000[|V|]Win[|V|, d]h= vc[d]Wout[|V|, d]s0.161.160.75−0.120.370.680.100.22[|V|]softmaxwedrinkhotcoffeeeverymorningcartaxkept: embedding tableused only to train the tableWord2Vec network with shapesFrom left to right: a column of eight cells with a single 1 at the position of coffee; the input matrix W in, eight rows by three columns, with the row of coffee highlighted and marked as the embedding table that is kept; the hidden vector h of three cells, equal to that row; the output matrix W out, eight rows by three columns, with the row of drink highlighted; and horizontal bars for the softmax probabilities of the eight words, with drink the longest. The output part is marked as used only during training.ec00010000[|V|]Win[|V|, d]h= vc[d]Wout[|V|, d]softmaxwedrinkhotcoffeeeverymorningcartaxkept: embedding tableused only in training
Toy sizes |V| = 8 and d = 3, centre word coffee, observed context word drink. The one-hot vector of coffee times W_in reads out one row, v_coffee; there is no bias and no non-linearity, so the hidden vector h is that row. Each row u_w of W_out is dotted with h to give one score per vocabulary word, and the softmax turns the 8 scores into a distribution over the context word (scores and bars are computed from toy vectors). Training raises the probability of drink. After training only W_in is kept, as the embedding table; W_out and the softmax exist only to provide the training signal. For CBOW the input is the 2m context words and h is the mean of their rows.

Two tables are needed because with one, a word’s score against itself, ∥vw∥2\|v_w\|^2, would be large, while a word rarely occurs in its own window; two tables let uw⋅vwu_w \cdot v_w be small (Goldberg and Levy, 2014). Libraries return WinW_{\text{in}} (wv in gensim).

Two prediction tasks: CBOW and skip-gram#

The network leaves open which words are inputs and which are targets. Word2Vec defines two choices on the same windows.

Continuous bag of words (CBOW) predicts the centre word from its context: the mean of the context input vectors is classified among the ∣V∣|V| possible centre words:

ht=1∣Jt∣∑j∈Jtvwt+j,p(wt∣Ct)=exp⁡(uwt⋅ht)∑w′∈Vexp⁡(uw′⋅ht).h_t = \frac{1}{|J_t|}\sum_{j \in J_t} v_{w_{t+j}}, \qquad p(w_t \mid C_t) = \frac{\exp(u_{w_t} \cdot h_t)}{\sum_{w' \in V}\exp(u_{w'} \cdot h_t)}.

“Bag” because the mean ignores word order; each position gives one example.

Skip-gram reverses the direction: the centre word predicts each context word separately, with the softmax of the previous section, minimizing

LSG=−1T∑t=1T∑j∈Jtlog⁡p(wt+j∣wt).\mathcal L_{\text{SG}} = -\frac{1}{T}\sum_{t=1}^T \sum_{j \in J_t} \log p(w_{t+j} \mid w_t).

Each position gives up to 2m2m (centre, context) pairs.

Figure

One window, two prediction tasks

Skip-gram pairs and the CBOW example from one windowTwo copies of the sentence we drink hot coffee every morning, with coffee highlighted as the centre and a window of two words on each side. In the top copy four blue arrows leave coffee and point at drink, hot, every and morning, and the four pairs are listed below. In the bottom copy four red arrows leave the neighbours and point into coffee, with the note that their vectors are averaged. A final line counts 18 skip-gram pairs and 6 CBOW examples for the whole sentence.Skip-gram: the centre predicts each neighbourwedrinkhotcoffeeeverymorning(coffee, drink) (coffee, hot) (coffee, every) (coffee, morning)CBOW: the neighbours together predict the centrewedrinkhotcoffeeeverymorningmean of v(drink), v(hot), v(every), v(morning) → coffeeWhole sentence: 2 + 3 + 4 + 4 + 3 + 2 = 18 skip-gram pairs, 6 CBOW examplesSkip-gram pairs and the CBOW example from one windowTwo copies of the sentence we drink hot coffee every morning, with coffee highlighted as the centre and a window of two words on each side. In the top copy four blue arrows leave coffee and point at drink, hot, every and morning, and the four pairs are listed below. In the bottom copy four red arrows leave the neighbours and point into coffee, with the note that their vectors are averaged. A final line counts 18 skip-gram pairs and 6 CBOW examples for the whole sentence.Skip-gram: centre → each neighbourwedrinkhotcoffeeeverymorning(coffee, drink) (coffee, hot)(coffee, every) (coffee, morning)CBOW: neighbours → centrewedrinkhotcoffeeeverymorningmean of v(drink), v(hot), v(every),v(morning) → coffeeWhole sentence: 2 + 3 + 4 + 4 + 3 + 2 = 18skip-gram pairs, 6 CBOW examples
The sentence “we drink hot coffee every morning” with window radius m = 2 and centre word coffee (amber); the word “we” is outside the window. Skip-gram (top) turns the window into four separate training pairs, each asking the model to predict one neighbour from coffee. CBOW (bottom) turns the same window into a single example: the four neighbour vectors are averaged and the average has to predict coffee. Sliding the centre over all six positions gives 2, 3, 4, 4, 3, 2 neighbours per position (fewer at the sentence edges), so 18 skip-gram updates against 6 CBOW updates.

Worked example: training pairs. In we drink hot coffee every morning (T=6T = 6, m=2m = 2) the centre coffee gives four skip-gram pairs and one CBOW example, in which the mean of the four context vectors predicts coffee (figure above). Position ii has min⁡(m,i−1)+min⁡(m,T−i)\min(m, i - 1) + \min(m, T - i) neighbours, so the sentence gives 2+3+4+4+3+2=182 + 3 + 4 + 4 + 3 + 2 = 18 skip-gram pairs against 6 CBOW examples.

A neural language model (Bengio et al., 2003) also starts with an embedding table but predicts the next word, like the n-gram model, through a costly non-linear hidden layer. Word2Vec only wants the table, so it drops the non-linearity and uses context on both sides.

CBOW computes one output distribution per position and skip-gram up to 2m2m, so CBOW is cheaper by about the window size, but in the comparison of Mikolov et al. (2013a), §3.1–3.2 and Table 3 (640-dimensional vectors), skip-gram was far better on semantic analogies (55% against 24%) and slightly worse on syntactic ones (59% against 64%). It is also reported to be better for rare words (word2vec project page), whose vectors CBOW only updates through a mean with up to 2m−12m - 1 others.

For each centre the effective radius is drawn uniformly from {1,…,m}\{1, \dots, m\} (Mikolov et al., 2013a, §3.2), so a neighbour at distance jj is used with probability (m−j+1)/m(m - j + 1)/m (1,0.8,0.6,0.4,0.21, 0.8, 0.6, 0.4, 0.2 for m=5m = 5): near neighbours count more without an explicit weight.

Why the softmax is the problem#

Write the skip-gram loss of one pair (c,o)(c, o) as −log⁡p(o∣c)=−uo⋅vc+log⁡∑w∈Vexp⁡(uw⋅vc)-\log p(o \mid c) = -u_o \cdot v_c + \log \sum_{w \in V} \exp(u_w \cdot v_c). The derivative of the log-sum-exp with respect to vcv_c is the softmax-weighted average of the uwu_w, and with respect to one uwu_w it is p(w∣c) vcp(w \mid c)\, v_c:

∂ (−log⁡p(o∣c))∂vc=−uo+∑w∈Vp(w∣c) uw,∂ (−log⁡p(o∣c))∂uw=(p(w∣c)−1[w=o]) vc.\begin{aligned} \frac{\partial\,(-\log p(o \mid c))}{\partial v_c} &= -u_o + \sum_{w \in V} p(w \mid c)\, u_w, \\ \frac{\partial\,(-\log p(o \mid c))}{\partial u_w} &= \big(p(w \mid c) - \mathbb 1[w = o]\big)\, v_c . \end{aligned}

The first line reads “observed minus expected”: a step pulls vcv_c towards the context word that occurred and away from the one the model expects. The second is non-zero for every ww, so one pair writes to all ∣V∣|V| rows of WoutW_{\text{out}}, and the normalizer alone needs ∣V∣|V| dot products (Rong, 2014).

With ∣V∣=200,000|V| = 200{,}000 and d=300d = 300 the model has 2∣V∣d=1.2×1082|V|d = 1.2 \times 10^8 parameters. One pair costs ∣V∣d=6×107|V| d = 6 \times 10^7 multiply-adds for the scores and updates ∣V∣d+d=60,000,300|V| d + d = 60{,}000{,}300 parameters, and a corpus of 10910^9 tokens with m=5m = 5 gives up to 101010^{10} pairs per pass. The model is small; the normalization makes training infeasible.

Figure

Parameters touched by one training pair as the vocabulary grows

Cost per training pair against vocabulary sizeLog-log plot with vocabulary size from one thousand to ten million on the horizontal axis and parameters updated per pair from one hundred to ten billion on the vertical axis. The full-softmax line rises with slope one from about three hundred thousand to three billion. The hierarchical-softmax curve rises slowly from about three thousand to seven thousand. The negative-sampling line is flat at 2,100. A vertical line at two hundred thousand words marks a gap of about 28,600 times between the full softmax and negative sampling.10²10⁴10⁶10⁸10¹⁰10³10⁴10⁵10⁶10⁷vocabulary size |V|parameters updated per pairfull softmax: (|V| + 1)dhierarchical softmax: ≈ d(log₂|V| + 1)negative sampling, k = 5: (k + 2)d = 2,100|V| = 200,000:≈ 28,600× fewerCost per training pair against vocabulary sizeLog-log plot with vocabulary size from one thousand to ten million on the horizontal axis and parameters updated per pair from one hundred to ten billion on the vertical axis. The full-softmax line rises with slope one from about three hundred thousand to three billion. The hierarchical-softmax curve rises slowly from about three thousand to seven thousand. The negative-sampling line is flat at 2,100. A vertical line at two hundred thousand words marks a gap of about 28,600 times between the full softmax and negative sampling.10²10⁴10⁶10⁸10¹⁰10³10⁴10⁵10⁶10⁷vocabulary size |V|parameters per pairfull softmaxhierarchical softmaxnegative sampling, k = 5|V| = 200,000:≈ 28,600× fewer
Both axes are logarithmic; d = 300. The full softmax reads and updates every output row, so its cost grows in proportion to |V|. Hierarchical softmax replaces the |V|-way normalization by about log₂|V| binary decisions along a tree. Negative sampling with k = 5 updates the centre vector, the observed context vector and 5 sampled vectors, (k + 2)d = 2,100 parameters, whatever the vocabulary size. At |V| = 200,000 (vertical line) the full softmax touches 60,000,300 parameters per pair, about 28,600 times more.

Hierarchical softmax (Morin and Bengio, 2005) puts the vocabulary at the leaves of a binary (Huffman, Mikolov et al., 2013b, §2.1) tree, so a prediction takes about log⁡2∣V∣\log_2 |V| binary decisions, 18 for 200,000 words. Negative sampling drops the normalization; it is the default in practice and the subject of the rest of this note.

Negative sampling#

Figure

Softmax versus negative sampling on the output side of skip-gram

Softmax versus negative samplingTwo panels. In each, a column of three cells on the left is the centre vector of coffee and a column of eight word boxes on the right is the vocabulary. In the full-softmax panel every word is connected to the centre vector by a solid line. In the negative-sampling panel only the observed word drink (green, target 1) and the two sampled negatives car and tax (red, target 0) are connected; the other words are drawn faintly.full softmaxall |V| output rows read and updatedvccoffeewedrinkhotcarmorningtaxcupcoffeeone softmax over |V| scoresnegative sampling, k = 2k + 1 = 3 output rows read and updatedvccoffeewedrink ← observed (1)hotcar ← negative (0)morningtax ← negative (0)cupcoffeek + 1 logistic classifiersSoftmax versus negative samplingTwo panels. In each, a column of three cells on the left is the centre vector of coffee and a column of eight word boxes on the right is the vocabulary. In the full-softmax panel every word is connected to the centre vector by a solid line. In the negative-sampling panel only the observed word drink (green, target 1) and the two sampled negatives car and tax (red, target 0) are connected; the other words are drawn faintly.full softmaxall |V| output rows read and updatedvccoffeewedrinkhotcarmorningtaxcupcoffeeone softmax over |V| scoresnegative sampling, k = 2k + 1 = 3 output rows read and updatedvccoffeewedrink ← observed (1)hotcar ← negative (0)morningtax ← negative (0)cupcoffeek + 1 logistic classifiers
Toy sizes |V| = 8 and d = 3; the words are those of the worked example below: centre coffee, observed context drink, negatives car and tax. With the full softmax (first panel) the probability of drink is normalized over all |V| words, so one training pair reads and updates every row of W_out. With negative sampling (second panel) the pair (coffee, drink) is a positive example with target 1 and k = 2 sampled words, car and tax, are negatives with target 0 (targets in brackets); each is an independent logistic classifier on its score, and only these k + 1 output rows and v_coffee are read and updated. The rest of the vocabulary is not visited. At |V| = 200,000, d = 300 and k = 5 this is 2,100 parameters per pair instead of 60,000,300.

For an observed pair (c,o)(c, o) and noise words n1,…,nk∼Pnn_1, \dots, n_k \sim P_n, the skip-gram negative-sampling (SGNS) loss is

LNS(c,o)=−log⁡σ(uo⋅vc)−∑i=1klog⁡σ(−uni⋅vc).\mathcal L_{\text{NS}}(c, o) = -\log \sigma(u_o \cdot v_c) - \sum_{i=1}^k \log \sigma(-u_{n_i} \cdot v_c).

σ(uw⋅vc)\sigma(u_w \cdot v_c) is the model’s probability that a pair is real and σ(−x)=1−σ(x)\sigma(-x) = 1 - \sigma(x), so each term of the sum is the log-probability that a noise pair is recognized as fake. With the scores so=uo⋅vcs_o = u_o \cdot v_c and si=uni⋅vcs_i = u_{n_i} \cdot v_c, and ddxlog⁡σ(x)=1−σ(x)\frac{d}{dx}\log\sigma(x) = 1 - \sigma(x), the gradients are

∂LNS∂vc=(σ(so)−1) uo+∑i=1kσ(si) uni,∂LNS∂uo=(σ(so)−1) vc,∂LNS∂uni=σ(si) vc.\begin{aligned} \frac{\partial \mathcal L_{\text{NS}}}{\partial v_c} &= \big(\sigma(s_o) - 1\big)\, u_o + \sum_{i=1}^k \sigma(s_i)\, u_{n_i}, \\ \frac{\partial \mathcal L_{\text{NS}}}{\partial u_o} &= \big(\sigma(s_o) - 1\big)\, v_c, \qquad \frac{\partial \mathcal L_{\text{NS}}}{\partial u_{n_i}} = \sigma(s_i)\, v_c . \end{aligned}

This is “observed minus expected” with the expectation over ∣V∣|V| words replaced by kk sampled words, each weighted by how plausible the model finds it; all other rows have zero gradient.

CBOW uses the same loss with the context mean hth_t in place of the centre vector and the centre word as the positive:

LCBOW-NS(t)=−log⁡σ(uwt⋅ht)−∑i=1klog⁡σ(−uni⋅ht).\mathcal L_{\text{CBOW-NS}}(t) = -\log \sigma(u_{w_t} \cdot h_t) - \sum_{i=1}^k \log \sigma(-u_{n_i} \cdot h_t).

Its gradients are those above with hth_t for vcv_c. The chain rule through the mean would send 1/∣Jt∣1/|J_t| of hth_t‘s gradient to each context vector; word2vec.c (word2vec project page) and gensim (cbow_mean=1) add all of it, in effect a larger learning rate for the input table.

A pair updates (k+2)d(k + 2) d parameters, 2,1002{,}100 for d=300d = 300 and k=5k = 5. Mikolov et al. (2013b), §2.2, report that kk between 5 and 20 works for small training sets and 2 to 5 for large ones; gensim uses k=5k = 5.

Worked example#

Toy numbers: d=2d = 2, k=2k = 2, learning rate η=0.5\eta = 0.5 (large, so that the movement is visible), centre coffee, observed context drink, negatives car and tax.

VectorValueScore with vcoffeev_{\text{coffee}}σ(score)\sigma(\text{score})Loss term
vcoffeev_{\text{coffee}}(1.0,0.5)(1.0, 0.5)
udrinku_{\text{drink}} (observed)(0.8,0.6)(0.8, 0.6)1.101.100.7500.750−log⁡σ(1.10)=0.287-\log \sigma(1.10) = 0.287
ucaru_{\text{car}} (negative)(−0.2,0.9)(-0.2, 0.9)0.250.250.5620.562−log⁡σ(−0.25)=0.826-\log \sigma(-0.25) = 0.826
utaxu_{\text{tax}} (negative)(0.6,−0.4)(0.6, -0.4)0.400.400.5990.599−log⁡σ(−0.40)=0.913-\log \sigma(-0.40) = 0.913

The loss is 0.287+0.826+0.913=2.0260.287 + 0.826 + 0.913 = 2.026, and the gradients are

  • ∂L/∂vcoffee=−0.250 (0.8,0.6)+0.562 (−0.2,0.9)+0.599 (0.6,−0.4)=(0.047,0.117)\partial \mathcal L / \partial v_{\text{coffee}} = -0.250\,(0.8, 0.6) + 0.562\,(-0.2, 0.9) + 0.599\,(0.6, -0.4) = (0.047, 0.117);
  • ∂L/∂udrink=−0.250 (1.0,0.5)=(−0.250,−0.125)\partial \mathcal L / \partial u_{\text{drink}} = -0.250\,(1.0, 0.5) = (-0.250, -0.125);
  • ∂L/∂ucar=0.562 (1.0,0.5)=(0.562,0.281)\partial \mathcal L / \partial u_{\text{car}} = 0.562\,(1.0, 0.5) = (0.562, 0.281) and ∂L/∂utax=0.599 (1.0,0.5)=(0.599,0.299)\partial \mathcal L / \partial u_{\text{tax}} = 0.599\,(1.0, 0.5) = (0.599, 0.299).

One step x←x−η ∂L/∂xx \leftarrow x - \eta\, \partial\mathcal L/\partial x gives vcoffee=(0.977,0.442)v_{\text{coffee}} = (0.977, 0.442), udrink=(0.925,0.662)u_{\text{drink}} = (0.925, 0.662), ucar=(−0.481,0.759)u_{\text{car}} = (-0.481, 0.759) and utax=(0.301,−0.550)u_{\text{tax}} = (0.301, -0.550); the two figures below show the vectors and the scores moving, and the loss falls from 2.0262.026 to 1.6111.611. Four rows changed; with 200,000 words the other 199,997 output rows were not read.

Figure

One negative-sampling step, drawn in the plane

Geometry of one negative-sampling updateFour arrows from the origin of a plane, each drawn dashed before the update and solid after it. The blue centre vector v coffee barely moves. The green observed context vector u drink moves outward along the direction of v coffee. The two red negative vectors u car and u tax move away from v coffee. A table lists the scores before and after: drink 1.10 to 1.20, car 0.25 to −0.13, tax 0.40 to 0.05.−0.5−0.50.50.51vcoffeeudrinkucarutaxscore with vcoffeebeforeafterdrink (observed)1.101.20car (negative)0.25−0.13tax (negative)0.400.05Geometry of one negative-sampling updateFour arrows from the origin of a plane, each drawn dashed before the update and solid after it. The blue centre vector v coffee barely moves. The green observed context vector u drink moves outward along the direction of v coffee. The two red negative vectors u car and u tax move away from v coffee. A table lists the scores before and after: drink 1.10 to 1.20, car 0.25 to −0.13, tax 0.40 to 0.05.−0.5−0.50.50.51vcoffeeudrinkucarutaxscore with vcoffeebeforeafterdrink (observed)1.101.20car (negative)0.25−0.13tax (negative)0.400.05
The worked example with d = 2, k = 2 negatives and learning rate 0.5. Dashed: the four vectors before the step; solid: after it; short arrows: how each output tip moved (v_coffee moves too little for an arrow). The centre vector v_coffee moves (1.000, 0.500) → (0.977, 0.442). The observed context vector u_drink moves along v_coffee, so their dot product grows; the negatives u_car and u_tax move against v_coffee, so theirs shrink. Every gradient is a multiple of a vector already in the picture: an output row moves only along v_coffee, and v_coffee moves along a weighted sum of the three output rows. No other row of the vocabulary is read.
Figure

The two loss terms of negative sampling as functions of the score

Negative-sampling loss terms against the scoreTwo curves over the score from minus four to four. The green curve, minus log sigma of s, falls from about four at the left to almost zero at the right. The red curve, minus log sigma of minus s, is its mirror image and rises to about four at the right. They cross at score zero, at log 2. Three pairs of points mark the worked example: the observed pair drink on the green curve moves right from 1.10 to 1.20; the negatives car and tax on the red curve move left from 0.25 to −0.13 and from 0.40 to 0.05.1234−4−2024score s = u · vc0−log σ(s): observed pair−log σ(−s): negative pairdrink: score 1.10 → 1.20car: score 0.25 → −0.13tax: score 0.40 → 0.05Negative-sampling loss terms against the scoreTwo curves over the score from minus four to four. The green curve, minus log sigma of s, falls from about four at the left to almost zero at the right. The red curve, minus log sigma of minus s, is its mirror image and rises to about four at the right. They cross at score zero, at log 2. Three pairs of points mark the worked example: the observed pair drink on the green curve moves right from 1.10 to 1.20; the negatives car and tax on the red curve move left from 0.25 to −0.13 and from 0.40 to 0.05.1234−4−2024score s = u · vc0−log σ(s)−log σ(−s)drinkcartax
Green: −log σ(s), the loss of the observed pair; its slope σ(s) − 1 vanishes once the score is large, so a pair that is already recognized stops moving. Red: −log σ(−s), the loss of each negative pair; its slope σ(s) grows with the score, so a negative that the model wrongly finds plausible gets the largest push. Points are the worked example (d = 2, k = 2, learning rate 0.5): hollow before the step, filled after it. The observed pair (coffee, drink) moves from score 1.10 to 1.20, the negatives car and tax from 0.25 and 0.40 to −0.13 and 0.05; the total loss falls from 2.026 to 1.611.

For contrast, the full softmax over a toy six-word vocabulary with the same vcoffeev_{\text{coffee}}: drink (0.8,0.6)(0.8, 0.6), hot (0.7,0.1)(0.7, 0.1), morning (0.3,0.5)(0.3, 0.5), car (−0.2,0.9)(-0.2, 0.9), tax (0.6,−0.4)(0.6, -0.4) and cup (0.9,0.2)(0.9, 0.2). The scores are 1.10,0.75,0.55,0.25,0.40,1.001.10, 0.75, 0.55, 0.25, 0.40, 1.00, the probabilities 0.243,0.171,0.140,0.104,0.121,0.2200.243, 0.171, 0.140, 0.104, 0.121, 0.220, and the loss −log⁡0.243=1.414-\log 0.243 = 1.414. The gradient on vcoffeev_{\text{coffee}}, ∑wp(w∣c) uw−udrink=(−0.193,−0.277)\sum_w p(w \mid c)\, u_w - u_{\text{drink}} = (-0.193, -0.277), needs all six rows and pushes down cup, a plausible context ranked second; negative sampling pushes a word down only when it is drawn.

Which words are negatives#

Negatives are drawn from the unigram distribution raised to the power 3/43/4 and renormalized (Mikolov et al., 2013b, §2.2):

Pn(w)=count⁡(w)3/4∑w′∈Vcount⁡(w′)3/4.P_n(w) = \frac{\operatorname{count}(w)^{3/4}}{\sum_{w' \in V} \operatorname{count}(w')^{3/4}} .

With toy counts the 600, coffee 30 and espresso 3, sampling in proportion to the counts gives probabilities 0.948,0.047,0.0050.948, 0.047, 0.005, and the 3/43/4 power gives 0.889,0.094,0.0170.889, 0.094, 0.017: espresso becomes 3.5 times more likely to be drawn.

Figure

Raising the unigram distribution to the power 3/4

Noise distribution for three powers of the countsGrouped bar chart over word ranks one to ten. Grey bars, proportional to frequency, fall from 0.34 at rank one to 0.034 at rank ten. Blue bars, frequency to the power three quarters, fall less steeply, from 0.27 to 0.047. A dashed horizontal line at 0.1 marks uniform sampling.0.10.20.3012345678910word rank (1 = most frequent)P(w)α = 1: ratio 10α = 3/4: ratio 5.6α = 0: uniformratio = P(rank 1) / P(rank 10)Noise distribution for three powers of the countsGrouped bar chart over word ranks one to ten. Grey bars, proportional to frequency, fall from 0.34 at rank one to 0.034 at rank ten. Blue bars, frequency to the power three quarters, fall less steeply, from 0.27 to 0.047. A dashed horizontal line at 0.1 marks uniform sampling.0.10.20.3012345678910word rank (1 = most frequent)P(w)α = 1: ratio 10α = 3/4: ratio 5.6α = 0: uniformratio = P(rank 1) / P(rank 10)
A toy vocabulary of 10 words whose counts follow Zipf's law: count proportional to 1/rank. Grey: negatives drawn in proportion to frequency (α = 1). Blue: the Word2Vec choice α = 3/4. Dashed: uniform sampling (α = 0). The power 3/4 takes probability from the most frequent words and gives it to the rare ones: the most frequent word is drawn 10 times as often as the rarest with α = 1, 5.6 times as often with α = 3/4. The value 3/4 was chosen empirically.

Subsampling frequent words#

Pairs with the or a are numerous and uninformative. Before windows are formed, each occurrence of a word ww with relative frequency f(w)f(w) is discarded with probability

Pdiscard(w)=1−θ/f(w)P_{\text{discard}}(w) = 1 - \sqrt{\theta / f(w)}

for a threshold θ≈10−5\theta \approx 10^{-5}, and never when f(w)≤θf(w) \le \theta (Mikolov et al., 2013b, §2.3). For toy frequencies 0.050.05, 10−310^{-3} and 10−410^{-4} the discard probabilities are 0.9860.986, 0.90.9 and 0.680.68. Removing a token brings the words around it closer, so subsampling also widens the effective window. gensim uses a variant of this rule with threshold sample, default 10−310^{-3}.

What negative sampling optimizes#

Negative sampling optimizes a different objective from the softmax, a simplification of noise-contrastive estimation (Gutmann and Hyvärinen, 2010; Mnih and Teh, 2012), which classifies with the corrected logit uo⋅vc−log⁡(k Pn(o))u_o \cdot v_c - \log\big(k\, P_n(o)\big) and whose optimum is log⁡P(o∣c)\log P(o \mid c). Negative sampling uses the raw score (Mikolov et al., 2013b, §2.2), so its optimum is shifted: if dd is large enough for every score to be set independently, it is the pointwise mutual information shifted by log⁡k\log k (Levy and Goldberg, 2014, §3.1):

uo⋅vc=PMI⁡(c,o)−log⁡k,PMI⁡(c,o)=log⁡P(c,o)P(c) Pn(o).u_o \cdot v_c = \operatorname{PMI}(c, o) - \log k, \qquad \operatorname{PMI}(c, o) = \log \frac{P(c, o)}{P(c)\, P_n(o)} .

With the 3/43/4 power this is a smoothed PMI: rare context words get a larger Pn(o)P_n(o) and a smaller value (Levy, Goldberg and Dagan, 2015, “context distribution smoothing”).

Figure

The per-pair negative-sampling objective and its minimum

Per-pair SGNS objective against the scoreThree curves over the score from minus four to four. The blue curve, for a strongly associated pair with PMI 3.00, is U-shaped with its minimum at 1.39. The amber curve, for a pair that co-occurs as often as chance predicts, PMI zero, has its minimum at −1.61. Below the axis two arrows run from each PMI to the corresponding minimum, both of length log 5. A dotted grey curve for a pair that never co-occurs falls monotonically towards zero on the left and has no minimum.123−4−20240score x = uo · vcPMI 3.00 → minimum 1.39PMI 0.00 → minimum −1.61arrows: from the PMI (open) to the minimum (filled), a shift of −log k = −1.61associated: #(c, o) = 200, PMI 3.00unrelated: #(c, o) = 10, PMI 0.00never co-occur: #(c, o) = 0, no minimumPer-pair SGNS objective against the scoreThree curves over the score from minus four to four. The blue curve, for a strongly associated pair with PMI 3.00, is U-shaped with its minimum at 1.39. The amber curve, for a pair that co-occurs as often as chance predicts, PMI zero, has its minimum at −1.61. Below the axis two arrows run from each PMI to the corresponding minimum, both of length log 5. A dotted grey curve for a pair that never co-occurs falls monotonically towards zero on the left and has no minimum.123−4−20240score x = uo · vc3.00 → 1.390.00 → −1.61arrows: PMI → minimum, −log k = −1.61#(c, o) = 200, PMI 3.00#(c, o) = 10, PMI 0.00#(c, o) = 0, no minimum
The objective of one pair (c, o) as a function of its score x = u_o · v_c, divided by the number of terms so that the curves share an axis. Toy counts: the centre word c occurs in #(c) = 1000 pairs, P_n(o) = 0.01 and k = 5, so o is drawn as a negative of c 50 times in expectation. Blue: o occurs with c 200 times, PMI = log 20 = 3.00. Amber: 10 times, PMI = 0.00, as often as chance predicts. Each curve has its minimum (filled point) at PMI − log k, 1.39 and −1.61; the arrows below the axis show the shift by log 5 = 1.61 from the PMI (open marker). Dotted: a pair that never co-occurs keeps only the negative term −log σ(−x), which is non-negative and decreases towards its infimum 0 as x → −∞ without reaching it, so there is no finite minimizer and its optimal score is −∞.

So SGNS factorizes the shifted PMI matrix into WinWout⊤W_{\text{in}} W_{\text{out}}^\top of rank dd, and this compression puts words with similar PMI rows close together. Pairs that never co-occur have PMI⁡=−∞\operatorname{PMI} = -\infty (dotted curve), so there it stays approximate for any dd.

What a small model learns from Quora questions#

We train a model with d=32d = 32, window radius 5 and minimum count 5 on about half a million Quora questions, tokenized with stopwords removed but punctuation such as ? kept. Everything else is a gensim default (table below), so this is CBOW with negative sampling, k=5k = 5, and subsampling.

The vector of word has 32 coordinates between −4.09-4.09 and 4.184.18 (norm 10.7), and its nearest cosine neighbours, listed in the previous note, are sentence (0.836), words (0.796) and verb (0.787). Singular and plural forms sit together (word/words, phrase/phrases) because the text was not lemmatized. The neighbours are topical as much as grammatical because, without stopwords and with ? subsampled, a radius-5 window covers more of a question than five raw tokens.

A second CBOW model, 100-dimensional with minimum count 4 and window radius 5, is trained on the AG News training articles only, so that no test words leak in; it supplies the input vectors of the next note.

Hyperparameters and what they do#

ParameterEffectDefault in gensimQuora and AG News models
vector_size ddCapacity; 50–300 is the usual range10032 (Quora), 100 (AG News)
window mmRadius; larger windows give more topical neighbours, smaller ones more syntactic ones (Jurafsky and Martin, §5.7)55
min_countDrops rarer words; sets ∣V∣\lvert V \rvert55 (Quora), 4 (AG News)
sg0 = CBOW, 1 = skip-gram0default
negative kkNegatives per pair; 0 with hs=1 gives hierarchical softmax5default
ns_exponentPower of the counts in PnP_n0.75default
sampleSubsampling threshold for frequent words10−310^{-3}default
epochs, alphaPasses over the corpus; initial learning rate5, 0.025default

With tuned window, subsampling, negatives and noise exponent, count-based methods and SGNS perform much more alike than the original comparisons suggested (Levy, Goldberg and Dagan, 2015).

What changed#

Task-trained embeddingsFull-softmax Word2VecWord2Vec with negative sampling
Training signalLabels of one taskThe text itselfThe text itself
Data availableThousands of labelled examplesBillions of tokensBillions of tokens
Vocabulary coverageWords in the labelled setWords in the corpusWords in the corpus
Output per stepKK label classes∣V∣\lvert V \rvert-way softmaxk+1k + 1 binary classifiers
Parameters touched per pair (∣V∣=200,000\lvert V \rvert = 200{,}000, d=300d = 300)—60,000,3002,100 (k=5k = 5)
What the vectors encodeWhatever separates the labelsCo-occurrence structureShifted PMI, compressed to rank dd

The result is a table that any model can reuse.

GloVe and FastText#

Two later static embeddings have notes of their own. GloVe (Pennington, Socher and Manning, 2014), which gave the Twitter vectors of the previous note, fits uw⋅vc+bw+bc≈log⁡Xwcu_w \cdot v_c + b_w + b_c \approx \log X_{wc} to the co-occurrence matrix XX by weighted least squares; like SGNS it fits a function of co-occurrence counts with dot products, so the two end up close (GloVe note). FastText (Bojanowski et al., 2017) trains SGNS but represents a word as the sum of its character n-gram vectors (where → <wh, whe, her, ere, re>), so related words share parameters and an unseen word still gets a vector (FastText note).

Limitations#

  • Static. One vector per word type: bank is a single compromise between the river and the money. The BERT note removes this.
  • Closed vocabulary. Words below min_count or absent from the corpus get no vector; FastText and subword tokenization address this.
  • Window-bound. Only neighbours within mm positions shape a vector, and CBOW ignores their order; negation and long-range dependencies do not enter.
  • Similarity means substitutability. good and bad, hot and cold, Monday and Tuesday share contexts and end up close, the wrong geometry for sentiment.
  • Data-hungry. Half a million questions suffice for frequent words such as word, not for rare ones; the analogies of the previous note use billions of tokens.
  • Sensitive, not reproducible. Preprocessing, window, subsampling and kk change the neighbours, and multithreaded runs with one seed differ.

What you should remember#

  • Skip-gram predicts the context from the centre, CBOW the centre from the context. The network is linear; its first layer WinW_{\text{in}} is the embedding table, the output layer only a training signal.
  • The full softmax updates all ∣V∣|V| output rows per pair; negative sampling classifies the real pair against kk pairs drawn from the 3/43/4-power unigram distribution and updates (k+2)d(k + 2) d parameters.
  • At its optimum SGNS sets uo⋅vc=PMI⁡(c,o)−log⁡ku_o \cdot v_c = \operatorname{PMI}(c, o) - \log k: the vectors are a low-rank compression of co-occurrence statistics.
  • gensim trains CBOW with k=5k = 5 negatives by default; skip-gram needs sg=1.

Notebook#

week01_word_embeddings.ipynb. Cell numbers count every cell, markdown included, from 1. Quoted numbers come from the run saved with the course; cells changed since then for current library versions have no saved output.

  • Data (cells 4–31). Cell 4 downloads the Quora file only if it is missing (the repository already has it); cell 6 reads data/quora.txt from disk. Cells 13–22 build data_tok: wordpunct_tokenize, lower-casing (an exercise in cell 15, with the solution filled in), NLTK stopword removal, punctuation kept. The lemmatized and stemmed variants of the 537,272 questions (cells 28–31) are not used by Word2Vec.
  • Training (cells 53–58). Markdown introduces skip-gram and gensim (Alammar, 2019); cell 58 trains Word2Vec(data_tok, vector_size=32, min_count=5, window=5), which with the defaults is CBOW with 5 negatives and the summed context update (cbow_mean=1) described above, not skip-gram.
  • Neighbours (cells 59–60). The vector of word and its nearest neighbours, the only saved outputs of this model: no loss curve, training time, vocabulary size or evaluation score was saved. The norm 10.7 quoted above is computed from the printed coordinates.
  • Analogies (cells 61–66). Pretrained 100-dimensional GloVe Twitter vectors and the analogies reported in the previous note.

week02_NN_text_classification.ipynb, cells 13–15, trains a 100-dimensional CBOW model (min_count=4, window=5) on the AG News training texts only, so no test words leak in, and turns each article into a sequence of vectors for the next note.

Next#

Word2Vec learns from one window at a time and never looks at the corpus as a whole. The next note counts every pair of words once into a co-occurrence matrix and fits vectors to the logarithms of those counts directly, and shows that the two approaches end up factorizing nearly the same matrix.

References#