{"cells":[{"metadata":{"_uuid":"86a5eda07f27aef7aaaaf971409dcba0405820af"},"cell_type":"markdown","source":"#### We don't have `ignite` available in kaggle kernels, so a hack is needed. There it is\nsupport ignite author pull request for better life\nhttps://github.com/Kaggle/docker-python/pull/226"},{"metadata":{"trusted":false,"_uuid":"3c3371ae826898e55bc60e87e254eb4f25c27ccf"},"cell_type":"code","source":"ignite_wheel = '''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\nZ2luZXMvdGJwdHQucHlQSwECFAMUAAAACAAwm2lNhWEQsXgAAADNAAAAIwAAAAAAAAAAAAAAtIHJ\nCgAAaWduaXRlL2NvbnRyaWIvaGFuZGxlcnMvX19pbml0X18ucHlQSwECFAMUAAAACAAwm2lNiyzO\nKA4IAABHJQAAKgAAAAAAAAAAAAAAtIGCCwAAaWduaXRlL2NvbnRyaWIvaGFuZGxlcnMvcGFyYW1f\nc2NoZWR1bGVyLnB5UEsBAhQDFAAAAAgAMJtpTUuyfcjGBQAALBEAACYAAAAAAAAAAAAAALSB2BMA\nAGlnbml0ZS9jb250cmliL2hhbmRsZXJzL3RxZG1fbG9nZ2VyLnB5UEsBAhQDFAAAAAgAMJtpTe7Q\nCZFpAAAAtgAAACIAAAAAAAAAAAAAALSB4hkAAGlnbml0ZS9jb250cmliL21ldHJpY3MvX19pbml0\nX18ucHlQSwECFAMUAAAACAAwm2lNlJ2vHqYCAABRBgAAKwAAAAAAAAAAAAAAtIGLGgAAaWduaXRl\nL2NvbnRyaWIvbWV0cmljcy9hdmVyYWdlX3ByZWNpc2lvbi5weVBLAQIUAxQAAAAIADCbaU1V4HY+\nSwEAAP8CAAAdAAAAAAAAAAAAAAC0gXodAABpZ25pdGUvY29udHJpYi9tZXRyaWNzL21hZS5weVBL\nAQIUAxQAAAAIADCbaU1v9zWqwwIAACMGAAAhAAAAAAAAAAAAAAC0gQAfAABpZ25pdGUvY29udHJp\nYi9tZXRyaWNzL3JvY19hdWMucHlQSwECFAMUAAAACAAwm2lNXAtnyHADAACHDAAAGQAAAAAAAAAA\nAAAAtIECIgAAaWduaXRlL2VuZ2luZS9fX2luaXRfXy5weVBLAQIUAxQAAAAIADCbaU2bjALuoQwA\nAO4uAAAXAAAAAAAAAAAAAAC0gaklAABpZ25pdGUvZW5naW5lL2VuZ2luZS5weVBLAQIUAxQAAAAI\nADCbaU3v8RrNbQAAANUAAAAbAAAAAAAAAAAAAAC0gX8yAABpZ25pdGUvaGFuZGxlcnMvX19pbml0\nX18ucHlQSwECFAMUAAAACAAwm2lNxyr4yCIJAABKHgAAHQAAAAAAAAAAAAAAtIElMwAAaWduaXRl\nL2hhbmRsZXJzL2NoZWNrcG9pbnQucHlQSwECFAMUAAAACAAwm2lN1c5F9FADAABWCQAAIQAAAAAA\nAAAAAAAAtIGCPAAAaWduaXRlL2hhbmRsZXJzL2Vhcmx5X3N0b3BwaW5nLnB5UEsBAhQDFAAAAAgA\nMJtpTabUo0VDAwAAyAcAACMAAAAAAAAAAAAAALSBEUAAAGlnbml0ZS9oYW5kbGVycy90ZXJtaW5h\ndGVfb25fbmFuLnB5UEsBAhQDFAAAAAgAMJtpTa7Py10eBQAAPREAABkAAAAAAAAAAAAAALSBlUMA\nAGlnbml0ZS9oYW5kbGVycy90aW1pbmcucHlQSwECFAMUAAAACAAwm2lN0mMDz+gAAAAcAwAAGgAA\nAAAAAAAAAAAAtIHqSAAAaWduaXRlL21ldHJpY3MvX19pbml0X18ucHlQSwECFAMUAAAACAAwm2lN\nOD1CWqICAADIBwAAGgAAAAAAAAAAAAAAtIEKSgAAaWduaXRlL21ldHJpY3MvYWNjdXJhY3kucHlQ\nSwECFAMUAAAACAAwm2lNQ1hsSu8AAADeAQAAIQAAAAAAAAAAAAAAtIHkTAAAaWduaXRlL21ldHJp\nY3MvYmluYXJ5X2FjY3VyYWN5LnB5UEsBAhQDFAAAAAgAMJtpTRltT+zyAAAA6AEAACYAAAAAAAAA\nAAAAALSBEk4AAGlnbml0ZS9tZXRyaWNzL2NhdGVnb3JpY2FsX2FjY3VyYWN5LnB5UEsBAhQDFAAA\nAAgAMJtpTQZZGNNuBAAATQwAAB4AAAAAAAAAAAAAALSBSE8AAGlnbml0ZS9tZXRyaWNzL2Vwb2No\nX21ldHJpYy5weVBLAQIUAxQAAAAIADCbaU1njNO4MAMAAEMIAAAWAAAAAAAAAAAAAAC0gfJTAABp\nZ25pdGUvbWV0cmljcy9sb3NzLnB5UEsBAhQDFAAAAAgAMJtpTcaZnWxxAQAAXwMAACUAAAAAAAAA\nAAAAALSBVlcAAGlnbml0ZS9tZXRyaWNzL21lYW5fYWJzb2x1dGVfZXJyb3IucHlQSwECFAMUAAAA\nCAAwm2lNdf1ujdEBAABBBAAAKAAAAAAAAAAAAAAAtIEKWQAAaWduaXRlL21ldHJpY3MvbWVhbl9w\nYWlyd2lzZV9kaXN0YW5jZS5weVBLAQIUAxQAAAAIADCbaU14niaGcwEAAFoDAAAkAAAAAAAAAAAA\nAAC0gSFbAABpZ25pdGUvbWV0cmljcy9tZWFuX3NxdWFyZWRfZXJyb3IucHlQSwECFAMUAAAACAAw\nm2lN6FfyffUCAAAcCAAAGAAAAAAAAAAAAAAAtIHWXAAAaWduaXRlL21ldHJpY3MvbWV0cmljLnB5\nUEsBAhQDFAAAAAgAMJtpTemdfR2jAwAATAsAABsAAAAAAAAAAAAAALSBAWAAAGlnbml0ZS9tZXRy\naWNzL3ByZWNpc2lvbi5weVBLAQIUAxQAAAAIADCbaU2rjnsRpAMAAPMKAAAYAAAAAAAAAAAAAAC0\ngd1jAABpZ25pdGUvbWV0cmljcy9yZWNhbGwucHlQSwECFAMUAAAACAAwm2lNFeu4DNsAAACEAQAA\nKQAAAAAAAAAAAAAAtIG3ZwAAaWduaXRlL21ldHJpY3Mvcm9vdF9tZWFuX3NxdWFyZWRfZXJyb3Iu\ncHlQSwECFAMUAAAACAAwm2lNTHcQbzoEAACFDQAAIQAAAAAAAAAAAAAAtIHZaAAAaWduaXRlL21l\ndHJpY3MvcnVubmluZ19hdmVyYWdlLnB5UEsBAhQDFAAAAAgAMJtpTdbXWQLlAQAAZAQAACwAAAAA\nAAAAAAAAALSBUm0AAGlnbml0ZS9tZXRyaWNzL3RvcF9rX2NhdGVnb3JpY2FsX2FjY3VyYWN5LnB5\nUEsBAhQDFAAAAAgAbp1pTcbFdoIXAwAA6AUAACYAAAAAAAAAAAAAALSBgW8AAHB5dG9yY2hfaWdu\naXRlLTAuMS4xLmRpc3QtaW5mby9MSUNFTlNFUEsBAhQDFAAAAAgAbp1pTe2LmXwIBgAAyg0AACcA\nAAAAAAAAAAAAALSB3HIAAHB5dG9yY2hfaWduaXRlLTAuMS4xLmRpc3QtaW5mby9NRVRBREFUQVBL\nAQIUAxQAAAAIAG6daU08Ro/MXwAAAG4AAAAkAAAAAAAAAAAAAAC0gSl5AABweXRvcmNoX2lnbml0\nZS0wLjEuMS5kaXN0LWluZm8vV0hFRUxQSwECFAMUAAAACABunWlNfy44XQkAAAAHAAAALAAAAAAA\nAAAAAAAAtIHKeQAAcHl0b3JjaF9pZ25pdGUtMC4xLjEuZGlzdC1pbmZvL3RvcF9sZXZlbC50eHRQ\nSwECFAMUAAAACAB5m2lNkwbXMgMAAAABAAAAJwAAAAAAAAAAAAAAtIEdegAAcHl0b3JjaF9pZ25p\ndGUtMC4xLjEuZGlzdC1pbmZvL3ppcC1zYWZlUEsBAhQDFAAAAAgAbp1pTT1eHo6RBwAA8w0AACUA\nAAAAAAAAAAAAALQBZXoAAHB5dG9yY2hfaWduaXRlLTAuMS4xLmRpc3QtaW5mby9SRUNPUkRQSwUG\nAAAAACkAKQB8DAAAOYIAAAAA'''.replace('\\n', '')","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"9a05c294001d73af3369398e9b2ecec1fc487f91"},"cell_type":"code","source":"len(ignite_wheel)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"3a93275f8ef6db4b7c426b9c17b5b2a73acd41f4"},"cell_type":"code","source":"!echo $ignite_wheel | base64 -di - > pytorch_ignite-0.1.1-py2.py3-none-any.whl","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"be982274112b4dc93b17a543d3b6b20825ae8cdd"},"cell_type":"code","source":"!pip install pytorch_ignite-0.1.1-py2.py3-none-any.whl","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"d2132d7b2960242c45be4ad9a5d5a4c3ec6f6e2e"},"cell_type":"code","source":"import os\n\nimport pandas as pd\nimport numpy as np\n\nfrom sklearn import metrics\nimport random","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"d508c03b6aca4a68f4e97c845a43f3998616542a"},"cell_type":"code","source":"from tqdm import tqdm_notebook, tqdm_pandas, tqdm\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nfrom itertools import chain","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"49780dbc8784e95d76b609cc945a04a497079049"},"cell_type":"code","source":"import logging\n\nfile_log = \"log.log\" # no limits\nlogger = logging.getLogger(\"NTB\")\n\nformatter = logging.Formatter(fmt=\"%(asctime)s - %(levelname)s - %(message)s\",  datefmt=\"%F %T\")\n\nconsole_logging_handler = logging.StreamHandler()\nconsole_logging_handler.setFormatter(formatter)\n\nfile_logging_handler = logging.FileHandler(file_log)\nfile_logging_handler.setFormatter(formatter)\n\nlogger.addHandler(file_logging_handler) \nlogger.addHandler(console_logging_handler)\nlogger.setLevel(logging.DEBUG)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"b7f8fe1e1c28398d5f7b3d0615792b020436ecfa"},"cell_type":"code","source":"import torch\n\nfrom torchtext import data, vocab\nimport spacy","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"20e007e278d9d97cc8a78482ecb6b7b817fc76f5"},"cell_type":"markdown","source":"#### Some basic GPU settings"},{"metadata":{"trusted":false,"_uuid":"4283befdb4dba54830d0d8dbf02eb2cf329909b2"},"cell_type":"code","source":"kaggle = True\ncuda = True\n\nif cuda:\n    torch.cuda.set_device(0 if kaggle else 2)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e1341d2ccb46a557d3706205c4b245e29b7c3f20"},"cell_type":"markdown","source":"#### Prepare SpaCy for text processing: parsing, lemmatizing"},{"metadata":{"trusted":false,"_uuid":"d521832c78b967cc2e6d25efa1a250e35d0b97ed"},"cell_type":"code","source":"nlp = spacy.load('en')\n\nnlp.remove_pipe('parser') # dont need PoS\nnlp.remove_pipe('ner') # dont need NERs","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d50f45a458459fde3bc7d84c88fe76ba1e88b83f"},"cell_type":"markdown","source":"#### Helper for DataFrame preparation"},{"metadata":{"trusted":false,"_uuid":"77689e3c604cd4a6483d2722eeca75e13991681a"},"cell_type":"code","source":"def process_text(df):\n    \n    preprocessed = tqdm_notebook(nlp.pipe(\n        tqdm_notebook(df.question_text), \n        batch_size=850 if kaggle else 1500, # batching processing is MUCH faster\n        n_threads=4 if kaggle else 8\n    ))\n    \n    df['processed'] = list(map(lambda x: ' '.join([_.lemma_ for _ in x]), preprocessed))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"00fea63c60d7bff2183792c9174c9db51cb54c19"},"cell_type":"code","source":"from random import random as get_rnd_flt\n\ndef make_iterators_from_sets(dataset):\n    return data.BucketIterator(\n        dataset=dataset, \n        shuffle=True, \n        repeat=True,\n        batch_size=128,\n        sort=False, # cant sort here due to real shuffling, need sophisticated preparation for using that feature\n                    # will add this logic if comunity need that\n        sort_key=lambda x: len(x.processed) + get_rnd_flt(), #random is for shuffling in equal-lenght batches, dont need now actually\n        device='cuda' if cuda else None\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f6a3cabfadee4e6e378276d54882ba487da29ac1"},"cell_type":"markdown","source":"#### Needed for generating important absent vectors in embeddings"},{"metadata":{"trusted":false,"_uuid":"80a45fcd1f12a7030621f2abe1ba7b68d7317317"},"cell_type":"code","source":"def generate_vector(dim, phases=[1,5,123,216]):\n    vec = torch.rand(1, dim)\n    for i in range(dim):\n        appfactor = 0\n        for phase in phases:\n            appfactor += np.cos(i * phase)\n        appfactor = appfactor / len(phases)\n        vec[0, i] = vec[0, i] + appfactor\n    return vec","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0ebd19d6a815c6586eb9dc9e86189c2891163116"},"cell_type":"markdown","source":"### Set up data store"},{"metadata":{"trusted":false,"_uuid":"9818687f8eb7f7fbc9531076628d3177e333bfd8"},"cell_type":"code","source":"input_train_dir = '../input/train.csv' if kaggle else '/stor/comps/quora18/train.csv.zip'\ninput_predict_dir = '../input/test.csv' if kaggle else '/stor/comps/quora18/test.csv.zip'\ninput_embeddings_dir = '../input/embeddings/glove.840B.300d/glove.840B.300d.txt' if kaggle else '/stor/comps/quora18/glove.840B.300d/glove.840B.300d.txt'","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"638b3fd9ebcf46dfe2cbd03faaf450d2bcf34cf7"},"cell_type":"markdown","source":"### For local use: cache processed texts\n\nSpaCy takes about 20min to process..."},{"metadata":{"trusted":false,"_uuid":"f31c5a90d4b705a3977cde1ef2f26065110b299b"},"cell_type":"code","source":"if kaggle or not os.path.exists('temp_train.processed.csv'):\n    datas = pd.read_csv(input_train_dir)\n    process_text(datas)\n    if not kaggle:\n        datas.to_csv('temp_train.processed.csv', index=None)\nelse:\n    datas = pd.read_csv('temp_train.processed.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"35ebaea82d76e090872bd04fdbcee74809cfc913"},"cell_type":"code","source":"datas.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"2a1dafb573f5d1d5a3ac324e8f69c0b399c428b0"},"cell_type":"code","source":"to_predict = pd.read_csv(input_predict_dir)\n\nprocess_text(to_predict)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"483d47900c315d02dc69cfadbbbcbd757ab15b61"},"cell_type":"markdown","source":"### TorchText data loader fields preparation"},{"metadata":{"trusted":false,"_uuid":"3f5106d2fb5ce2b487fceca7e1c6ba370df50541"},"cell_type":"code","source":"precessed_field = ('processed', data.Field( # \"processed\" is exapmle field name\n    include_lengths=True, # may need seq lenght sometimes\n    sequential=True, # tell fields preprocessors its texts aka token sequence\n    init_token='<s>', # add special token at sequence start\n    eos_token='</s>', # final special token\n    batch_first=True, # I like batch dimension comes first \n))\n\nlabel_field = ('target', data.LabelField()) # tell torchtext dataloader what to predict, named \"target\"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cb66b951298cc88efe023fe763be656dcb15df84"},"cell_type":"markdown","source":"### Way to transform dataframe rows to torchtext examples"},{"metadata":{"trusted":false,"_uuid":"83583685a75925b88b3e344abc8b232d1557e716"},"cell_type":"code","source":"def df2examples(df, fields):\n    return [\n        data.Example.fromdict(row.to_dict(), fields) for _, row in tqdm_notebook(df.iterrows())\n    ]","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"42bb7aac577ef421aefea0800f7f25650e1252c4"},"cell_type":"code","source":"data_examples = df2examples(datas, {'processed':precessed_field, 'target':label_field})","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"1eccb6e4caac99a200aaa3a89fd1c1abaac1de36"},"cell_type":"code","source":"text_dataset = data.Dataset(data_examples, dict([precessed_field, label_field]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"57e1a9ec7c30c726d83b0932c01de3bc834f6abe"},"cell_type":"code","source":"random.seed(42)\n\nrandom_state = random.getstate() # TorchText need that state to be reproducible, I am not sure its enought\n\ndef make_split_on_ds(ds):\n    return ds.split(\n        split_ratio=[0.8, 0.1, 0.1], # train, cv, test\n        stratified=True, \n        strata_field='target',\n        random_state=random_state\n    )","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"a267b832f7c859ad9ca2c155c1310c26ddf0a997"},"cell_type":"code","source":"train_ds, val_ds, test_ds = make_split_on_ds(text_dataset)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"776e17b2b6d6a92ac99cfc868583d5a4067e305e"},"cell_type":"markdown","source":"### prepare target dataset too"},{"metadata":{"trusted":false,"_uuid":"fa833cf85d0d880213d6ccfde941d3c3c14ec135"},"cell_type":"code","source":"all_examples_to_predict = df2examples(to_predict, {'processed': precessed_field})\n\nto_predict_dataset = data.Dataset(all_examples_to_predict, dict([precessed_field]))\n\nto_predict_iterator = data.BucketIterator(\n    repeat=0, \n    sort=False, \n    shuffle=False, \n    train=False,\n    batch_size=64,\n    dataset=to_predict_dataset, \n    device='cuda' if cuda else None,\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4d230d16456aa2bca857a88b46a61e90f21be93b"},"cell_type":"markdown","source":"### Prepare vectors for using with TorchText utils"},{"metadata":{"trusted":false,"_uuid":"a1840406bf5b60f553a2feff446c269c2cf74538"},"cell_type":"code","source":"if kaggle:\n    !mkdir cache_vectors\n\nglove_vecs = vocab.Vectors(name=input_embeddings_dir, cache='cache_vectors/')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"75e24c673a495c527eaf41293201975e749f7896"},"cell_type":"markdown","source":"### prepare field vocabs for tokens in trainset\nMaybe not have to hide tokens from other datasets"},{"metadata":{"trusted":false,"_uuid":"936078dc9584f47a4d5cf1bd9bd0f199d31bb37d"},"cell_type":"code","source":"precessed_field[1].build_vocab(\n    train_ds, \n    vectors=glove_vecs, \n    min_freq=3, \n    max_size=100000)\n\nlabel_field[1].build_vocab(train_ds)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dfcbeac89fcd6a3aa01ab4adc615f2cde26e9e54"},"cell_type":"markdown","source":"### prepare batch generators for train part"},{"metadata":{"trusted":false,"_uuid":"947b4e6848707e230ea553b3155c4eaf678ec501"},"cell_type":"code","source":"train_ds, val_ds, test_ds = [make_iterators_from_sets(_) for _ in [train_ds, val_ds, test_ds]]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"247c709c26be421133127b91f940b2a22e36c046"},"cell_type":"markdown","source":"### Some NN train settings"},{"metadata":{"trusted":false,"_uuid":"709cddb9fda7665977d7c94cc4299d7408d2119a"},"cell_type":"code","source":"lstm_hidden_size = 96\nfilters_size = 50\nvecs_dim = 300\nlstm_in_size = 300\n\nlog_interval = 50\nepoch_interval = 250","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"7fd647260e6012746f88ea9284771fc4a484ce3b"},"cell_type":"code","source":"early_stopping_patience = 5","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6e80bd210e753e1d83e88e6787daf3247a468516"},"cell_type":"markdown","source":"### Helper for applyting the NN to iterator"},{"metadata":{"trusted":false,"_uuid":"5cb491a57908b1c5f507fc5400aa0f9e8b12a811"},"cell_type":"code","source":"def apply_nn_to_batcher(nn, batcher, loss_func=None, targets_enable=True):\n    targets = []\n    answers = []\n    losses = []\n    lengths = []\n\n    nn.eval()  # Swith dropout off\n    with torch.no_grad():\n        for i, batch in enumerate(tqdm_notebook(batcher)):\n            r = nn(batch.processed[0])  # batch.processed is tuple (data: [examples x seqLen x embDim], seqLength: [examples])\n            if targets_enable:\n                ttarget = batch.target.type(torch.float32).view(-1, 1)\n                \n                loss = loss_func(r, ttarget)\n                \n                targets.append(ttarget.cpu().numpy()) # save for further analasys\n                losses.append(loss.item()) # save for further analasys\n                \n            lengths.append(batch.processed[1].cpu().numpy()) # save for further analasys\n            answers.append(r.detach().cpu().numpy()) # preds\n                            # detaches a tensor from computation graph\n                                     # moves tensor to CPU from GPU\n                                           # make numpy matrix from pytorch tensor\n    \n    \n    #aggregate data from batches\n    if targets_enable:\n        targets = np.vstack(targets)\n        \n    answers = np.vstack(answers)\n    lengths = np.vstack([_.reshape(-1, 1) for _ in lengths])\n    \n    if not targets_enable:\n        return answers, lengths\n    \n    return targets, answers, lengths, losses","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"b06c5192613fb5be084cb118caeb5f0b6d9ee222"},"cell_type":"code","source":"from torch import nn\n\n# implementation from https://github.com/c0nn3r/pytorch_highway_networks\n\nclass Highway(nn.Module):\n    def __init__(self, size, num_layers, f, drop_inner=None, drop_input=None):\n\n        super(Highway, self).__init__()\n\n        self.num_layers = num_layers\n\n        self.nonlinear = nn.ModuleList([nn.Linear(size, size) for _ in range(num_layers)])\n\n        self.linear = nn.ModuleList([nn.Linear(size, size) for _ in range(num_layers)])\n\n        self.gate = nn.ModuleList([nn.Linear(size, size) for _ in range(num_layers)])\n\n        if drop_inner is not None:\n            self.drop_inner = nn.Dropout(drop_inner, inplace=True)\n\n        if drop_input is not None:\n            self.drop_input = nn.Dropout(drop_input, inplace=True)\n\n        self.f = f\n\n    def forward(self, x):\n        \"\"\"\n            :param x: tensor with shape of [batch_size, size]\n            :return: tensor with shape of [batch_size, size]\n            applies σ(x) ⨀ (f(G(x))) + (1 - σ(x)) ⨀ (Q(x)) transformation | G and Q is affine transformation,\n            f is non-linear transformation, σ(x) is affine transformation with sigmoid non-linearition\n            and ⨀ is element-wise multiplication\n            \"\"\"\n        if hasattr(self, 'drop_input'):\n            x = self.drop_input(x)\n\n        for layer in range(self.num_layers):\n            if hasattr(self, 'drop_inner'):\n                x = self.drop_inner(x)\n\n            gate = torch.sigmoid(self.gate[layer](x))\n\n            nonlinear = self.f(self.nonlinear[layer](x))\n            linear = self.linear[layer](x)\n\n            x = gate * nonlinear + (1 - gate) * linear\n\n        # return self.out_scaler(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"91e3105413a2449c11265362ac061a0e8770a2b5"},"cell_type":"code","source":"class Classifier(torch.nn.Module):\n    def __init__(self):\n        super(Classifier, self).__init__()\n        \n#         self.prelstm = torch.nn.Sequential(\n#             torch.nn.Linear(int(vecs_dim), int(vecs_dim/2)),\n#             torch.nn.Tanh(),\n#             torch.nn.Dropout(0.3), \n#             torch.nn.Linear(int(vecs_dim/2), lstm_in_size),\n#             torch.nn.Dropout(0.2), \n#             torch.nn.Tanh(),\n#         )\n        \n        self.lstm = torch.nn.LSTM(lstm_in_size, lstm_hidden_size, 2, batch_first=True, bidirectional=True,)\n        \n        self.blstm_dropout = torch.nn.Dropout(0.1)\n        \n        self.convs = torch.nn.ModuleList()\n        for conv_len in range(2, 6):\n            self.convs.append(torch.nn.Conv1d(lstm_hidden_size*2, filters_size, conv_len, groups=1))\n        \n        self.lstm2 = torch.nn.LSTM(lstm_hidden_size*2, lstm_hidden_size, batch_first=True)\n        \n        self.fcnn_size = (lstm_hidden_size*3+2*len(self.convs)*filters_size)\n        \n        self.simple_nn = torch.nn.Sequential(\n#             torch.nn.BatchNorm1d(fcnn_size),\n            torch.nn.Dropout(0.5),\n            torch.nn.PReLU(),\n            torch.nn.Linear(self.fcnn_size, int(lstm_hidden_size)),\n            torch.nn.Dropout(0.1),\n            Highway(int(lstm_hidden_size), 4, torch.nn.PReLU(), drop_inner=0.2),\n            torch.nn.PReLU(),\n            torch.nn.Linear(int(lstm_hidden_size), 1),\n            torch.nn.Sigmoid()\n        )\n    \n    def forward(self, batch):\n        \n        r = glove_embs(batch)\n        r = self.lstm(r)[0]\n        \n        # real magic here, restore intuitive order of bilstm output\n        # look for explanations here \n        # https://towardsdatascience.com/understanding-bidirectional-rnn-in-pytorch-5bd25a5dd66\n        r = r.view(r.shape[0], r.shape[1], 2, lstm_hidden_size)        \n        r = torch.cat(\n            [\n                r[:, : , 0 , :].view(r.shape[0], r.shape[1], 1, lstm_hidden_size),\n                r[:, : , 1 , :].flip(dims=(1,)).view(r.shape[0], r.shape[1], 1, lstm_hidden_size)\n            ]\n            ,dim=2\n        )\n        \n        r = self.blstm_dropout(r.view(r.shape[0], r.shape[1], lstm_hidden_size*2))        \n        from_lstm = self.lstm2(r)[0]\n        \n        to_conv = r.transpose(1, 2)        \n        convs = []\n        for convlayer in self.convs:\n            conv_r = convlayer(to_conv)\n            convs.append(conv_r.max(2)[0]) # extract filters max activations\n            convs.append(conv_r.min(2)[0]) # extract filters min activations\n        \n        convs = torch.cat(convs, dim=1)\n        \n        r = torch.cat(\n            [\n                from_lstm[:, -1, :].view(from_lstm.shape[0], lstm_hidden_size), # last state of lstm\n                from_lstm.max(dim=1)[0].view(from_lstm.shape[0], lstm_hidden_size), # max activations of state\n                from_lstm.min(dim=1)[0].view(from_lstm.shape[0], lstm_hidden_size), # min activations of state\n                convs # previously extracted activations\n            ], dim=1)\n        \n        r = self.simple_nn(r) # final decision\n        return r","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"ff2c2b76e76082d90a4c1caa39854cca84c24314"},"cell_type":"code","source":"train_ds.repeat = True # infinite iterations\nval_ds.repeat = False # one time iteration\ntest_ds.repeat = False # one time iteration","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7e329dda10cafef7dc2e77ed14ed0dc740b8c613"},"cell_type":"markdown","source":"### Intensive Ignite usage part\n\nlook for additional info here: https://github.com/pytorch/ignite/tree/master/examples\n\nand here: https://pytorch.org/ignite/quickstart.html"},{"metadata":{"trusted":false,"_uuid":"4116ab8ab4f9ff317e745d4e8bd746da90dbe6ee"},"cell_type":"code","source":"from ignite.engine import Engine, Events, create_supervised_evaluator\nfrom ignite.metrics import Loss\nfrom ignite.handlers import EarlyStopping, ModelCheckpoint\n\nfrom ignite.contrib.handlers import CosineAnnealingScheduler, ProgressBar","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"4f191ef0f1be4384b407449ad59e437c8c342237"},"cell_type":"code","source":"from string import punctuation","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"11282dbb1f11379a42a3927becdfc1ba399f0587"},"cell_type":"markdown","source":"### Set up seeds again"},{"metadata":{"trusted":false,"_uuid":"78ef10c16b1c084672cb0b69abb9ae073cf22dcc"},"cell_type":"code","source":"random.seed(123)\ntorch.manual_seed(123)\nif cuda:\n    torch.cuda.manual_seed(123)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"88fe6204313959c1905ce281b5c5508ff97d5f2a"},"cell_type":"markdown","source":"### Setup `torch.nn.Embeddings` layer"},{"metadata":{"trusted":false,"_uuid":"2f04b8366c49241d971b2b3026451d388f53cae1"},"cell_type":"code","source":"glove_embs = torch.nn.Embedding(\n    precessed_field[1].vocab.vectors.shape[0], \n    precessed_field[1].vocab.vectors.shape[1]\n)\n\nglove_embs.weight.data = precessed_field[1].vocab.vectors.clone()\n\n# fill special tokens vectors if nessesary\nfor specmark in ['<s>', '</s>', '<pad>', '-PRON-', ] + list(punctuation): #'<unk>'\n    if specmark in precessed_field[1].vocab.stoi:\n        continue\n    glove_embs.weight.data[precessed_field[1].vocab.stoi[specmark]] = generate_vector(\n        glove_embs.weight.shape[1],\n        phases=[hash(specmark + _) % 256 for _ in ['', '1', '2', '3']]\n    )\n\nif cuda:\n    glove_embs = glove_embs.cuda()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"1b49382fe869ec035df7d5fc76fd6cac606fb866"},"cell_type":"code","source":"glove_embs.weight.data.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0f7c86fd62cdf65ef28fe02834cc0abf76b1c7d0"},"cell_type":"markdown","source":"#### total empty embeddings"},{"metadata":{"trusted":false,"_uuid":"b9713d5ef9e9093c275e4e13fadbd0ffbc69aecd"},"cell_type":"code","source":"(glove_embs.weight.data == 0).all(dim=1).sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"bb0e08dfe65973ff0cc1252a7d380b3a481a3fb3"},"cell_type":"code","source":"# Create NN instance\nclassifier = Classifier()\nif cuda:\n    classifier = classifier.cuda()\n\n# Setup optimizer\nopt = torch.optim.Adam(classifier.parameters(), lr=0.001, betas=(0.5, 0.9), amsgrad=True)\n\n# Define loss function\ntrain_loss_func = torch.nn.BCELoss() \nval_loss_func = torch.nn.BCELoss()\nif cuda:\n    train_loss_func = train_loss_func.cuda()\n    val_loss_func = val_loss_func.cuda()\n\n# define train iteration func for Ignite\ndef do_train_iter(engine, batch):\n    \n    classifier.train()\n    \n    r = classifier(batch.processed[0])\n    typed_batch = batch.target.type(torch.float32).view(-1, 1)\n    loss = train_loss_func(r, typed_batch)\n    loss.backward()\n    opt.step()\n    opt.zero_grad()\n\n    return loss.item()\n\n# create Ignite Engine from iteration function\ntrainer = Engine(do_train_iter)\n\n# attach to Ignite Engine artificial Event every epoch_interval times (iteration is infinite, remember?)\n@trainer.on(Events.ITERATION_COMPLETED)\ndef make_epoch_end_announce(engine):\n    if (trainer.state.iteration % epoch_interval == 0) and (engine.state.epoch > 0):\n        logger.debug('Rising EPOCH_COMPLETED...')\n        engine.fire_event(Events.EPOCH_COMPLETED)\n        engine.state.epoch = engine.state.epoch + 1\n\n# make evaluation iteration sometimes\n@trainer.on(Events.EPOCH_COMPLETED)\ndef make_val_scores(engine):\n    logger.debug('running evaluation')\n    val_targets, val_answers, val_lengths, val_losses = apply_nn_to_batcher(\n        classifier, \n        val_ds, \n        val_loss_func, \n        targets_enable=True\n    )\n    engine.state.valmetrics = {'all_ce': val_losses, 'bce':np.mean(val_losses)}\n    logger.info(\"Validation Results - Epoch: %d BCE: %4.4f\",\n              engine.state.epoch, \n              engine.state.valmetrics['bce'],\n    )\n\n# add handler log losses history\ntrain_bce_history = []\nval_bce_history = []\ntrain_lr_history = []\n\n@trainer.on(Events.ITERATION_COMPLETED)\ndef track_train_loss(engine):\n    train_bce_history.append((trainer.state.iteration, engine.state.output))\n    train_lr_history.append((trainer.state.iteration, opt.param_groups[0]['lr']))\n\n# log sometimes   \n@trainer.on(Events.ITERATION_COMPLETED)\ndef log_training_loss(engine):\n    iter = engine.state.iteration\n    if iter % log_interval == 0:\n        logger.debug('TRAIN BCE: %d\\t%5.5f', iter, engine.state.output)\n        logger.debug('  \\tCURRENT LR: %d    \\t%5.5f', iter, opt.param_groups[0]['lr'])\n    \n@trainer.on(Events.EPOCH_COMPLETED)\ndef track_val_loss(engine):\n    val_bce_history.append((trainer.state.iteration, engine.state.valmetrics['bce']))\n\n\n# Early stopping, use validation scores for decision\nes_engine = EarlyStopping(early_stopping_patience, lambda x: -x.state.valmetrics['bce'], trainer)\ntrainer.add_event_handler(Events.EPOCH_COMPLETED, es_engine)\n\n\n# cleanup\nif not kaggle:\n    !rm -rf models_checkpoints/\n\n# checkpoint logic, saves best models, could save embeddings too, but its frozen for now\ncheckpointer = ModelCheckpoint(\n    'models_checkpoints', \n    'glove_lstm', \n    n_saved=4, \n    score_function=lambda x: -x.state.valmetrics['bce'],\n    save_as_state_dict=True\n)\ntrainer.add_event_handler(Events.EPOCH_COMPLETED, checkpointer, {'mymodel': classifier})","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":false,"_uuid":"09c76c9b5df14d93e3112a83a294ee159f1c1870"},"cell_type":"code","source":"trainer.run(tqdm_notebook(train_ds))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"89e66c770eee13907ed593521e3f6e00d9dc1002"},"cell_type":"markdown","source":"### plot training process"},{"metadata":{"trusted":false,"_uuid":"0b37781aea7400ae783eaf33cb1eb25393a1c4a5"},"cell_type":"code","source":"plt.plot(*zip(*train_bce_history[log_interval:]))\nplt.plot(*zip(*val_bce_history[1:]))\nplt.plot(*zip(*train_lr_history[log_interval:]))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"36478a38b2522518ce8f11bb5d1421f44da0e3f6"},"cell_type":"markdown","source":"#### look at best saved models "},{"metadata":{"trusted":false,"_uuid":"f100a2119874cee5e72116c4f95c4880798f9850"},"cell_type":"code","source":"checkpointer._saved","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"92c397ef246d5850a79424d256b67204a93b9cc3"},"cell_type":"markdown","source":"### Load best model(evaluated at validation set)"},{"metadata":{"trusted":false,"_uuid":"67005713697082df7cc36d9851486ba4948cc6c2"},"cell_type":"code","source":"best_model = Classifier()\n\nbest_model.load_state_dict(torch.load(checkpointer._saved[-1][-1][0]))\n\nif cuda:\n    best_model = best_model.cuda()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9ad41321561865b3b5e53f599bceb7ee9c4e1269"},"cell_type":"markdown","source":"#### Apply model to validation again"},{"metadata":{"trusted":false,"_uuid":"58666bc31f83fa7d1b31a1a7ec250575c471822d"},"cell_type":"code","source":"val_targets, val_answers, val_lengths, val_losses = apply_nn_to_batcher(best_model, val_ds, val_loss_func)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"85ed96c4e199d20400c3ae6ba9ed09801d5d6fd4"},"cell_type":"markdown","source":"### Have a look: some perfomance metrics on validation score"},{"metadata":{"trusted":false,"_uuid":"30bb6b2f99832ddb9bc99e710b74d31892932359"},"cell_type":"code","source":"import numpy as np\nfrom sklearn import metrics\n\nfpr, tpr, thresholds = metrics.roc_curve(val_targets, val_answers, pos_label=1)\n\nroc_auc = metrics.auc(fpr, tpr)\n\n# method I: plt\nplt.title('Receiver Operating Characteristic')\nplt.plot(fpr, tpr, 'b', label = 'AUC = %0.4f' % roc_auc)\nplt.legend(loc = 'lower right')\nplt.plot([0, 1], [0, 1],'r--')\nplt.xlim([0, 1])\nplt.ylim([0, 1])\nplt.ylabel('True Positive Rate')\nplt.xlabel('False Positive Rate')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"711eef339299b0f653f4bdbacec764f6adb252de"},"cell_type":"markdown","source":"#### Choose optimal threshold(by val set)"},{"metadata":{"trusted":false,"_uuid":"a78495cc5d61d13dc0fea20d3646b0216cc36db0"},"cell_type":"code","source":"f1s = []\npoints_to_check = thresholds[::15]\nfor _ in tqdm_notebook(points_to_check):\n    f1s.append(metrics.f1_score(val_targets, val_answers > _))\n\nbest_threshold = points_to_check[np.argmax(f1s)]\n\nplt.plot(points_to_check, f1s)\nplt.plot(best_threshold, np.max(f1s), marker='x', markersize=20)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"e003f6a682ee4a685c6f3c6969b078b76665d236"},"cell_type":"code","source":"print(np.argmax(f1s), np.max(f1s), best_threshold, np.mean(val_targets), np.mean(val_answers > best_threshold))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"32b4c425a7c142c470d6620526aa66a86ae3f821"},"cell_type":"code","source":"loss_func = torch.nn.BCELoss()\n\nif cuda:\n    loss_func = loss_func.cuda()\n\ntest_targets, test_answers, test_lengths, test_losses = apply_nn_to_batcher(best_model, test_ds, loss_func)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"699c6118779b8730fdb44e012016c14a9bfdd3d4"},"cell_type":"code","source":"print(metrics.f1_score(test_targets, test_answers > best_threshold))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"5750929173d55badad7bdf74b7a0d1157a382e09"},"cell_type":"code","source":"np.mean(test_targets), np.mean(test_answers > best_threshold), np.mean(val_losses), np.mean(test_losses)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"6860223b1eddf6e63450d2e020092ea1c2b799b0"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"a04c369ac5f392cbf11a2bec75fb96a046d1c1dd"},"cell_type":"code","source":"topred_answers, topred_lengths = \\\n    apply_nn_to_batcher(\n    best_model, \n    to_predict_iterator, \n    loss_func=None, \n    targets_enable=False\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"85735aac74663831c1ef1c3d37e6c3be135d99c2"},"cell_type":"code","source":"to_predict['prediction'] = list(map(lambda x: int(x > best_threshold), topred_answers))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"46c8bf0383c86cdd21933d02adb80419b3ce572e"},"cell_type":"code","source":"to_predict.prediction.mean()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"f475a23b24244c1b0cf80e30d5a8868e6d2d2f23"},"cell_type":"code","source":"to_predict.loc[to_predict.prediction == 1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"3bfcb7afbc1b5b2d2f0fb9b08e8e7045acb4ebe3"},"cell_type":"code","source":"to_predict[['qid', 'prediction']].to_csv('submission.csv', index=None, header=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"5cbf9589b37b15772e6870223e21a1dfecbd67d3"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.6"}},"nbformat":4,"nbformat_minor":1}