"
+ },
+ "metadata": {}
+ }
+ ],
+ "execution_count": 20,
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "One of the reasons we're not seeing higher accuracy is because some words from our dataset are missing in the pretrained GloVe vocabulary, and thus they are essentially ignored. To overcome this, we can train our own embeddings based on our dataset. \n",
+ "\n",
+ "\n",
+ "## Training your own embeddings\n",
+ "\n",
+ "In our examples, we have been using pretrained semantic embeddings, but it is interesting to see how those embeddings can be trained using either CBoW, or skip-gram architectures. This exercise goes beyond this module, but those interested might want to check out this [official TensorFlow tutorial on training Word2Vec model](https://www.tensorflow.org/tutorials/text/word2vec). Also, the **gensim** framework can be used to train the most commonly used embeddings in a few lines of code, as described [in the official documentation](https://radimrehurek.com/gensim/auto_examples/tutorials/run_word2vec.html#training-your-own-model)."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Contextual embeddings\n",
+ "\n",
+ "One key limitation of traditional pretrained embedding representations such as Word2Vec is the fact that, even though they can capture some meaning of a word, they can't differentiate between different meanings. This can cause problems in downstream models.\n",
+ "\n",
+ "For example the word 'play' has different meaning in these two different sentences:\n",
+ "- I went to a **play** at the theater.\n",
+ "- John wants to **play** with his friends.\n",
+ "\n",
+ "The pretrained embeddings we talked about represent both meanings of the word 'play' in the same embedding. To overcome this limitation, we need to build embeddings based on the **language model**, which is trained on a large corpus of text, and *knows* how words can be put together in different contexts. Discussing contextual embeddings is out of scope for this tutorial, but we will come back to them when talking about language models in the next unit.\n"
+ ],
+ "metadata": {}
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "name": "conda-env-py37_tensorflow-py",
+ "language": "python",
+ "display_name": "py37_tensorflow"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.7.9",
+ "mimetype": "text/x-python",
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "pygments_lexer": "ipython3",
+ "nbconvert_exporter": "python",
+ "file_extension": ".py"
+ },
+ "kernel_info": {
+ "name": "conda-env-py37_tensorflow-py"
+ },
+ "nteract": {
+ "version": "nteract-front-end@1.0.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
\ No newline at end of file
diff --git a/5-NLP/14-Embeddings/torchnlp.py b/5-NLP/14-Embeddings/torchnlp.py
new file mode 100644
index 00000000..d6ca5e0c
--- /dev/null
+++ b/5-NLP/14-Embeddings/torchnlp.py
@@ -0,0 +1,104 @@
+import builtins
+import torch
+import torchtext
+import collections
+import os
+
+device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+
+vocab = None
+tokenizer = torchtext.data.utils.get_tokenizer('basic_english')
+
+def load_dataset(ngrams=1,min_freq=1):
+ global vocab, tokenizer
+ print("Loading dataset...")
+ train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')
+ train_dataset = list(train_dataset)
+ test_dataset = list(test_dataset)
+ classes = ['World', 'Sports', 'Business', 'Sci/Tech']
+ print('Building vocab...')
+ counter = collections.Counter()
+ for (label, line) in train_dataset:
+ counter.update(torchtext.data.utils.ngrams_iterator(tokenizer(line),ngrams=ngrams))
+ vocab = torchtext.vocab.Vocab(counter, min_freq=min_freq)
+ return train_dataset,test_dataset,classes,vocab
+
+def encode(x,voc=None,unk=0,tokenizer=tokenizer):
+ v = vocab if voc is None else voc
+ return [v.stoi.get(s,unk) for s in tokenizer(x)]
+
+def train_epoch(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.CrossEntropyLoss(),epoch_size=None, report_freq=200):
+ optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)
+ loss_fn = loss_fn.to(device)
+ net.train()
+ total_loss,acc,count,i = 0,0,0,0
+ for labels,features in dataloader:
+ optimizer.zero_grad()
+ features, labels = features.to(device), labels.to(device)
+ out = net(features)
+ loss = loss_fn(out,labels) #cross_entropy(out,labels)
+ loss.backward()
+ optimizer.step()
+ total_loss+=loss
+ _,predicted = torch.max(out,1)
+ acc+=(predicted==labels).sum()
+ count+=len(labels)
+ i+=1
+ if i%report_freq==0:
+ print(f"{count}: acc={acc.item()/count}")
+ if epoch_size and count>epoch_size:
+ break
+ return total_loss.item()/count, acc.item()/count
+
+def padify(b,voc=None,tokenizer=tokenizer):
+ # b is the list of tuples of length batch_size
+ # - first element of a tuple = label,
+ # - second = feature (text sequence)
+ # build vectorized sequence
+ v = [encode(x[1],voc=voc,tokenizer=tokenizer) for x in b]
+ # compute max length of a sequence in this minibatch
+ l = max(map(len,v))
+ return ( # tuple of two tensors - labels and features
+ torch.LongTensor([t[0]-1 for t in b]),
+ torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])
+ )
+
+def offsetify(b,voc=None):
+ # first, compute data tensor from all sequences
+ x = [torch.tensor(encode(t[1],voc=voc)) for t in b]
+ # now, compute the offsets by accumulating the tensor of sequence lengths
+ o = [0] + [len(t) for t in x]
+ o = torch.tensor(o[:-1]).cumsum(dim=0)
+ return (
+ torch.LongTensor([t[0]-1 for t in b]), # labels
+ torch.cat(x), # text
+ o
+ )
+
+def train_epoch_emb(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.CrossEntropyLoss(),epoch_size=None, report_freq=200,use_pack_sequence=False):
+ optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)
+ loss_fn = loss_fn.to(device)
+ net.train()
+ total_loss,acc,count,i = 0,0,0,0
+ for labels,text,off in dataloader:
+ optimizer.zero_grad()
+ labels,text = labels.to(device), text.to(device)
+ if use_pack_sequence:
+ off = off.to('cpu')
+ else:
+ off = off.to(device)
+ out = net(text, off)
+ loss = loss_fn(out,labels) #cross_entropy(out,labels)
+ loss.backward()
+ optimizer.step()
+ total_loss+=loss
+ _,predicted = torch.max(out,1)
+ acc+=(predicted==labels).sum()
+ count+=len(labels)
+ i+=1
+ if i%report_freq==0:
+ print(f"{count}: acc={acc.item()/count}")
+ if epoch_size and count>epoch_size:
+ break
+ return total_loss.item()/count, acc.item()/count
+
diff --git a/5-NLP/README.md b/5-NLP/README.md
new file mode 100644
index 00000000..5ea06aa8
--- /dev/null
+++ b/5-NLP/README.md
@@ -0,0 +1,39 @@
+# Natural Language Processing
+
+In this section, we will focus on using Neural Networks to handle tasks related to natural language processing (NLP). There are many NLP problems that we want computers to be able to solve:
+
+* **Text classification** is typical classification problem on text sequences. Examples include classifying e-mail messages on spam vs. no-spam, or attributing news article into one of the pre-defined categories (sport, business, politics, etc.). Also, when developing chat bots, we often need to understand what a used wanted to say -- in this case we are dealing with **intent classificaton**. Often, in intent classification we need to deal with many categories.
+* **Sentiment analysis** is typical regression problem, where we need to attribute a number -- sentiment -- corresponding to how positive/negative the meaning of a sentence is. More advanced version of sentiment analysis is **aspect-based sentiment analysis** (ABSA), where we attribute sentiment not the the whole sentence, but to different parts of it (aspects), eg. *In this restaurant, I liked the cuisine, but the atmosphere was awful*.
+* **Named Entity Recognition** (NER) refers to the problem of extracting certain entities from text. For example, we might need to understand that in the phrase *I need to fly to Paris tomorrow* the word *tomorrow* refers to DATE, and *Paris* is a LOCATION.
+* **Keyword extraction** is similar to NER, but we need to extract words important to the meaning of the sentence automatically, without pre-training for specific entity types.
+* **Text clustering** can be useful when we want to group together similar sentences, for example, similar requests in technical support conversations.
+* **Question answering** refers to the ability of a model to answer a specific question. The model receives a text passage and a question as inputs, and it needs to provide a place in the text where the answer to the question is contained (or, sometimes, to generate the answer text).
+* **Text Generation** is the ability of a model to generate new text. It can be considered as classification task that predicts next letter/word based on some *text prompt*. Advanced text generation models, such as GPT-3, are able to solve other NLP tasks such as classification using a technique called [prompt programming](https://towardsdatascience.com/software-3-0-how-prompting-will-change-the-rules-of-the-game-a982fbfe1e0) or [prompt engineering](https://medium.com/swlh/openai-gpt-3-and-prompt-engineering-dcdc2c5fcd29)
+* **Text summarization** is a technique when we want a computer to "read" long text, and summarize it in a few sentences.
+* **Machine translation** can be viewed as a combination of text understanding in one language, and text generation in another one.
+
+Initially, most of NLP tasks were solved using traditional methods such as grammars. For example, in machine translation parsers were used to transform initial sentence into a syntax tree, then higher level semantic structures were extracted to represent the meaning of the sentence, and based on this meaning and grammar of the target language the result was generated. Nowadays, many NLP tasks are more effectively solved using neural networks.
+
+Many classical NLP methods are implemented in [Natural Language Processing Toolkit (NLTK)](https://www.nltk.org) Python library. There is a great [NLTK Book](https://www.nltk.org/book/) available online that covers how different NLP tasks can be solved using NLTK.
+
+In our course, we will mostly focus on using Neural Networks for NLP, and we will use NLTK where needed.
+
+We have already learnt about using neural networks for dealing with tabular data and with images. The main difference between those types of data and text is that text is a sequence of variable length, while the input size in case of images is known in advance. While convolutional networks can extract patterns from input data, patterns in text are more complex. Eg., we can have negation being separated from the subject be arbitrary many words (eg. *I do not like organges*, vs. *I do not like those big colorful tasty oranges*), and that should still be interpreted as one pattern. Thus, to handle language we need to introduce new neural network types, such as *recurrent networks* and *transformers*.
+
+## Install Libraries
+
+If you are using local Python installation to run this course, you may need to install all required libraries for NLP using the following commands:
+
+**For PyTorch**
+```bash
+pip install -r requirements-torch.txt
+```
+**For Tensorflow**
+```bash
+pip install -r requirements-tf.txt
+```
+
+## Contents
+
+* [Representing text as tensors](13-TextRep/README.md)
+* [Word Embeddings](14-Emdeddings/README.md)
diff --git a/5-NLP/requirements-pytorch.txt b/5-NLP/requirements-pytorch.txt
new file mode 100644
index 00000000..3545f559
--- /dev/null
+++ b/5-NLP/requirements-pytorch.txt
@@ -0,0 +1,15 @@
+gensim==3.8.3
+huggingface==0.0.1
+matplotlib
+nltk==3.5
+numpy==1.18.5
+opencv-python==4.5.1.48
+Pillow==7.1.2
+scikit-learn
+scipy
+torch==1.8.1
+torchaudio==0.8.1
+torchinfo==0.0.8
+torchtext==0.9.1
+torchvision==0.9.1
+transformers==4.3.3
\ No newline at end of file
diff --git a/5-NLP/requirements-tf.txt b/5-NLP/requirements-tf.txt
new file mode 100644
index 00000000..8b7689c0
--- /dev/null
+++ b/5-NLP/requirements-tf.txt
@@ -0,0 +1,12 @@
+gensim==3.8.3
+huggingface==0.0.1
+matplotlib
+nltk==3.5
+numpy==1.18.5
+opencv-python==4.5.1.48
+Pillow==7.1.2
+scikit-learn
+scipy
+tensorflow
+tensorflow_datasets
+transformers==4.3.3
\ No newline at end of file
diff --git a/README.md b/README.md
index 4706c59f..0080b20a 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ For a gentle introduction to *AI in the Cloud* topic you may consider taking [Ge
Text Text |
PyTorch |
Keras/Tensorflow | |
-| IV | Computer Vision |
+
| IV | Computer Vision |
MS Learn |
MS Learn |
PAT |
@@ -57,17 +57,17 @@ For a gentle introduction to *AI in the Cloud* topic you may consider taking [Ge
| 10 | Generative Adversarial Networks | Text | PyTorch | Tensorflow | |
| 11 | Object Detection | Text | PyTorch | Tensorflow | |
| 12 | Instance Segmentation. U-Net | Text | PyTorch | Tensorflow | |
-| V | Natural Language Processing |
+
| V | Natural Language Processing |
MS Learn |
MS Learn |
PAT |
-| 13 | Text Representation. Bow/TF-IDF | Text | PyTorch | Tensorflow | |
-| 14 | Semantic Word Embeddings | Text | PyTorch | Tensorflow | |
+| 13 | Text Representation. Bow/TF-IDF | Text | PyTorch | Tensorflow | |
+| 14 | Semantic word embeddings | Text | PyTorch | Tensorflow | |
| 15 | Training your own embeddings | Text | PyTorch | Tensorflow | |
| 16 | Recurrent Neural Networks | Text | PyTorch | Tensorflow | |
| 17 | Generative Recurrent Networks | Text | PyTorch | Tensorflow | |
-| 18 | Language Modelling. BERT. Transformers. | Text | PyTorch | Tensorflow | |
-| 19 | Named Entity Recognition. | Text | PyTorch | Tensorflow | |
+| 18 | Language Modelling. Transformers. BERT. | Text | PyTorch | Tensorflow | |
+| 19 | Named Entity Recognition | Text | PyTorch | Tensorflow | |
| 20 | Text Generation using GPT | Text | PyTorch | Tensorflow | |
| VI | Other AI Techniques | PAT |
| 21 | Genetic Algorithms | Text | Notebook | |