{"cells":[{"metadata":{},"cell_type":"markdown","source":"# NLP Course- Transformers With Quora Binary Classification\n\n\nThis is an extension of [Notebook-1](https://www.kaggle.com/abhilash1910/nlp-workshop-ml-india/edit) where we will be focussing on extensive architectures from the transformer family. We will be using variants of the BERT transformer after understanding the fundamental building blocks of transformers and attention mechanisms.\n\nFirstly, we will be using transformers made with the help of the [HuggingFace Repository](https://huggingface.co/) specifically the [DistillBert](https://huggingface.co/transformers/model_doc/distilbert.html) transformer and then understand the inner layers inside the transformer. We will also be exploring the attention mechanisms- Self,Scaled Dot Product,Hierarchical- and other variants.\n\nThough we will be focussing on distillbert, we can also use any other versions as well. This is the [paper](https://paperswithcode.com/paper/attention-is-all-you-need) which started the revolution in NLP space related to attentions and transformers. This [repository](https://github.com/Lsdefine/attention-is-all-you-need-keras/blob/master/transformer.py) contains the original implementation of the transformer with scaled dot product attention.\n\n[hierarchical attention](https://github.com/abhilash1910/MiniAttention) this can be used for Hierarchical Attention.\n\n[Keras Example](https://keras.io/examples/nlp/text_classification_with_transformer/) also provides a good information for creating a custom model.\n\nThe most important architecture which remains the same throughout the Transformers architecture is :\n\n<img src=\"https://i0.wp.com/esciencegroup.com/wp-content/uploads/2020/02/01.png?resize=506%2C641&ssl=1\"></img>"},{"metadata":{},"cell_type":"markdown","source":"## Some useful resources \n\nThese are certain important resources and kernels which may help in understanding the codes of attention mechanisms with Keras:\n\n1. [Transformer in Keras](https://github.com/Lsdefine/attention-is-all-you-need-keras/blob/master/transformer.py)\n2. [Good Kernel](https://www.kaggle.com/suicaokhoailang/lstm-attention-baseline-0-652-lb)\n3. [Another Kernel](https://www.kaggle.com/shujian/transformer-initial-attempt)\n\nThese kernels are written well and they provide a good outline as to how the attention model is built internally. Through we will be discussin on this.\n"},{"metadata":{},"cell_type":"markdown","source":"## DistilBert \n\nThis contains the architecture of the distilbert transformer model:\n\n<img src=\"https://storage.googleapis.com/groundai-web-prod/media%2Fusers%2Fuser_14%2Fproject_391208%2Fimages%2FKD_figures%2Ftransformer_distillation.png\"></img>\n\nIn this case, the distilbert performs better than Bert in most cases owing to continuous feedback of attention weights from the teacher to the student network. Where the weights change by a large extent in case of Bert, this fails to happen in DistilBert."},{"metadata":{},"cell_type":"markdown","source":""},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Creating DistillBert with Transformers\n\nWe will be creating the DistillBert transformer and then training it with our own corpus.\nThen we will validate the results with our initial benchmarks from last kernel.\n\nFollow this [link](https://huggingface.co/models) for testing any pre-trained transformer model."},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\n\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras.layers import Dense, Input\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nfrom kaggle_datasets import KaggleDatasets\nimport transformers\nfrom tqdm.notebook import tqdm\nfrom tokenizers import BertWordPieceTokenizer\nfrom sklearn.model_selection import train_test_split\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Tokenize the Data (Fast Tokenize)\n\nThis will assist in the model tuning stage. We have to divide the data in chunks so that it is simpler for the model to absorb the data."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Tokenize the data and separate them in chunks of 256 units\n\nmaxlen=512\nchunk_size=256\ndef fast_encode(texts, tokenizer, chunk_size=chunk_size, maxlen=maxlen):\n    tokenizer.enable_truncation(max_length=maxlen)\n    tokenizer.enable_padding(max_length=maxlen)\n    all_ids = []\n    #sliding window methodology\n    for i in tqdm(range(0, len(texts), chunk_size)):\n        text_chunk = texts[i:i+chunk_size].tolist()\n        encs = tokenizer.encode_batch(text_chunk)\n        all_ids.extend([enc.ids for enc in encs])\n    \n    return np.array(all_ids)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model Building With DistillBert\n\nIn this context, we have to build the model. We are creating a function which would help us to do that .\n\nWe will be using the [Model](https://www.kaggle.com/abhilash1910/nlp-workshop-ml-india/) API from Keras which was mentioned in the session-1, and addionally we will be using the same additional layers as Dense. The activations (sigmoid) also remain pretty much the same."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create the model\n\ndef build_model(transformer, max_len=512):\n    input_word_ids = Input(shape=(max_len,), dtype=tf.int32, name=\"input_word_ids\")\n    #Replaced from the Embedding+LSTM/CoNN layers\n    sequence_output = transformer(input_word_ids)[0]\n    cls_token = sequence_output[:, 0, :]\n    out = Dense(1, activation='sigmoid')(cls_token)\n    \n    model = Model(inputs=input_word_ids, outputs=out)\n    model.compile(Adam(lr=1e-5), loss='binary_crossentropy', metrics=['accuracy'])\n    model.summary()\n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## TPU Cluster Check\n\nIn this context, we will be using the TPU cluster from the Notebook (Hardware accelerations). TPUs provide a better performance with respect to Tensorflow and Keras computations on tensors against GPUs.But it has to be explicitly called out in the code segment.\n\n[Kaggle Documentation on TPUs](https://www.kaggle.com/docs/tpu) provide an excellent starting point for this.Highly recommend to go through it.\n\nSteps to check and run the TPU cluster:\n\n### detect and init the TPU\ntpu = tf.distribute.cluster_resolver.TPUClusterResolver()\ntf.config.experimental_connect_to_cluster(tpu)\ntf.tpu.experimental.initialize_tpu_system(tpu)\n\n### instantiate a distribution strategy\ntpu_strategy = tf.distribute.experimental.TPUStrategy(tpu)\n\n### instantiating the model in the strategy scope creates the model on the TPU\nwith tpu_strategy.scope():\n    model = tf.keras.Sequential( … ) # define your model normally\n    model.compile( … )\n\n### train model normally\nmodel.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=…)"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Detect and deploy\n\ntry:\n    # TPU detection. No parameters necessary if TPU_NAME environment variable is\n    # set: this is always the case on Kaggle.\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Running on TPU ', tpu.master())\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    # Default distribution strategy in Tensorflow. Works on CPU and single GPU.\n    strategy = tf.distribute.get_strategy()\n\nprint(\"REPLICAS: \", strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Replicas\n\nThe replicas assist in segregating the data in sync, by allowing a faster batch sampling and an equal partition of the set, amongst the different replicas. In this context, it will be partitioned in blocks amongst 8 TPU clusters."},{"metadata":{"trusted":true},"cell_type":"code","source":"#allow experimental tf\nAUTO = tf.data.experimental.AUTOTUNE\n\n# Data access\nGCS_DS_PATH = KaggleDatasets().get_gcs_path()\n\n# Configuration of hyperparameters\nEPOCHS = 3\n#batch size denotes the partitioning amongst the cluster replicas.\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync\nMAX_LEN = 192","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load the Tokenizer from DistillBert\n\nIn this case, we will be using the [DistilBertTokenizer](https://huggingface.co/transformers/v2.11.0/model_doc/distilbert.html). This will help us to tokenize the data from 'distillbert-base-multilingual-cased' pre-trained tokenized model.\nIt is recommended to go through the different tokenizers present in [HuggingFace](https://huggingface.co/transformers/main_classes/tokenizer.html)\n\nThe two most important ones for generic language modelling:\n\n1. ByteLevelBPETokenizer\n2. BertWordPieceTokenizer\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# First load the real tokenizer\ntokenizer = transformers.DistilBertTokenizer.from_pretrained('distilbert-base-multilingual-cased')\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\nfast_tokenizer = BertWordPieceTokenizer('vocab.txt', lowercase=False)\nfast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_set['question_text'].shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['question_text']","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Tokenize the text samples\n\nIn this case, we apply the fast Tokenizer from Distillbert on the samples."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_x = fast_encode(train_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\nval_x = fast_encode(test_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_x.shape)\nprint(train_y.shape)\nprint(val_x.shape)\nprint(val_y.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create Datasets \n\nAn important aspect of finetuning Bert variants of transformers is to use a proper tensor slicing mechanism for splitting the training and validation sets. This allows the algorithm to understand the different datasets. This also allows the DistillBert algorithm to download and train the data in the form of \"tf.data.Dataset\", which effectively implies that we have converted the dataset to be compatible with tensorflow datasets."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((train_x, train_y))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((val_x, val_y))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_dataset)\nprint(valid_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Build the transformer model\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFDistilBertModel\n        .from_pretrained('distilbert-base-multilingual-cased')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Parameters in DistillBert\n\nAs it is visible the number of parameters have greatly increased and now it has approx. 10.34 million parameters (1 crore) to train. This increase in the number of trainable parameters make the transformer model less susceptible to catastrophic forgetting , which is prevalent in Sequential networks. Moreover, transformers have attention mechanisms which allow the neural network to retrieve certain important weights from the training network.  This form of learning is very commonly known as seq2seq modelling (a subset of transfer learning) deviced by Illya Sutskever from OpenAI. Some important resources in seq2seq learning is as follows:\n\n1. [Sutskever's Paper](https://paperswithcode.com/paper/sequence-to-sequence-learning-with-neural)\n2. [DistillBert Paper](https://paperswithcode.com/paper/distilbert-a-distilled-version-of-bert)\n3. [Representational Learning](https://paperswithcode.com/task/representation-learning)\n4. [Transfer Learning](https://paperswithcode.com/task/transfer-learning)\n\nThese resources are for scientific papers which would definitely assist in understanding the core concepts of transfer learning, seq2seq modelling."},{"metadata":{},"cell_type":"markdown","source":"## Train the Transformer\n\nIn this case, we train the DistillBert transformer with our corpus."},{"metadata":{"trusted":true},"cell_type":"code","source":"n_steps = train_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Validating the Model\n\nAfter saturation of the training metrics(accuracy), we have to validate the model against the validation /testing set. This is similar to the code written above."},{"metadata":{"trusted":true},"cell_type":"code","source":"n_steps = valid_x.shape[0] // BATCH_SIZE\ntrain_history_2 = model.fit(\n    valid_dataset.repeat(),\n    steps_per_epoch=n_steps,\n    epochs=EPOCHS*2\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Outline for training with any Transformer\n\nThe following is the outline for training any transformer(HuggingFace) with the Kaggle corpus:\n\n1. Create a function for Fast Tokenization. Provide the maxlen for truncating and chunk size.\n2. Create a function for the Transformer Model. Notice there are no additional Embedding/LSTM layers attached in the model.\n3. Detect and check for TPUs - this will greatly boost the training period for us.Tensor Processing Units are specifically designed    for super fast computing of the Tensors (in Tensorflow).\n4. Create Replicas to split the TPU cluster for better performance - recommended.\n5. Load the training and validation datasets into the Fast Tokenization function to encode it with any Transformer (in our case        DistillBert). Notice BertWordPieceTokenizer- this is used with any variant of Bert Transformer.\n6. After Tokenization, make the dataset compatible with Tensorflow datasets- (tensorflow.data.Datasets). This gives performance        boost on TPU.\n7. Load the Transformer model from The HuggingFace Repository. The code for this should be of the same pattern for any Transformer.\n8. Train the model with the parameters.\n9. Validate it against the validation set.\n\nThis pipeline follows for any classification task with Transformers. For categorical classification, only the change is required in the model building (function) stage - the last Dense layer should have a softmax activation instead of sigmoid. Other than this, no changes are required.\n\nThe list of pre-trained models from the HuggingFace repository can be found here:\n\n1. [Pre-trained Model Names](https://huggingface.co/transformers/pretrained_models.html)"},{"metadata":{},"cell_type":"markdown","source":"## Analysing a different Transformer\n\nNow that we have trained and validated against DistillBert, let us try another Transformer. In this case, we will be using the XLM- Roberta Transformer. Important details on this model can be found here:\n\n1. [XLM-Roberta](https://huggingface.co/transformers/model_doc/xlmroberta.html)\n2. [Paper](https://arxiv.org/abs/1911.02116)\n\nThis is entirely based on the Roberta Transformer by Facebook,and some of the details of that model is present here:\n\n1. [Roberta](https://huggingface.co/transformers/model_doc/roberta.html)\n2. [Paper](https://huggingface.co/transformers/model_doc/roberta.html)\n\nApart from this, there are several in the list which was provided in the tab above. Anyone can be tried out and the performance can be validated against.\n\nFor doing this, we follow the same instructions provided above. Since in this case, we already have done till step 4. \nFrom step 5 we have to change the tokenizer  and the model.\n\n The architecture for Roberta (original) is provided below:\n \n <img src=\"https://camo.githubusercontent.com/f5c0d05eb0635cdd0e17e137265af23fa825b1d4/68747470733a2f2f646c2e666261697075626c696366696c65732e636f6d2f584c4d2f786c6d5f6669677572652e6a7067\"></img>"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n# First load the real tokenizer\ntokenizer = transformers.XLMRobertaTokenizer.from_pretrained('xlm-roberta-base')\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\nfast_tokenizer = BertWordPieceTokenizer('vocab.txt', lowercase=False)\nfast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n#Tokenize the samples\ntrain_x = fast_encode(train_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\nval_x = fast_encode(test_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 6.\n#Load into Tensorflow compatible datasets\ntrain_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((train_x, train_y))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((val_x, val_y))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\nprint(train_dataset)\nprint(valid_dataset)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 7.\n#Build the transformer model\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFRobertaModel\n        .from_pretrained('roberta-base')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 8.\n#Train the Transformer\n\nn_steps = train_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 9.\n#Validate the model\n\nn_steps = val_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Albert- The lightweight Bert\n\nWe have seen 2 different transformers for our use case- DistillBert, XLM-Roberta (Roberta). Now let us see the performance of ALbert from Google Research. It is a lightweight , which uses splits and tensor decomposition of the embedding matrix. Most of the architecture is same as Bert, with the addition of repeated layers which reduces memory consumption. These are the resources for understanding Albert and Bert:\n\n1. [HuggingFace Albert](https://huggingface.co/transformers/model_doc/albert.html)\n2. [Albert Paper](https://arxiv.org/abs/1909.11942)\n\nThe original Bert paper and resources are present in these links:\n\n1. [Traditional BERT](https://huggingface.co/transformers/model_doc/bert.html)\n2. [Paper](https://arxiv.org/abs/1810.04805)\n\nIn this case, we will first use Bert Transformer and then analyse the performance using Albert.\nThis will allow us to see the speed up and the increase in performance in Albert from Bert. \n\nAs usual we will be focussing from Steps 5 to 9."},{"metadata":{},"cell_type":"markdown","source":"## Analysis with Bert Transformer\n\nFirst, let us build a composite Bert model for our use case.\nThe model architecture of Bert is shown from the paper :\n\n<img src=\"https://miro.medium.com/max/1000/1*G6PYuBxc7ryP4Pz7nrZJgQ@2x.png\"></img>\n\n\nThe pathway from pre-training to fine-tuning is shown here:\n\n<img src=\"data:image/jpeg;base64,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\"></img>\n\n\n\nThe full block diagram of internal layers of the Bert model is shown here:\n\n<img src=\"https://miro.medium.com/max/876/0*ViwaI3Vvbnd-CJSQ.png\"></img>"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n# First load the real tokenizer- Bert\ntokenizer = transformers.BertTokenizer.from_pretrained('bert-base-multilingual-cased')\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\nfast_tokenizer = BertWordPieceTokenizer('vocab.txt', lowercase=False)\nfast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n#Tokenize the datasets\ntrain_x = fast_encode(train_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\nval_x = fast_encode(test_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values\nprint(train_x.shape)\nprint(train_y.shape)\nprint(val_x.shape)\nprint(val_y.shape)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 6.\n#Create Tensorflow Datasets\ntrain_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((train_x, train_y))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((val_x, val_y))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\nprint(train_dataset)\nprint(valid_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 7.\n#Build the transformer model\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFBertModel\n        .from_pretrained('bert-base-multilingual-cased')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 8.\n#Train the model\n\nn_steps = train_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 9.\n#Validate the model\n\nn_steps = val_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Analyse the Albert Model\n\nNow with the performance of Bert with us, we will be analysing the Albert model for our use case.\nFor this, we will use the Albert Model from HuggingFace Transformers"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n# First load the real tokenizer- Bert\ntokenizer = transformers.AlbertTokenizer.from_pretrained('albert-base-v1')\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\nfast_tokenizer = BertWordPieceTokenizer('vocab.txt', lowercase=False)\nfast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n#Tokenize the datasets\ntrain_x = fast_encode(train_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\nval_x = fast_encode(test_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values\nprint(train_x.shape)\nprint(train_y.shape)\nprint(val_x.shape)\nprint(val_y.shape)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 6.\n#Create Tensorflow Datasets\ntrain_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((train_x, train_y))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((val_x, val_y))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\nprint(train_dataset)\nprint(valid_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 7.\n#Build the transformer model\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFAlbertModel\n        .from_pretrained('albert-base-v1')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 8.\n#Train the model\n\nn_steps = train_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 9.\n#Validate the model\n\nn_steps = val_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Some other Transformers\n\nThere are several transformers we can use for our use cases. We will be focussing on  more such transformer architectures.\nThe first one is GPT (OpenAI) and the second is BART (Facebook).\n\nGPT(Generative Pre-training) is a SOTA for generative (transfer learning) based architecture which has achieved great heights with its new language models (GPT2/3). We will be analysing the performance of GPT-2 for our use case. Some important resources on GPT-2:\n\n1. [GPT-2](https://openai.com/blog/better-language-models/)\n2. [HuggingFace GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html)\n\nWe will also be looking into BART, which is another improvisation by Facebook,done by using Bert's left to right encoder and GPT's right to left decoder. Some resources on this can be found at:\n\n1. [BART](https://huggingface.co/transformers/model_doc/bart.html)\n2. [Paper](https://arxiv.org/abs/1910.13461)\n\nFor our usecases, we will just follow the steps from before and build these models on our corpuses. \nSince BART is incompatible with Tensorflow yet, we can try it using Pytorch.\nAnother Transformer architecture which is important is TransformerXL:\n\n1. [TransformerXL](https://huggingface.co/transformers/model_doc/transformerxl.html)\n2. [Paper](https://arxiv.org/abs/1901.02860)\n\nThis covers most of the famous architectures in the Transformer space. A comparative analysis between Bert and Gpt model can be found here:\n\n<img src=\"data:image/png;base64,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\"></img>"},{"metadata":{},"cell_type":"markdown","source":"## GPT-2 Transformer\n\nHere we analyse the GPT-2 Transformer for our use case.\n\nThe pathway for self attention in GPT-2 is shown here:\n\n<img src=\"https://jalammar.github.io/images/gpt2/gpt2-self-attention-split-attention-heads-1.png\"></img>"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n# First load the real tokenizer- GPT-2\ntokenizer = transformers.GPT2Tokenizer.from_pretrained('gpt2-medium')\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\nfast_tokenizer = BertWordPieceTokenizer('vocab.txt', lowercase=False)\nfast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n#Tokenize the datasets\ntrain_x = fast_encode(train_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\nval_x = fast_encode(test_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values\nprint(train_x.shape)\nprint(train_y.shape)\nprint(val_x.shape)\nprint(val_y.shape)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 6.\n#Create Tensorflow Datasets\ntrain_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((train_x, train_y))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((val_x, val_y))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\nprint(train_dataset)\nprint(valid_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 7.\n#Build the transformer model\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFGPT2Model\n        .from_pretrained('gpt2-medium')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 8.\n#Train the model\n\nn_steps = train_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 9.\n#Validate the model\n\nn_steps = val_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Analyse the BART Transformer\n\nHere we will now  analyse the BART Transformer and check its performance with respect to other transformers.\nHowever BART from HuggingFace is not compatible with Tensorflow yet. We should use Pytorch as our framework for training BART.\n\nA preview is shown here:\n\n<img src=\"https://www.programmersought.com/images/833/4ff45b63f9b61a1cc178dc89f356f0c9.JPEG\"></img>\n\n\nBart uses pretrained encoders to evaluate against the current encodings and validates them before passing in to the transformer network."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n# First load the real tokenizer- BART\ntokenizer = transformers.BartTokenizer.from_pretrained('facebook/bart-base')\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\nfast_tokenizer = BertWordPieceTokenizer('vocab.txt', lowercase=False)\nfast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n#Tokenize the datasets\ntrain_x = fast_encode(train_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\nval_x = fast_encode(test_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values\nprint(train_x.shape)\nprint(train_y.shape)\nprint(val_x.shape)\nprint(val_y.shape)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 6.\n#Create Tensorflow Datasets\ntrain_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((train_x, train_y))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((val_x, val_y))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\nprint(train_dataset)\nprint(valid_dataset)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Bart (HuggingFace) is incompatible with Tensorflow (for now!)\n\nSo for this, we just need to plug in the Bart tokenizer with any pre-trained model, for instance Albert to form a composite architecture. This is sometimes refered to as an ensemble Transformer architecture."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 7.\n#Build the transformer model- Bart tokenizer + ALbert model\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFAlbertModel\n        .from_pretrained('albert-base-v1')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 8.\n#Train the model\n\nn_steps = train_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 9.\n#Validate the model\n\nn_steps = val_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## The Transformer XL Architecture\n\nThis is another transformer and should be analysed as well. All of the transformers covered are SOTA in their respective tasks and anyone can be used based on certain use cases.\n\nA good analysis between GPT/BERT/Transformer-XL is provided here:\n\n<img src=\"https://jalammar.github.io/images/gpt2/gpt-2-transformer-xl-bert-3.png\"></img>"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n# First load the real tokenizer- BART\ntokenizer = transformers.TransfoXLTokenizer.from_pretrained('transfo-xl-wt103')\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\nfast_tokenizer = BertWordPieceTokenizer('vocab.txt', lowercase=False)\nfast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 5.\n#Tokenize the datasets\ntrain_x = fast_encode(train_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\nval_x = fast_encode(test_set['question_text'].astype(str), fast_tokenizer, maxlen=MAX_LEN)\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values\nprint(train_x.shape)\nprint(train_y.shape)\nprint(val_x.shape)\nprint(val_y.shape)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 6.\n#Create Tensorflow Datasets\ntrain_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((train_x, train_y))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((val_x, val_y))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\nprint(train_dataset)\nprint(valid_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 7.\n#Build the transformer model- Bart tokenizer + ALbert model\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFTransfoXLModel\n        .from_pretrained('transfo-xl-wt103')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 8.\n#Train the model\n\nn_steps = train_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Step 9.\n#Validate the model\n\nn_steps = val_x.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=EPOCHS\n)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Conclusion for Transformers For Industrial Use case\n\nThis concludes the several SOTA Transformers for our usecase and this can also be used for any classification tasks as well.\nIn the next section, let us build a custom transformer to understand the architectures in depth along with the Attention mechanism\n\nThis image shows the variation of Transformer architectures for different NLP tasks from classification to question anwering:\n\n<img src=\"http://jalammar.github.io/images/openai-input%20transformations.png\"></img>\n\nPlease follow the excellent resources:\n\n1. [Transfer Learning in Transformers](http://jalammar.github.io/illustrated-bert/)\n2. [GPT-2 Enhanced Architecuture](http://jalammar.github.io/illustrated-gpt2/)\n3. [Current SOTA GPT-3](http://jalammar.github.io/how-gpt3-works-visualizations-animations/)\n"},{"metadata":{},"cell_type":"markdown","source":"# Creating a Custom Transformer\n\nThis section will help us in understanding the concepts required for creating a custom transformer.\nThe most important paper for this is present in the [link](https://paperswithcode.com/paper/attention-is-all-you-need) . It was written by Vaswani etal from Google research and is the paper which started the transformer journey.\n\n<img src=\"https://miro.medium.com/max/744/1*abz_nltyDYtC6ThqNg4O6w.png\"></img>\n\nTransformers alleviate the use of Convolution or Recurrent Networks by replacing them with attention mechanisms. This is because of the need for parallelization in training as well as to remove recurrence units. Seq2seq transduction models like the ones shown yesterday rely on something called as a Encoder-Decoder architecture. \n\nThe encoder architecture consists of stacked LSTM cells which control and give access to the memory for storing latent features. The decoder is responsible for extracting the outputs from the topmost stacked LSTM cell. While this is a good strategy over traditional models, it gets affected by catastrophic forgetting. \n\nSome excellent sources for understanding seq2seq encoder-decoder model are:\n\n1. [Jason's blog](https://machinelearningmastery.com/develop-encoder-decoder-model-sequence-sequence-prediction-keras/)\n2. [Francois Chollet's Code](https://github.com/keras-team/keras/blob/master/examples/lstm_seq2seq.py)\n\nFrom the encoder -decoder architecture arose the need for memory persistent attention units.\nThe first paper on attention was provided by Bahdanau for [Neural Machine Translation](https://paperswithcode.com/paper/neural-machine-translation-by-jointly).\n\n\nA comparative analysis between Bahdanau Attention and Luong Attention is provided here:\n\n<img src=\"https://miro.medium.com/max/1000/1*BfwFEH4tgY-JwHxr-2D2KQ.png\"></img>\n\nNeural Machine Translation is an entire different area of research which also uses Encoder decoder architectures coupled with attention mechanisms. A diagram of how this happens is provided below:\n\n<img src=\"http://jalammar.github.io/images/t/The_transformer_encoder_decoder_stack.png\"></img>"},{"metadata":{},"cell_type":"markdown","source":"## Encoder Decoder Architectures\n\nThese architectures are inherent in every transformer. Both of them are effectively similar deep learning models which are used to storing and abstracting data mainly consisting of LSTM units. The block diagram is provided:\n\n<img src=\"https://3qeqpr26caki16dnhd19sv6by6v-wpengine.netdna-ssl.com/wp-content/uploads/2017/10/Encoder-Decoder-Architecture-for-Neural-Machine-Translation.png\"></img>\n\n\nThere are different embeddings which are present in both of them (encoder and decoder). The input to the encoder layer is tokenized and then passed in to the positional embeddings layer. Then these are passed into the Deep Learning layers (mostly CNN/LSTM) . Then these are passed through the Attention module which performs tensor computations to assign more weights to certain words in the input (encoded) sentence. These are then passed in to the decoder unit.\n\nDuring indference, the decoder uses the mapping of the attention weights of certain important words to get the correct probabilities of the output words. Essentially the activation used in totality is the softmax as it has been employed across every embedding algorithm ,which relies on joint probability distribution of a word with respect to other words in the sentence."},{"metadata":{},"cell_type":"markdown","source":"## Self Attention in Depth\n\nSelf Attention relies on certain vectors q(query),k(key) and v(value). The vectors q and k are multiplied together and divided by 8(according to the papers) and then passed through a normalized softmax activation unit. This is donw so as to retain the memory of the weights when they are transferred from the encoder to the decoder layer. A series of images help us understand this:\n\n<img src=\"http://jalammar.github.io/images/t/transformer_self_attention_vectors.png\"></img>\n\nThis is how the operation is executed:\n\n<img src=\"http://jalammar.github.io/images/t/self-attention-output.png\"></img>\n\n\nThe entire Self Attention is done multiple times to get Multi-Head Attention which aids in parallel computing of the weights of the attention layers:\n\n<img src=\"http://jalammar.github.io/images/t/transformer_multi-headed_self-attention-recap.png\"></img>\n\nThis excellent resource from [Jalammar](http://jalammar.github.io/illustrated-transformer/) is highly recommended."},{"metadata":{},"cell_type":"markdown","source":"## Layer Normalization after Multi Headed Self Attention\n\nLayer normalization is an important measure to maintain the mean and variance of each layer. It has its similarities with batch normalization in normal neural networks, but with certain [changes](http://jalammar.github.io/images/t/transformer_resideual_layer_norm_3.png).\n\nThe entire Encoder architecture involving Layer Norm and Self Attention for Transformers is  represented here:\n\n<img src=\"http://jalammar.github.io/images/t/transformer_resideual_layer_norm_3.png\"></img>"},{"metadata":{},"cell_type":"markdown","source":"## Creating a Transformer With Keras\n\nA mini transformer with  multi headed attention mechanism from keras for our use cases.\n\nFor this we will be needing a masked Multi Head self attention.The effect of masking in Attention is provided in the image:\n\n<img src=\"http://jalammar.github.io/images/gpt2/self-attention-and-masked-self-attention.png\"></img>"},{"metadata":{},"cell_type":"markdown","source":"## Resources for Transformers\n\nSome of the resources which helped to create this:\n\n1. [Tensorflow Implementation-Google Brain](https://github.com/tensorflow/models/tree/master/official/nlp/transformer)\n2. [Excellent Resource](https://github.com/Lsdefine/attention-is-all-you-need-keras/blob/master/transformer.py)\n3. [Tensor2Tensor from Google](https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb)\n\nThese will be helpful for analysing with other resources provided."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Creating the inputs features\ntrain_df=pd.read_csv('../input/quora-insincere-questions-classification/train.csv')\ntest_df=pd.read_csv('../input/quora-insincere-questions-classification/test.csv')\ntrain_set,test_set=train_test_split(train_df,test_size=0.2,random_state=2017)\nprint(train_set.shape)\nprint(test_set.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Codes from day-1\nmaxlen=1000\nmax_features=5000 \nembed_size=300\n\n#clean some null words or use the previously cleaned & lemmatized corpus\n\ntrain_x=train_set['question_text'].fillna('_na_').values\nval_x=test_set['question_text'].fillna('_na_').values\n\n#Tokenizing steps- must be remembered\ntokenizer=Tokenizer(num_words=max_features)\ntokenizer.fit_on_texts(list(train_x))\ntrain_x=tokenizer.texts_to_sequences(train_x)\nval_x=tokenizer.texts_to_sequences(val_x)\n\n#Pad the sequence- To allow same length for all vectorized words\ntrain_x=pad_sequences(train_x,maxlen=maxlen)\nval_x=pad_sequences(val_x,maxlen=maxlen)\n\n\n#get the target values - either using values or using Label Encoder\ntrain_y=train_set['target'].values\nval_y=test_set['target'].values\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Codes from Day-1\nEMBEDDING_FILE = '../input/embeddings/glove.840B.300d/glove.840B.300d.txt'\ndef get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')\nembeddings_index = dict(get_coefs(*o.split(\" \")) for o in open(EMBEDDING_FILE))\n\nall_embs = np.stack(embeddings_index.values())\nemb_mean,emb_std = all_embs.mean(), all_embs.std()\nembed_size = all_embs.shape[1]\n\nword_index = tokenizer.word_index\nnb_words = min(max_features, len(word_index))\nembedding_matrix = np.random.normal(emb_mean, emb_std, (nb_words, embed_size))\nfor word, i in word_index.items():\n    if i >= max_features: continue\n    embedding_vector = embeddings_index.get(word)\n    if embedding_vector is not None: embedding_matrix[i] = embedding_vector\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Building the actual Model\n\nIn this case, here are the following parts of the model:\n\n1. Add a Layer Normalization Layer\n2. Create a function/class for Self Attention\n3. Join different Self Attention objects together to get Multi Head Attention\n4. "},{"metadata":{"trusted":true},"cell_type":"code","source":"import random, os, sys\nimport numpy as np\nfrom keras.models import *\nfrom keras.layers import *\nfrom keras.callbacks import *\nfrom keras.initializers import *\nimport tensorflow as tf\nfrom keras.engine.topology import Layer\n\ntry:\n    from dataloader import TokenList, pad_to_longest\n    # for transformer\nexcept: pass\n\n#Layer normalization class\nclass LayerNormalization(Layer):\n    def __init__(self, eps=1e-6, **kwargs):\n        self.eps = eps\n        super(LayerNormalization, self).__init__(**kwargs)\n    def build(self, input_shape):\n        #Adding custom weights\n        self.gamma = self.add_weight(name='gamma', shape=input_shape[-1:],\n                                     initializer=Ones(), trainable=True)\n        self.beta = self.add_weight(name='beta', shape=input_shape[-1:],\n                                    initializer=Zeros(), trainable=True)\n        super(LayerNormalization, self).build(input_shape)\n    def call(self, x):\n        mean = K.mean(x, axis=-1, keepdims=True)\n        std = K.std(x, axis=-1, keepdims=True)\n        return self.gamma * (x - mean) / (std + self.eps) + self.beta\n    def compute_output_shape(self, input_shape):\n        return input_shape\n\n#Division by 8 (q.k/d^0.5)\nclass ScaledDotProductAttention():\n    def __init__(self, d_model, attn_dropout=0.1):\n        self.temper = np.sqrt(d_model)\n        self.dropout = Dropout(attn_dropout)\n    def __call__(self, q, k, v, mask):\n        attn = Lambda(lambda x:K.batch_dot(x[0],x[1],axes=[2,2])/self.temper)([q, k])\n        if mask is not None:\n            mmask = Lambda(lambda x:(-1e+10)*(1-x))(mask)\n            attn = Add()([attn, mmask])\n        attn = Activation('softmax')(attn)\n        attn = self.dropout(attn)\n        output = Lambda(lambda x:K.batch_dot(x[0], x[1]))([attn, v])\n        return output, attn\n\nclass MultiHeadAttention():\n    # mode 0 - big martixes, faster; mode 1 - more clear implementation\n    def __init__(self, n_head, d_model, d_k, d_v, dropout, mode=0, use_norm=True):\n        self.mode = mode\n        self.n_head = n_head\n        self.d_k = d_k\n        self.d_v = d_v\n        self.dropout = dropout\n        if mode == 0:\n            self.qs_layer = Dense(n_head*d_k, use_bias=False)\n            self.ks_layer = Dense(n_head*d_k, use_bias=False)\n            self.vs_layer = Dense(n_head*d_v, use_bias=False)\n        elif mode == 1:\n            self.qs_layers = []\n            self.ks_layers = []\n            self.vs_layers = []\n            for _ in range(n_head):\n                self.qs_layers.append(TimeDistributed(Dense(d_k, use_bias=False)))\n                self.ks_layers.append(TimeDistributed(Dense(d_k, use_bias=False)))\n                self.vs_layers.append(TimeDistributed(Dense(d_v, use_bias=False)))\n        #Joining scaled dot product\n        self.attention = ScaledDotProductAttention(d_model)\n        self.layer_norm = LayerNormalization() if use_norm else None\n        self.w_o = TimeDistributed(Dense(d_model))\n\n    def __call__(self, q, k, v, mask=None):\n        d_k, d_v = self.d_k, self.d_v\n        n_head = self.n_head\n\n        if self.mode == 0:\n            qs = self.qs_layer(q)  # [batch_size, len_q, n_head*d_k]\n            ks = self.ks_layer(k)\n            vs = self.vs_layer(v)\n\n            def reshape1(x):\n                s = tf.shape(x)   # [batch_size, len_q, n_head * d_k]\n                x = tf.reshape(x, [s[0], s[1], n_head, d_k])\n                x = tf.transpose(x, [2, 0, 1, 3])  \n                x = tf.reshape(x, [-1, s[1], d_k])  # [n_head * batch_size, len_q, d_k]\n                return x\n            qs = Lambda(reshape1)(qs)\n            ks = Lambda(reshape1)(ks)\n            vs = Lambda(reshape1)(vs)\n\n            if mask is not None:\n                mask = Lambda(lambda x:K.repeat_elements(x, n_head, 0))(mask)\n            head, attn = self.attention(qs, ks, vs, mask=mask)  \n                \n            def reshape2(x):\n                s = tf.shape(x)   # [n_head * batch_size, len_v, d_v]\n                x = tf.reshape(x, [n_head, -1, s[1], s[2]]) \n                x = tf.transpose(x, [1, 2, 0, 3])\n                x = tf.reshape(x, [-1, s[1], n_head*d_v])  # [batch_size, len_v, n_head * d_v]\n                return x\n            head = Lambda(reshape2)(head)\n        elif self.mode == 1:\n            heads = []; attns = []\n            for i in range(n_head):\n                qs = self.qs_layers[i](q)   \n                ks = self.ks_layers[i](k) \n                vs = self.vs_layers[i](v) \n                head, attn = self.attention(qs, ks, vs, mask)\n                heads.append(head); attns.append(attn)\n            head = Concatenate()(heads) if n_head > 1 else heads[0]\n            attn = Concatenate()(attns) if n_head > 1 else attns[0]\n\n        outputs = self.w_o(head)\n        outputs = Dropout(self.dropout)(outputs)\n        if not self.layer_norm: return outputs, attn\n        outputs = Add()([outputs, q])\n        return self.layer_norm(outputs), attn\n#Feedforward layer using COnv1D and Layer normalization.\nclass PositionwiseFeedForward():\n    def __init__(self, d_hid, d_inner_hid, dropout=0.1):\n        self.w_1 = Conv1D(d_inner_hid, 1, activation='relu')\n        self.w_2 = Conv1D(d_hid, 1)\n        self.layer_norm = LayerNormalization()\n        self.dropout = Dropout(dropout)\n    def __call__(self, x):\n        output = self.w_1(x) \n        output = self.w_2(output)\n        output = self.dropout(output)\n        output = Add()([output, x])\n        return self.layer_norm(output)\n#Encoder layer containing self/multi head attention with positionwisefeedforward\nclass EncoderLayer():\n    def __init__(self, d_model, d_inner_hid, n_head, d_k, d_v, dropout=0.1):\n        self.self_att_layer = MultiHeadAttention(n_head, d_model, d_k, d_v, dropout=dropout)\n        self.pos_ffn_layer  = PositionwiseFeedForward(d_model, d_inner_hid, dropout=dropout)\n    def __call__(self, enc_input, mask=None):\n        output, slf_attn = self.self_att_layer(enc_input, enc_input, enc_input, mask=mask)\n        output = self.pos_ffn_layer(output)\n        return output, slf_attn\n#Decoder layer with same architecture as the encoder.\nclass DecoderLayer():\n    def __init__(self, d_model, d_inner_hid, n_head, d_k, d_v, dropout=0.1):\n        self.self_att_layer = MultiHeadAttention(n_head, d_model, d_k, d_v, dropout=dropout)\n        self.enc_att_layer  = MultiHeadAttention(n_head, d_model, d_k, d_v, dropout=dropout)\n        self.pos_ffn_layer  = PositionwiseFeedForward(d_model, d_inner_hid, dropout=dropout)\n    def __call__(self, dec_input, enc_output, self_mask=None, enc_mask=None):\n        output, slf_attn = self.self_att_layer(dec_input, dec_input, dec_input, mask=self_mask)\n        output, enc_attn = self.enc_att_layer(output, enc_output, enc_output, mask=enc_mask)\n        output = self.pos_ffn_layer(output)\n        return output, slf_attn, enc_attn\n#This is from the paper \"Attention is all you need\" which hypothesizes sin and cosine for positional encoding\ndef GetPosEncodingMatrix(max_len, d_emb):\n    pos_enc = np.array([\n        [pos / np.power(10000, 2 * (j // 2) / d_emb) for j in range(d_emb)] \n        if pos != 0 else np.zeros(d_emb) \n            for pos in range(max_len)\n            ])\n    pos_enc[1:, 0::2] = np.sin(pos_enc[1:, 0::2]) # dim 2i\n    pos_enc[1:, 1::2] = np.cos(pos_enc[1:, 1::2]) # dim 2i+1\n    return pos_enc\n\n#normal padding class for masking\ndef GetPadMask(q, k):\n    ones = K.expand_dims(K.ones_like(q, 'float32'), -1)\n    mask = K.cast(K.expand_dims(K.not_equal(k, 0), 1), 'float32')\n    mask = K.batch_dot(ones, mask, axes=[2,1])\n    return mask\n\ndef GetSubMask(s):\n    len_s = tf.shape(s)[1]\n    bs = tf.shape(s)[:1]\n    mask = K.cumsum(tf.eye(len_s, batch_shape=bs), 1)\n    return mask\n\nclass Encoder():\n    def __init__(self, d_model, d_inner_hid, n_head, d_k, d_v, \\\n                layers=6, dropout=0.1, word_emb=None, pos_emb=None):\n        self.emb_layer = word_emb\n        self.pos_layer = pos_emb\n        self.emb_dropout = Dropout(dropout)\n        self.layers = [EncoderLayer(d_model, d_inner_hid, n_head, d_k, d_v, dropout) for _ in range(layers)]\n        \n    def __call__(self, src_seq, src_pos, return_att=False, active_layers=999):\n        x = self.emb_layer(src_seq)\n        if src_pos is not None:\n            pos = self.pos_layer(src_pos)\n            x = Add()([x, pos])\n        x = self.emb_dropout(x)\n        if return_att: atts = []\n        mask = Lambda(lambda x:GetPadMask(x, x))(src_seq)\n        for enc_layer in self.layers[:active_layers]:\n            x, att = enc_layer(x, mask)\n            if return_att: atts.append(att)\n        return (x, atts) if return_att else x\n\n\nclass Transformer():\n    def __init__(self, len_limit, d_model=embed_size, \\\n              d_inner_hid=512, n_head=10, d_k=64, d_v=64, layers=2, dropout=0.1, \\\n              share_word_emb=False, **kwargs):\n        self.name = 'Transformer'\n        self.len_limit = len_limit\n        self.src_loc_info = True\n        self.d_model = d_model\n        self.decode_model = None\n        d_emb = d_model\n\n        pos_emb = Embedding(len_limit, d_emb, trainable=False, \\\n                            weights=[GetPosEncodingMatrix(len_limit, d_emb)])\n\n        i_word_emb = Embedding(max_features, d_emb, weights=[embedding_matrix]) # Add Kaggle provided embedding here\n\n        self.encoder = Encoder(d_model, d_inner_hid, n_head, d_k, d_v, layers, dropout, \\\n                               word_emb=i_word_emb, pos_emb=pos_emb)\n\n        \n    def get_pos_seq(self, x):\n        mask = K.cast(K.not_equal(x, 0), 'int32')\n        pos = K.cumsum(K.ones_like(x, 'int32'), 1)\n        return pos * mask\n\n    def compile(self, active_layers=999):\n        src_seq_input = Input(shape=(None,))\n        src_seq = src_seq_input\n        src_pos = Lambda(self.get_pos_seq)(src_seq)\n        if not self.src_loc_info: src_pos = None\n\n        x = self.encoder(src_seq, src_pos, active_layers=active_layers)\n        # x = GlobalMaxPool1D()(x) # Not sure about this layer. Just wanted to reduce dimension\n        x = GlobalAveragePooling1D()(x)\n        outp = Dense(1, activation=\"sigmoid\")(x)\n\n        self.model = Model(inputs=src_seq_input, outputs=outp)\n        self.model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"seq2seq = Transformer(maxlen, layers=1)\nseq2seq.compile()\nmodel = seq2seq.model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Evaluate and Train the Model\n\nmodel.fit(train_x, train_y, batch_size=1024, epochs=1, validation_data=(val_x, val_y))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Some important resources from Github\n\nHere are some important resources which will definitely help.\n\n1. [BERT:Google Research](https://github.com/google-research/bert)\n2. [Dale's notebook](https://github.com/google-research/bert/blob/master/predicting_movie_reviews_with_bert_on_tf_hub.ipynb)\n3. [Albert](https://github.com/google-research/albert)\n4. [GPT-2](https://github.com/openai/gpt-2)\n5. [Roberta](https://github.com/pytorch/fairseq/tree/master/examples/roberta)\n6. [Bart](https://github.com/pytorch/fairseq/tree/master/examples/bart)\n7. [Transformer-XL](https://github.com/kimiyoung/transformer-xl)\n8. [Hugging Face Transformers](https://github.com/huggingface/transformers)\n\n\nThese resources should help. Apart from this, for more details on attention mechanism (for now only Hierarchical) you can refer to [my repo](https://github.com/abhilash1910/MiniAttention). I will be adding more custom attention modules which can be used any sequential network, including a separate transformer architecture. "},{"metadata":{},"cell_type":"markdown","source":"## Graph Learning\n\nThere is another paradigm in NLP which relies on Deep Learning in Graphs, which is beyond today's session. Just as an overview, all the architectures/models which we have built are also applicable for knowledge graphs. These are essentially in huge corpuses of data such as Google search, where scalable transformer architectures are employed on graphs. All social media (twitter,facebook etc) rely on extensive large scale graph transformer networks for classification, question answering, semantic indexing, reference resolution, masking and generative modelling."},{"metadata":{},"cell_type":"markdown","source":"# Conclusion\n\nThis completes today's session and the entire workshop in totality.\nWould appreciate feedbacks as well as follow-ups. Follow me on [github](https://github.com/abhilash1910) for any updates on deep learning or NLP!"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}