{"cells":[{"metadata":{"id":"svDDvMhYgxwM","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":35},"outputId":"95a9914f-ce8e-46f6-e9fb-46d2671cb78f","trusted":true,"_uuid":"1642a59f5e4d475a1757b74cf74fc4f48f5cecc3"},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom keras.preprocessing.text import Tokenizer,  text_to_word_sequence\nfrom keras.engine.topology import Layer\nfrom keras import initializers as initializers, regularizers, constraints\nfrom keras.callbacks import Callback, ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\nfrom keras.utils.np_utils import to_categorical\nfrom keras.preprocessing.sequence import pad_sequences\nfrom keras.optimizers import Adam\nfrom keras.layers import Embedding, Input, Dense, LSTM, GRU, Bidirectional, TimeDistributed, Dropout, CuDNNLSTM, SpatialDropout1D, BatchNormalization, Lambda, Average, Concatenate, ReLU, Add\nfrom keras import backend as K\nfrom keras import optimizers\nfrom keras.models import Model\nimport nltk\nimport re\nimport matplotlib.pyplot as plt\nimport sys\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn import metrics\nfrom nltk import tokenize,word_tokenize\nimport seaborn as sns\nfrom tqdm import tqdm\nimport gc\ntqdm.pandas()\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"id":"u01IFY1Hgxwf","colab_type":"text","_uuid":"4440f99cbe40c318bd13ee6ecbbe1a3cb162fa40"},"cell_type":"markdown","source":"### Attention Layer"},{"metadata":{"id":"XbOJEMv7gxwi","colab_type":"code","colab":{},"trusted":true,"_uuid":"668e772f91421e5a8e87c3f97429c04d1d372f0d"},"cell_type":"code","source":"def dot_product(x, kernel):\n    \"\"\"\n    Wrapper for dot product operation, in order to be compatibl|e with both\n    Theano and Tensorflow\n    Args:\n        x (): input\n        kernel (): weights\n    Returns:\n    \"\"\"\n    if K.backend() == 'tensorflow':\n        return K.squeeze(K.dot(x, K.expand_dims(kernel)), axis=-1)\n    else:\n        return K.dot(x, kernel)\n\nclass AttentionWithContext(Layer):\n    \"\"\"\n    Attention operation, with a context/query vector, for temporal data.\n    Supports Masking.\n    Follows the work of Yang et al. [https://www.cs.cmu.edu/~diyiy/docs/naacl16.pdf]\n    \"Hierarchical Attention Networks for Document Classification\"\n    by using a context vector to assist the attention\n    # Input shape\n        3D tensor with shape: `(samples, steps, features)`.\n    # Output shape\n        2D tensor with shape: `(samples, features)`.\n    How to use:\n    Just put it on top of an RNN Layer (GRU/LSTM/SimpleRNN) with return_sequences=True.\n    The dimensions are inferred based on the output shape of the RNN.\n    Note: The layer has been tested with Keras 2.0.6\n    Example:\n        model.add(LSTM(64, return_sequences=True))\n        model.add(AttentionWithContext())\n        # next add a Dense layer (for classification/regression) or whatever...\n    \"\"\"\n\n    def __init__(self,\n                 W_regularizer=None, u_regularizer=None, b_regularizer=None,\n                 W_constraint=None, u_constraint=None, b_constraint=None,\n                 bias=True, **kwargs):\n\n        self.supports_masking = True\n        self.init = initializers.get('glorot_uniform')\n\n        self.W_regularizer = regularizers.get(W_regularizer)\n        self.u_regularizer = regularizers.get(u_regularizer)\n        self.b_regularizer = regularizers.get(b_regularizer)\n\n        self.W_constraint = constraints.get(W_constraint)\n        self.u_constraint = constraints.get(u_constraint)\n        self.b_constraint = constraints.get(b_constraint)\n\n        self.bias = bias\n        super(AttentionWithContext, self).__init__(**kwargs)\n\n    def build(self, input_shape):\n        assert len(input_shape) == 3\n\n        self.W = self.add_weight((input_shape[-1], input_shape[-1],),\n                                 initializer=self.init,\n                                 name='{}_W'.format(self.name),\n                                 regularizer=self.W_regularizer,\n                                 constraint=self.W_constraint)\n        if self.bias:\n            self.b = self.add_weight((input_shape[-1],),\n                                     initializer='zero',\n                                     name='{}_b'.format(self.name),\n                                     regularizer=self.b_regularizer,\n                                     constraint=self.b_constraint)\n\n        self.u = self.add_weight((input_shape[-1],),\n                                 initializer=self.init,\n                                 name='{}_u'.format(self.name),\n                                 regularizer=self.u_regularizer,\n                                 constraint=self.u_constraint)\n\n        super(AttentionWithContext, self).build(input_shape)\n\n    def compute_mask(self, input, input_mask=None):\n        # do not pass the mask to the next layers\n        return None\n\n    def call(self, x, mask=None):\n        uit = dot_product(x, self.W)\n\n        if self.bias:\n            uit += self.b\n\n        uit = K.tanh(uit)\n        ait = dot_product(uit, self.u)\n\n        a = K.exp(ait)\n\n        # apply mask after the exp. will be re-normalized next\n        if mask is not None:\n            # Cast the mask to floatX to avoid float64 upcasting in theano\n            a *= K.cast(mask, K.floatx())\n\n        # in some cases especially in the early stages of training the sum may be almost zero\n        # and this results in NaN's. A workaround is to add a very small positive number ε to the sum.\n        # a /= K.cast(K.sum(a, axis=1, keepdims=True), K.floatx())\n        a /= K.cast(K.sum(a, axis=1, keepdims=True) + K.epsilon(), K.floatx())\n\n        a = K.expand_dims(a)\n        weighted_input = x * a\n        return K.sum(weighted_input, axis=1)\n\n    def compute_output_shape(self, input_shape):\n        return input_shape[0], input_shape[-1]","execution_count":null,"outputs":[]},{"metadata":{"id":"rWL4urlHgxwu","colab_type":"text","_uuid":"de867e70a1b042a2ac5a31a8fdcb0dbc2ddc13f9"},"cell_type":"markdown","source":"### Config"},{"metadata":{"id":"wvVCtTJbgxwx","colab_type":"code","colab":{},"trusted":true,"_uuid":"8e970050b9852e54e964961fe0110226348860c1"},"cell_type":"code","source":"max_features= 200000\nmax_senten_len = 40\nmax_senten_num = 3\nembed_size = 300\nVALIDATION_SPLIT = 0","execution_count":null,"outputs":[]},{"metadata":{"id":"iphJED4Qgxw8","colab_type":"text","_uuid":"da31e0150178690c03f71da4f77c1883a4639cb3"},"cell_type":"markdown","source":"### Data"},{"metadata":{"id":"SISE6xEnrKx_","colab_type":"code","colab":{},"trusted":true,"_uuid":"66b5c24a07ba29ee90cb163703dcf9433249000a"},"cell_type":"code","source":"from sklearn.utils import shuffle","execution_count":null,"outputs":[]},{"metadata":{"id":"83stXVBjgxw-","colab_type":"code","colab":{},"trusted":true,"_uuid":"1dfa79cd274172897f8f5a90594e7cbe1d30fc30"},"cell_type":"code","source":"df = pd.read_csv('../input/train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c144abd805dcfa0f3120c31a739465f769c972d3"},"cell_type":"code","source":"test_df = pd.read_csv(\"../input/test.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"60f0ecb944a3504916ad2f2b802858f35d5a4dee"},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"id":"yn2rJmMsfPOO","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":35},"outputId":"e8cc4a75-083a-4099-a16b-a4e9c414fb93","trusted":true,"_uuid":"bf9f1ccf81d0e91bc2722f119677314301a73af3"},"cell_type":"code","source":"len(df.target.unique())","execution_count":null,"outputs":[]},{"metadata":{"id":"mkBa2gzGq5MD","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":588},"outputId":"343f8c37-4ce1-4821-f42b-aee7c944d6b3","trusted":true,"_uuid":"4e2ea661300670641050fd8870ce3cea821f1a2d"},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"id":"cEhKU6wPq5HZ","colab_type":"code","colab":{},"trusted":true,"_uuid":"923adeea51ed5a9a2598f456f27a5aa596eb78bd"},"cell_type":"code","source":"df.columns = ['qid', 'text', 'category']\ntest_df.columns = ['qid', 'text']","execution_count":null,"outputs":[]},{"metadata":{"id":"7Q5PnT6M44If","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":626},"outputId":"994f280b-bc40-4f3a-b288-1b5a922c72cd","trusted":true,"_uuid":"a5fea8907a2d824ba0becf68142efe9ab6c56da6"},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"id":"QTbOuQw7gxxH","colab_type":"code","colab":{},"trusted":true,"_uuid":"120aa99478cccb4022937e6b6d3abd92c74f5bb3"},"cell_type":"code","source":"df = df[['text', 'category']]","execution_count":null,"outputs":[]},{"metadata":{"id":"JVUm8F55gxxP","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":142},"outputId":"b6dca62a-738e-448b-a935-f9dafef95ad7","trusted":true,"_uuid":"36ad12bc4f9634905d660c932d6eb93ec3d1df68"},"cell_type":"code","source":"df.info()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7bc0de8192893bd0e125562128e27f8c13699324"},"cell_type":"markdown","source":"## Preprocessing"},{"metadata":{"trusted":true,"_uuid":"8ad88c06ad9c6b8a67f4971a5d8f63d70c9d5697"},"cell_type":"code","source":"df['text'] = df['text'].str.lower()\ntest_df['text'] = test_df['text'].str.lower()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"29b7c9e16baba707786d2f33cf32aad268cc2c0b"},"cell_type":"code","source":"contraction_mapping = {\"ain't\": \"is not\", \"aren't\": \"are not\",\"can't\": \"cannot\", \"'cause\": \"because\", \"could've\": \"could have\", \"couldn't\": \"could not\", \"didn't\": \"did not\",  \"doesn't\": \"does not\", \"don't\": \"do not\", \"hadn't\": \"had not\", \"hasn't\": \"has not\", \"haven't\": \"have not\", \"he'd\": \"he would\",\"he'll\": \"he will\", \"he's\": \"he is\", \"how'd\": \"how did\", \"how'd'y\": \"how do you\", \"how'll\": \"how will\", \"how's\": \"how is\",  \"I'd\": \"I would\", \"I'd've\": \"I would have\", \"I'll\": \"I will\", \"I'll've\": \"I will have\",\"I'm\": \"I am\", \"I've\": \"I have\", \"i'd\": \"i would\", \"i'd've\": \"i would have\", \"i'll\": \"i will\",  \"i'll've\": \"i will have\",\"i'm\": \"i am\", \"i've\": \"i have\", \"isn't\": \"is not\", \"it'd\": \"it would\", \"it'd've\": \"it would have\", \"it'll\": \"it will\", \"it'll've\": \"it will have\",\"it's\": \"it is\", \"let's\": \"let us\", \"ma'am\": \"madam\", \"mayn't\": \"may not\", \"might've\": \"might have\",\"mightn't\": \"might not\",\"mightn't've\": \"might not have\", \"must've\": \"must have\", \"mustn't\": \"must not\", \"mustn't've\": \"must not have\", \"needn't\": \"need not\", \"needn't've\": \"need not have\",\"o'clock\": \"of the clock\", \"oughtn't\": \"ought not\", \"oughtn't've\": \"ought not have\", \"shan't\": \"shall not\", \"sha'n't\": \"shall not\", \"shan't've\": \"shall not have\", \"she'd\": \"she would\", \"she'd've\": \"she would have\", \"she'll\": \"she will\", \"she'll've\": \"she will have\", \"she's\": \"she is\", \"should've\": \"should have\", \"shouldn't\": \"should not\", \"shouldn't've\": \"should not have\", \"so've\": \"so have\",\"so's\": \"so as\", \"this's\": \"this is\",\"that'd\": \"that would\", \"that'd've\": \"that would have\", \"that's\": \"that is\", \"there'd\": \"there would\", \"there'd've\": \"there would have\", \"there's\": \"there is\", \"here's\": \"here is\",\"they'd\": \"they would\", \"they'd've\": \"they would have\", \"they'll\": \"they will\", \"they'll've\": \"they will have\", \"they're\": \"they are\", \"they've\": \"they have\", \"to've\": \"to have\", \"wasn't\": \"was not\", \"we'd\": \"we would\", \"we'd've\": \"we would have\", \"we'll\": \"we will\", \"we'll've\": \"we will have\", \"we're\": \"we are\", \"we've\": \"we have\", \"weren't\": \"were not\", \"what'll\": \"what will\", \"what'll've\": \"what will have\", \"what're\": \"what are\",  \"what's\": \"what is\", \"what've\": \"what have\", \"when's\": \"when is\", \"when've\": \"when have\", \"where'd\": \"where did\", \"where's\": \"where is\", \"where've\": \"where have\", \"who'll\": \"who will\", \"who'll've\": \"who will have\", \"who's\": \"who is\", \"who've\": \"who have\", \"why's\": \"why is\", \"why've\": \"why have\", \"will've\": \"will have\", \"won't\": \"will not\", \"won't've\": \"will not have\", \"would've\": \"would have\", \"wouldn't\": \"would not\", \"wouldn't've\": \"would not have\", \"y'all\": \"you all\", \"y'all'd\": \"you all would\",\"y'all'd've\": \"you all would have\",\"y'all're\": \"you all are\",\"y'all've\": \"you all have\",\"you'd\": \"you would\", \"you'd've\": \"you would have\", \"you'll\": \"you will\", \"you'll've\": \"you will have\", \"you're\": \"you are\", \"you've\": \"you have\", 'u.s':'america', 'e.g':'for example'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"588facdf9e1cc7a5cabf4c4964c5572c0713484a"},"cell_type":"code","source":"def clean_contractions(text, mapping):\n    specials = [\"’\", \"‘\", \"´\", \"`\"]\n    for s in specials:\n        text = text.replace(s, \"'\")\n    text = ' '.join([mapping[t] if t in mapping else t for t in text.split(\" \")])\n    return text","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ab08938d0c9123331c6be94a5513763856a39cb6"},"cell_type":"code","source":"df['text'] = df['text'].progress_apply(lambda x: clean_contractions(x, contraction_mapping))\ntest_df['text'] = test_df['text'].progress_apply(lambda x: clean_contractions(x, contraction_mapping))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1494d4e502b0fde26012cdd77e1474e9dcee3723"},"cell_type":"code","source":"punct = [',', '.', '\"', ':', ')', '(', '-', '!', '?', '|', ';', \"'\", '$', '&', '/', '[', ']', '>', '%', '=', '#', '*', '+', '\\\\', '•',  '~', '@', '£', \n '·', '_', '{', '}', '©', '^', '®', '`',  '<', '→', '°', '€', '™', '›',  '♥', '←', '×', '§', '″', '′', 'Â', '█', '½', 'à', '…', \n '“', '★', '”', '–', '●', 'â', '►', '−', '¢', '²', '¬', '░', '¶', '↑', '±', '¿', '▾', '═', '¦', '║', '―', '¥', '▓', '—', '‹', '─', \n '▒', '：', '¼', '⊕', '▼', '▪', '†', '■', '’', '▀', '¨', '▄', '♫', '☆', 'é', '¯', '♦', '¤', '▲', 'è', '¸', '¾', 'Ã', '⋅', '‘', '∞', \n '∙', '）', '↓', '、', '│', '（', '»', '，', '♪', '╩', '╚', '³', '・', '╦', '╣', '╔', '╗', '▬', '❤', 'ï', 'Ø', '¹', '≤', '‡', '√', ]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cc60c96d084d18d0360091e18631cfaa03138966"},"cell_type":"code","source":"punct_mapping = {\"‘\": \"'\", \"₹\": \"e\", \"´\": \"'\", \"°\": \"\", \"€\": \"e\", \"™\": \"tm\", \"√\": \" sqrt \", \"×\": \"x\", \"²\": \"2\", \"—\": \"-\", \"–\": \"-\", \"’\": \"'\", \"_\": \"-\", \"`\": \"'\", '“': '\"', '”': '\"', '“': '\"', \"£\": \"e\", '∞': 'infinity', 'θ': 'theta', '÷': '/', 'α': 'alpha', '•': '.', 'à': 'a', '−': '-', 'β': 'beta', '∅': '', '³': '3', 'π': 'pi', '!':' '}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4039d4fb243963d6834dfb4db67cb8fc5910bfce"},"cell_type":"code","source":"def clean_special_chars(text, punct, mapping):\n    for p in mapping:\n        text = text.replace(p, mapping[p])\n    \n    for p in punct:\n        text = text.replace(p, f' {p} ')\n    \n    specials = {'\\u200b': ' ', '…': ' ... ', '\\ufeff': '', 'करना': '', 'है': ''}  # Other special characters that I have to deal with in last\n    for s in specials:\n        text = text.replace(s, specials[s])\n    \n    return text","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"af1f7dbc784b5f7dc2f404c2aca4466e44b3a28d"},"cell_type":"code","source":"df['text'] = df['text'].progress_apply(lambda x: clean_special_chars(x, punct, punct_mapping))\ntest_df['text'] = test_df['text'].progress_apply(lambda x: clean_special_chars(x, punct, punct_mapping))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3751626328ec4182079a73610cbdae65b629d8bc"},"cell_type":"code","source":"mispell_dict = {'colour': 'color', 'centre': 'center', 'favourite': 'favorite', 'travelling': 'traveling', 'counselling': 'counseling', 'theatre': 'theater', 'cancelled': 'canceled', 'labour': 'labor', 'organisation': 'organization', 'wwii': 'world war 2', 'citicise': 'criticize', 'youtu ': 'youtube ', 'Qoura': 'Quora', 'sallary': 'salary', 'Whta': 'What', 'narcisist': 'narcissist', 'howdo': 'how do', 'whatare': 'what are', 'howcan': 'how can', 'howmuch': 'how much', 'howmany': 'how many', 'whydo': 'why do', 'doI': 'do I', 'theBest': 'the best', 'howdoes': 'how does', 'mastrubation': 'masturbation', 'mastrubate': 'masturbate', \"mastrubating\": 'masturbating', 'pennis': 'penis', 'Etherium': 'Ethereum', 'narcissit': 'narcissist', 'bigdata': 'big data', '2k17': '2017', '2k18': '2018', 'qouta': 'quota', 'exboyfriend': 'ex boyfriend', 'airhostess': 'air hostess', \"whst\": 'what', 'watsapp': 'whatsapp', 'demonitisation': 'demonetization', 'demonitization': 'demonetization', 'demonetisation': 'demonetization'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dcd52e9658a9c38b569abc33b6915dfb2e0be61b"},"cell_type":"code","source":"def correct_spelling(x, dic):\n    for word in dic.keys():\n        x = x.replace(word, dic[word])\n    return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bbf6e8c271f3192ce6196e2261eb7731f2a045d2"},"cell_type":"code","source":"df['text'] = df['text'].progress_apply(lambda x: correct_spelling(x, mispell_dict))\ntest_df['text'] = test_df['text'].progress_apply(lambda x: correct_spelling(x, mispell_dict))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"648d67245cec720dee3ddc32189ea83ea5bf5d80"},"cell_type":"code","source":"labels = df['category']\ntext = df['text']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"83194acdaae61f8cba5efc4b006f10a20f7ef1b5"},"cell_type":"code","source":"\"\"\"\nindices = np.arange(text.shape[0])\nnp.random.shuffle(indices)\ntext = text[indices]\nlabels = labels.iloc[indices]\nnb_validation_samples = int(VALIDATION_SPLIT * df.shape[0])\n\ntrain_text = text[:-nb_validation_samples].reset_index().drop('index', axis=1)\ny_train = labels[:-nb_validation_samples].reset_index().drop('index', axis=1)\nval_text = text[-nb_validation_samples:].reset_index().drop('index', axis=1)\ny_val = labels[-nb_validation_samples:].reset_index().drop('index', axis=1)\n\"\"\"\ntrain_text =  text.reset_index().drop('index', axis=1)\ny_train = labels.reset_index().drop('index', axis=1)\nval_text = None\ny_val = None","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"291adb991ec85f2507dc8b38d38e208cd0ee0954"},"cell_type":"code","source":"test = test_df['text']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"075915765f8f8ca4ba91691b8d220d1017b64fc5"},"cell_type":"code","source":"cates = df.groupby('category')\nprint(\"total categories:\", cates.ngroups)\nprint(cates.size())","execution_count":null,"outputs":[]},{"metadata":{"id":"YJOFyzjf5fe0","colab_type":"code","colab":{},"trusted":true,"_uuid":"86e266a58a5e847021fc6cebd4fc30991d02bdf9"},"cell_type":"code","source":"paras = []\nlabels = []\ntexts = []","execution_count":null,"outputs":[]},{"metadata":{"id":"FxeewB4Jgxx3","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":53},"outputId":"909116f6-d7a0-4383-91cb-f6de9d3171ed","trusted":true,"_uuid":"4b8f64afbf8acc01a08f6f4ec577053908c7cc7d"},"cell_type":"code","source":"sent_lens = []\nsent_nums = []\nfor idx in tqdm(range(train_text.shape[0])):\n    text = train_text.text[idx]\n    texts.append(text)\n    sentences = tokenize.sent_tokenize(text)\n    sent_nums.append(len(sentences))\n    for sent in sentences:\n        sent_lens.append(len(text_to_word_sequence(sent)))\n    paras.append(sentences)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"88a937072dee076c6e7fd94446ddc47ebfdaae6d"},"cell_type":"code","source":"f, ax = plt.subplots(figsize=(12, 6))\nsns.distplot(sent_lens, ax=ax)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b54d956321b4f6598315566ca45ee661863700dc"},"cell_type":"code","source":"sns.distplot(sent_nums)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2fd6bb0a9179638ecee2bf52e4829a104575c7ef"},"cell_type":"code","source":"val_paras = []\nval_labels = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"aae6e7a65c9c9407293c6f91574ca51239f2a60e"},"cell_type":"code","source":"'''\nfor idx in range(val_text.shape[0]):\n    text = val_text.text[idx]\n    sentences = tokenize.sent_tokenize(text)\n    val_paras.append(sentences)\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e59c973e2d5a0f2df2b7a4e910bff272cd303418"},"cell_type":"code","source":"test_paras = []\ntest_labels = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cc8d187b1eb4c902b48f0e7b687b22c9c4d21ffa"},"cell_type":"code","source":"for idx in range(test.shape[0]):\n    text = test[idx]\n    sentences = tokenize.sent_tokenize(text)\n    test_paras.append(sentences)","execution_count":null,"outputs":[]},{"metadata":{"id":"zVjGIuJygxyP","colab_type":"code","colab":{},"trusted":true,"_uuid":"c3ea2a3aefd267b46c0947c04a7ad58bc9ca5e64"},"cell_type":"code","source":"tokenizer = Tokenizer(num_words=max_features, oov_token=True)\ntokenizer.fit_on_texts(texts)","execution_count":null,"outputs":[]},{"metadata":{"id":"99Jsdgjzgxyc","colab_type":"code","colab":{},"trusted":true,"_uuid":"2c6fca0199d8a02d21834d71b8acf8809cf3af39"},"cell_type":"code","source":"x_train = np.zeros((len(texts), max_senten_num, max_senten_len), dtype='int32')\nfor i, sentences in tqdm(enumerate(paras)):\n        tokenized_sent = tokenizer.texts_to_sequences(sentences)\n        padded_seq = pad_sequences(tokenized_sent, maxlen=max_senten_len, padding='post', truncating='post')\n        for j, seq in enumerate(padded_seq):\n            if(j < max_senten_num):\n                x_train[i,j,:] = seq\n            else:\n                break","execution_count":null,"outputs":[]},{"metadata":{"id":"OpKjmFmHgxyl","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":35},"outputId":"72313723-5fe8-49fa-9969-505c16be3cdc","trusted":true,"_uuid":"bd1e9d50df128646970caf5ce82de4af47ff6bdf"},"cell_type":"code","source":"x_train.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9db502983b824b6c0bf51684cd65182ffa87fc46"},"cell_type":"code","source":"'''\nx_val = np.zeros((val_text.shape[0], max_senten_num, max_senten_len), dtype='int32')\nfor i, sentences in tqdm(enumerate(val_paras)):\n        tokenized_sent = tokenizer.texts_to_sequences(sentences)\n        padded_seq = pad_sequences(tokenized_sent, maxlen=max_senten_len, padding='post', truncating='post')\n        for j, seq in enumerate(padded_seq):\n            if(j < max_senten_num):\n                x_val[i,j,:] = seq\n            else:\n                break\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"87944d5b420b7606ad5463bbbd984c978e004bce"},"cell_type":"code","source":"test_data = np.zeros((test.shape[0], max_senten_num, max_senten_len), dtype='int32')\nfor i, sentences in enumerate(test_paras):\n        tokenized_sent = tokenizer.texts_to_sequences(sentences)\n        padded_seq = pad_sequences(tokenized_sent, maxlen=max_senten_len, padding='post', truncating='post')\n        for j, seq in enumerate(padded_seq):\n            if(j < max_senten_num):\n                test_data[i,j,:] = seq\n            else:\n                break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0a7406d8471c86347b5b08b15132067e95846673"},"cell_type":"code","source":"print(test_data.shape)","execution_count":null,"outputs":[]},{"metadata":{"id":"YUgnmB2Igxyt","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":35},"outputId":"c5202c59-4f84-49fd-8bfa-5202f2b93262","trusted":true,"_uuid":"5d65bf7613c3e0e217b569fe1eb71fe7cc860cad"},"cell_type":"code","source":"word_index = tokenizer.word_index\nprint('Total %s unique tokens.' % len(word_index))","execution_count":null,"outputs":[]},{"metadata":{"id":"edq6g1Ybgxy3","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":53},"outputId":"6eb054ad-6950-4be5-e1ee-831c08847cfa","trusted":true,"_uuid":"3b57aabbe00d6cf62bd98d191c45706250416dab"},"cell_type":"code","source":"print('Shape of training tensor:', x_train.shape)\nprint('Shape of test tensor:', test_data.shape)","execution_count":null,"outputs":[]},{"metadata":{"id":"l2UCwLNggxzM","colab_type":"text","_uuid":"a31545078acc77f424c95c33d59a96f502aba10b"},"cell_type":"markdown","source":"### Embeddings"},{"metadata":{"id":"PGRLk4Q1z1U-","colab_type":"code","colab":{},"trusted":true,"_uuid":"9bff7cfc93983318f015bc4758dfa94579b9cba1"},"cell_type":"code","source":"import os","execution_count":null,"outputs":[]},{"metadata":{"id":"bp4upuqFu3Eb","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":35},"outputId":"2ac20441-d569-4bf5-e7af-aa23e31c866d","trusted":true,"_uuid":"88df613e2852c82455dfc92d953f5ff41b1569c0"},"cell_type":"code","source":"gc.collect()\nword_index = tokenizer.word_index\nmax_features = len(word_index)+1\ndef load_glove(word_index):\n    EMBEDDING_FILE = '../input/embeddings/glove.840B.300d/glove.840B.300d.txt'\n    def get_coefs(word,*arr): return word.lower(), np.asarray(arr, dtype='float32')\n    embeddings_index = dict(get_coefs(*o.split(\" \")) for o in open(EMBEDDING_FILE) if o.split(\" \")[0] in word_index)\n\n    all_embs = np.stack(embeddings_index.values())\n    emb_mean,emb_std = all_embs.mean(), all_embs.std()\n    embed_size = all_embs.shape[1]\n    embedding_matrix = np.random.normal(emb_mean, emb_std, (max_features, embed_size))\n    for 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            \n    return embedding_matrix \n    \ndef load_fasttext(word_index):    \n    EMBEDDING_FILE = '../input/embeddings/wiki-news-300d-1M/wiki-news-300d-1M.vec'\n    def get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')\n    embeddings_index = dict(get_coefs(*o.split(\" \")) for o in open(EMBEDDING_FILE) if len(o)>100 and o.split(\" \")[0] in word_index )\n\n    all_embs = np.stack(embeddings_index.values())\n    emb_mean,emb_std = all_embs.mean(), all_embs.std()\n    embed_size = all_embs.shape[1]\n\n    embedding_matrix = np.random.normal(emb_mean, emb_std, (max_features, embed_size))\n    for 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\n    return embedding_matrix\n\ndef load_para(word_index):\n    EMBEDDING_FILE = '../input/embeddings/paragram_300_sl999/paragram_300_sl999.txt'\n    def get_coefs(word,*arr): return word.lower(), np.asarray(arr, dtype='float32')\n    embeddings_index = dict(get_coefs(*o.split(\" \")) for o in open(EMBEDDING_FILE, encoding=\"utf8\", errors='ignore') if len(o)>100 and o.split(\" \")[0] in word_index)\n\n    all_embs = np.stack(embeddings_index.values())\n    emb_mean,emb_std = all_embs.mean(), all_embs.std()\n    embed_size = all_embs.shape[1]\n    \n    embedding_matrix = np.random.normal(emb_mean, emb_std, (max_features, embed_size))\n    for 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    \n    return embedding_matrix","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f53357d2f475bfc1ea27fa6b61892e1c92c8d6e0"},"cell_type":"code","source":"embedding_matrix_1 = load_glove(word_index)\n#embedding_matrix_2 = load_fasttext(word_index)\nembedding_matrix_3 = load_para(word_index)\nembedding_matrix = np.mean((embedding_matrix_1, embedding_matrix_3), axis=0)\ndel embedding_matrix_1, embedding_matrix_3\ngc.collect()\nnp.shape(embedding_matrix)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7f617fb84ac8d0d0f4cc68a91d408ea0e04292ab"},"cell_type":"markdown","source":"## Model"},{"metadata":{"trusted":true,"_uuid":"d9c57d4fbf10d12f90b27f8d7574d053f0dc902b"},"cell_type":"code","source":"# https://www.kaggle.com/hireme/fun-api-keras-f1-metric-cyclical-learning-rate/code\n\nclass CyclicLR(Callback):\n    \"\"\"This callback implements a cyclical learning rate policy (CLR).\n    The method cycles the learning rate between two boundaries with\n    some constant frequency, as detailed in this paper (https://arxiv.org/abs/1506.01186).\n    The amplitude of the cycle can be scaled on a per-iteration or \n    per-cycle basis.\n    This class has three built-in policies, as put forth in the paper.\n    \"triangular\":\n        A basic triangular cycle w/ no amplitude scaling.\n    \"triangular2\":\n        A basic triangular cycle that scales initial amplitude by half each cycle.\n    \"exp_range\":\n        A cycle that scales initial amplitude by gamma**(cycle iterations) at each \n        cycle iteration.\n    For more detail, please see paper.\n    \n    # Example\n        ```python\n            clr = CyclicLR(base_lr=0.001, max_lr=0.006,\n                                step_size=2000., mode='triangular')\n            model.fit(X_train, Y_train, callbacks=[clr])\n        ```\n    \n    Class also supports custom scaling functions:\n        ```python\n            clr_fn = lambda x: 0.5*(1+np.sin(x*np.pi/2.))\n            clr = CyclicLR(base_lr=0.001, max_lr=0.006,\n                                step_size=2000., scale_fn=clr_fn,\n                                scale_mode='cycle')\n            model.fit(X_train, Y_train, callbacks=[clr])\n        ```    \n    # Arguments\n        base_lr: initial learning rate which is the\n            lower boundary in the cycle.\n        max_lr: upper boundary in the cycle. Functionally,\n            it defines the cycle amplitude (max_lr - base_lr).\n            The lr at any cycle is the sum of base_lr\n            and some scaling of the amplitude; therefore \n            max_lr may not actually be reached depending on\n            scaling function.\n        step_size: number of training iterations per\n            half cycle. Authors suggest setting step_size\n            2-8 x training iterations in epoch.\n        mode: one of {triangular, triangular2, exp_range}.\n            Default 'triangular'.\n            Values correspond to policies detailed above.\n            If scale_fn is not None, this argument is ignored.\n        gamma: constant in 'exp_range' scaling function:\n            gamma**(cycle iterations)\n        scale_fn: Custom scaling policy defined by a single\n            argument lambda function, where \n            0 <= scale_fn(x) <= 1 for all x >= 0.\n            mode paramater is ignored \n        scale_mode: {'cycle', 'iterations'}.\n            Defines whether scale_fn is evaluated on \n            cycle number or cycle iterations (training\n            iterations since start of cycle). Default is 'cycle'.\n    \"\"\"\n\n    def __init__(self, base_lr=0.001, max_lr=0.006, step_size=2000., mode='triangular',\n                 gamma=1., scale_fn=None, scale_mode='cycle'):\n        super(CyclicLR, self).__init__()\n\n        self.base_lr = base_lr\n        self.max_lr = max_lr\n        self.step_size = step_size\n        self.mode = mode\n        self.gamma = gamma\n        if scale_fn == None:\n            if self.mode == 'triangular':\n                self.scale_fn = lambda x: 1.\n                self.scale_mode = 'cycle'\n            elif self.mode == 'triangular2':\n                self.scale_fn = lambda x: 1/(2.**(x-1))\n                self.scale_mode = 'cycle'\n            elif self.mode == 'exp_range':\n                self.scale_fn = lambda x: gamma**(x)\n                self.scale_mode = 'iterations'\n        else:\n            self.scale_fn = scale_fn\n            self.scale_mode = scale_mode\n        self.clr_iterations = 0.\n        self.trn_iterations = 0.\n        self.history = {}\n\n        self._reset()\n\n    def _reset(self, new_base_lr=None, new_max_lr=None,\n               new_step_size=None):\n        \"\"\"Resets cycle iterations.\n        Optional boundary/step size adjustment.\n        \"\"\"\n        if new_base_lr != None:\n            self.base_lr = new_base_lr\n        if new_max_lr != None:\n            self.max_lr = new_max_lr\n        if new_step_size != None:\n            self.step_size = new_step_size\n        self.clr_iterations = 0.\n        \n    def clr(self):\n        cycle = np.floor(1+self.clr_iterations/(2*self.step_size))\n        x = np.abs(self.clr_iterations/self.step_size - 2*cycle + 1)\n        if self.scale_mode == 'cycle':\n            return self.base_lr + (self.max_lr-self.base_lr)*np.maximum(0, (1-x))*self.scale_fn(cycle)\n        else:\n            return self.base_lr + (self.max_lr-self.base_lr)*np.maximum(0, (1-x))*self.scale_fn(self.clr_iterations)\n        \n    def on_train_begin(self, logs={}):\n        logs = logs or {}\n\n        if self.clr_iterations == 0:\n            K.set_value(self.model.optimizer.lr, self.base_lr)\n        else:\n            K.set_value(self.model.optimizer.lr, self.clr())        \n            \n    def on_batch_end(self, epoch, logs=None):\n        \n        logs = logs or {}\n        self.trn_iterations += 1\n        self.clr_iterations += 1\n\n        self.history.setdefault('lr', []).append(K.get_value(self.model.optimizer.lr))\n        self.history.setdefault('iterations', []).append(self.trn_iterations)\n\n        for k, v in logs.items():\n            self.history.setdefault(k, []).append(v)\n        \n        K.set_value(self.model.optimizer.lr, self.clr())\n    \n\ndef f1(y_true, y_pred):\n    '''\n    metric from here \n    https://stackoverflow.com/questions/43547402/how-to-calculate-f1-macro-in-keras\n    '''\n    def recall(y_true, y_pred):\n        \"\"\"Recall metric.\n\n        Only computes a batch-wise average of recall.\n\n        Computes the recall, a metric for multi-label classification of\n        how many relevant items are selected.\n        \"\"\"\n        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))\n        possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))\n        recall = true_positives / (possible_positives + K.epsilon())\n        return recall\n\n    def precision(y_true, y_pred):\n        \"\"\"Precision metric.\n\n        Only computes a batch-wise average of precision.\n\n        Computes the precision, a metric for multi-label classification of\n        how many selected items are relevant.\n        \"\"\"\n        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))\n        predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))\n        precision = true_positives / (predicted_positives + K.epsilon())\n        return precision\n    precision = precision(y_true, y_pred)\n    recall = recall(y_true, y_pred)\n    return 2*((precision*recall)/(precision+recall+K.epsilon()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1811275f20c541a2a4adb03e91180b6745fe5ce7"},"cell_type":"code","source":"from sklearn.metrics import roc_curve, precision_recall_curve\ndef threshold_search(y_true, y_proba, plot=False):\n    precision, recall, thresholds = precision_recall_curve(y_true, y_proba)\n    thresholds = np.append(thresholds, 1.001) \n    F = 2 / (1/precision + 1/recall)\n    best_score = np.max(F)\n    best_th = thresholds[np.argmax(F)]\n    if plot:\n        plt.plot(thresholds, F, '-b')\n        plt.plot([best_th], [best_score], '*r')\n        plt.show()\n    search_result = {'threshold': best_th , 'f1': best_score}\n    return search_result ","execution_count":null,"outputs":[]},{"metadata":{"id":"c2RcVWFTgxzc","colab_type":"code","colab":{},"trusted":true,"_uuid":"abdb6adfcfaace47815d0ae083ee45a0e2c31e6e"},"cell_type":"code","source":"def han_model(embedding_matrix):\n    nb_words = embedding_matrix.shape[0]\n    embedding_layer = Embedding(nb_words, embed_size, weights=[embedding_matrix])\n    word_input = Input(shape=(max_senten_len,), dtype='float32')\n    word_sequences = embedding_layer(word_input)\n    word_lstm = Bidirectional(CuDNNLSTM(64, return_sequences=True))(word_sequences)\n    word_att = AttentionWithContext()(word_lstm)\n    word_att = ReLU()(word_att)\n    wordEncoder = Model(word_input, word_att)\n\n    sent_input = Input(shape=(max_senten_num, max_senten_len), dtype='float32')\n    sent_encoder = TimeDistributed(wordEncoder)(sent_input)\n    sent_enc_avg = Lambda(lambda x: K.sum(x, axis=1))(sent_encoder)\n    sent_enc_avg  = ReLU()(sent_enc_avg)\n    pred1 = Dense(1, activation='sigmoid')(sent_enc_avg)\n    sent_lstm = Bidirectional(CuDNNLSTM(128, return_sequences=True))(sent_encoder)\n    sent_att = AttentionWithContext()(sent_lstm)\n    sent_att = ReLU()(sent_att)\n    pred2 = Dense(1, activation='sigmoid')(sent_att)\n    preds = Average()([pred1, pred2])\n    model = Model(sent_input, preds)\n    model.compile(loss='binary_crossentropy',optimizer=Adam(),metrics=[f1])\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b2988a7501829f6a58c9edf4b8925eef49049c62"},"cell_type":"code","source":"# https://www.kaggle.com/strideradu/word2vec-and-gensim-go-go-go\ndef train_pred(model, train_X, train_y, val_X, val_y, epochs=2, callback=None, batch_size=512):\n    print(train_X.dtype, train_y.dtype)\n    h = model.fit(train_X, train_y, batch_size=batch_size, epochs=epochs, validation_data=(val_X, val_y), callbacks = callback, verbose=1)\n    model.load_weights(filepath)\n    pred_val_y = model.predict([val_X], batch_size=1024, verbose=0)\n    pred_test_y = model.predict([test_data], batch_size=1024, verbose=0)\n    print('=' * 60)\n    return pred_val_y, pred_test_y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b9c381c4607f5434607d01b594ef22e34f818b83"},"cell_type":"code","source":"from sklearn.model_selection import GridSearchCV, StratifiedKFold","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0d06fdfd8cf886cf13b1260ac2ac145f54514f07"},"cell_type":"code","source":"DATA_SPLIT_SEED = 2018\nclr = CyclicLR(base_lr=0.001, max_lr=0.002,step_size=300., mode='exp_range',gamma=0.99994)\nfilepath=\"weights_best.h5\"\ntrain_meta = np.zeros(x_train.shape[0])\n#val_meta = np.zeros(x_val.shape[0])\ntest_meta = np.zeros(test_data.shape[0])\nsplits = list(StratifiedKFold(n_splits=5, shuffle=True, random_state=DATA_SPLIT_SEED).split(x_train, y_train))\nfor idx, (train_idx, valid_idx) in enumerate(splits):\n    checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='min')\n    #reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.6, patience=1, min_lr=0.0001, verbose=2)\n    callbacks = [checkpoint, clr]\n    train_x = x_train[train_idx]\n    train_y = y_train.values[train_idx]\n    val_x = x_train[valid_idx]\n    val_y = y_train.values[valid_idx]\n    model = han_model(embedding_matrix)\n    pred_val_y , pred_test_y = train_pred(model, train_x, train_y, val_x, val_y, epochs = 3, callback = callbacks)\n    train_meta[valid_idx] = pred_val_y.reshape(-1)\n    #val_meta += pred_y_val.reshape(-1) / len(splits)\n    test_meta += pred_test_y.reshape(-1) / len(splits)\n    os.remove(filepath)\n    del model\n    gc.collect()","execution_count":null,"outputs":[]},{"metadata":{"id":"nf5L1DvTgxzx","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":53},"outputId":"5148c7e8-7c84-4237-e479-5359b79aea80","trusted":true,"_uuid":"70fbbd2f34955592a8968d8ab95ce3fee6d3c64d"},"cell_type":"code","source":"search_result = threshold_search(y_train, train_meta)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6144e53f113a46244c209bbfbd92dcdeb1f0ad58"},"cell_type":"code","source":"print(search_result)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f57e1d7a06862050aacacbbfb7f55fc00539a60a"},"cell_type":"code","source":"pred_test_y = (test_meta>search_result['threshold']).astype(int)\nout_df = pd.DataFrame({\"qid\":test_df[\"qid\"].values})\nout_df['prediction'] = pred_test_y\nout_df.to_csv(\"submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3af0f03f198a6cd9264f02c03ff330912c13fbd6"},"cell_type":"code","source":"gc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1675e85a1bbd5c2df2c7910c9b72a0ce3d056d0f"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"colab":{"name":"HAN.ipynb","version":"0.3.2","provenance":[],"collapsed_sections":[],"toc_visible":true},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"accelerator":"GPU","language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}