Before you start
Train word embeddings with skip-gram and negative sampling, the word2vec method.
You get (center, context) pairs of word ids that appeared near each other.
The model has two embedding tables, self.center and self.context. For a
true pair, the dot product of the centre vector u and the context vector
v should be large. For K random "negative" words it should be small:
loss = -mean over the batch of [ log sigmoid(u . v_pos) + sum_k log sigmoid(-u . v_neg_k) ]
Write three things:
noise_distribution(counts): the distribution to draw negatives from,
counts ** 0.75, normalised to sum to one.SkipGramNS: an nn.Module whose forward(center, context, negatives)
returns the scalar loss above. center and context have shape (B,),
negatives has shape (B, K).train_skipgram(pairs, counts, dim): trains a new model, drawing fresh
negatives for each batch with torch.multinomial, and returns it.def noise_distribution(counts):
class SkipGramNS(torch.nn.Module):
def __init__(self, vocab_size, dim): ...
def forward(self, center, context, negatives): ...
def train_skipgram(pairs, counts, dim):
Input
noise_distribution(torch.tensor([1.0, 16.0, 81.0]))
Output
tensor([0.0278, 0.2222, 0.7500])
Reasoning
The powers are 1 ** 0.75 = 1, 16 ** 0.75 = 8 and 81 ** 0.75 = 27. They
sum to 36, so the probabilities are 1/36, 8/36 and 27/36. The power
0.75 gives rare words more negatives than their raw frequency would.
self.center and self.context. Both are
nn.Embedding(vocab_size, dim).F.logsigmoid. torch.log(torch.sigmoid(x)) gives -inf when x is
a large negative number.Run it in Colab
Google Colab has PyTorch and a free GPU, and needs nothing installed. Take a code, open the notebook, and paste the code into its first cell. Grading happens there and the result comes back here.
In Colab, the grading cell is your Submit. It runs the hidden cases there, and the result shows here on its own. This one is scored on a threshold, not on exact values.
⇧↵run cell