CBoW PyTorch

15-LanguageModelingartificial-intelligencernnganmicrosoft-for-beginnerslessonsAImicrosoft-AI-For-Beginnersmachine-learning5-NLPdeep-learningcomputer-visioncnnNLP

Training CBoW Model

This notebooks is a part of AI for Beginners Curriculum

In this example, we will look at training CBoW language model to get our own Word2Vec embedding space. We will use AG News dataset as the source of text.

[ ]
[ ]

First let's load our dataset and define tokenizer and vocabulary. We will set vocab_size to 5000 to limit computations a bit.

[ ]
[ ]
Loading dataset...
Building vocab...
[ ]

CBoW Model

CBoW learns to predict a word based on the 2N2N neighboring words. For example, when N=1N=1, we will get the following pairs from the sentence I like to train networks: (like,I), (I, like), (to, like), (like,to), (train,to), (to, train), (networks, train), (train,networks). Here, first word is the neighboring word used as an input, and second word is the one we are predicting.

To build a network to predict next word, we will need to supply neighboring word as input, and get word number as output. The architecture of CBoW network is the following:

  • Input word is passed through the embedding layer. This very embedding layer would be our Word2Vec embedding, thus we will define it separately as embedder variable. We will use embedding size = 30 in this example, even though you might want to experiment with higher dimensions (real word2vec has 300)
  • Embedding vector would then be passed to a linear layer that will predict output word. Thus it has the vocab_size neurons.

For the output, if we use CrossEntropyLoss as loss function, we would also have to provide just word numbers as expected results, without one-hot encoding.

[ ]
Sequential(
  (0): Embedding(5002, 30)
  (1): Linear(in_features=30, out_features=5002, bias=True)
)

Preparing Training Data

Now let's program the main function that will compute CBoW word pairs from text. This function will allow us to specify window size, and will return a set of pairs - input and output word. Note that this function can be used on words, as well as on vectors/tensors - which will allow us to encode the text, before passing it to to_cbow function.

[ ]
[['like', 'I'], ['to', 'I'], ['I', 'like'], ['to', 'like'], ['train', 'like'], ['I', 'to'], ['like', 'to'], ['train', 'to'], ['networks', 'to'], ['like', 'train'], ['to', 'train'], ['networks', 'train'], ['to', 'networks'], ['train', 'networks']]
[[232, 172], [5, 172], [172, 232], [5, 232], [0, 232], [172, 5], [232, 5], [0, 5], [1202, 5], [232, 0], [5, 0], [1202, 0], [5, 1202], [0, 1202]]

Let's prepare the training dataset. We will go through all news, call to_cbow to get the list of word pairs, and add those pairs to X and Y. For the sake of time, we will only consider first 10k news items - you can easily remove the limitation in case you have more time to wait, and want to get better embeddings :)

[ ]

We will also convert that data to one dataset, and create dataloader:

[ ]

We will also convert that data to one dataset, and create dataloader:

[ ]

Now let's do the actual training. We will use SGD optimizer with pretty high learning rate. You can also try playing around with other optimizers, such as Adam. We will train for 10 epochs to begin with - and you can re-run this cell if you want even lower loss.

[ ]
[ ]
Epoch: 1: loss=5.664632366860172
Epoch: 2: loss=5.632101973960962
Epoch: 3: loss=5.610399051405015
Epoch: 4: loss=5.594621561080262
Epoch: 5: loss=5.582538017415446
Epoch: 6: loss=5.572900234519603
Epoch: 7: loss=5.564951676341915
Epoch: 8: loss=5.558288112064614
Epoch: 9: loss=5.552576955031129
Epoch: 10: loss=5.547634165194347
5.547634165194347

Trying out Word2Vec

To use Word2Vec, let's extract vectors corresponding to all words in our vocabulary:

[ ]

Let's see, for example, how the word Paris is encoded into a vector:

[ ]
tensor([-0.0915,  2.1224, -0.0281, -0.6819,  1.1219,  0.6458, -1.3704, -1.3314,
        -1.1437,  0.4496,  0.2301, -0.3515, -0.8485,  1.0481,  0.4386, -0.8949,
         0.5644,  1.0939, -2.5096,  3.2949, -0.2601, -0.8640,  0.1421, -0.0804,
        -0.5083, -1.0560,  0.9753, -0.5949, -1.6046,  0.5774],
       grad_fn=<EmbeddingBackward>)

It is interesting to use Word2Vec to look for synonyms. The following function will return n closest words to a given input. To find them, we compute the norm of wiv|w_i - v|, where vv is the vector corresponding to our input word, and wiw_i is the encoding of ii-th word in the vocabulary. We then sort the array and return corresponding indices using argsort, and take first n elements of the list, which encode positions of closest words in the vocabulary.

[ ]
['microsoft', 'quoted', 'lp', 'rate', 'top']
[ ]
['basketball', 'lot', 'sinai', 'states', 'healthdaynews']
[ ]
['funds', 'travel', 'sydney', 'japan', 'business']

Takeaway

Using clever techniques such as CBoW, we can train Word2Vec model. You may also try to train skip-gram model that is trained to predict the neighboring word given the central one, and see how well it performs.