{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Name Entity Recognition(NER) using BERT:","metadata":{}},{"cell_type":"markdown","source":"![Image](https://confusedcoders.com/wp-content/uploads/2019/11/image2.png)","metadata":{}},{"cell_type":"markdown","source":"\nName Entity Recognition in short called NER is method of information extractions from the text data which comes under the NLP space. The most common entities that are extracted from the text data could be name of the person, Country, company, contact information like email-id, phone-no, home address etc.\n\nHowever NER tasks are not just limited to these standard entities, they could also be finetuned/trained to identify custom entities as per our need from the text data. \n\nThere are function in <B>NLTK</B> and <B>Spacy</B> that can be used for NER tasks. However in this tutorial we will be going through how can we identify the entities of our interest using <B>BERT</B> by using the method <B>BertForTokenClassification</B> from HuggingFace Transformer package using Pytorch","metadata":{}},{"cell_type":"markdown","source":"There are extensive tutorials available online to understand BERT. However you can check out Jay Alammar's blog on [A Visual Guide to Using BERT for the First Time](https://jalammar.github.io/a-visual-guide-to-using-bert-for-the-first-time/) which is one of the excellent way to learn BERT visually","metadata":{}},{"cell_type":"markdown","source":"# Why is it called Token Classification in Bert?\nWe know that in tasks like sequence classification, the entire sequence is classified to belong to 1 or 0 for binary classificationn and any 1 of the N classes for multiclass classfication. \n\nHowever in Token Classification every single token(i.e words) in the sequence is classified as 1 of the N classes. \n\nWhat do I mean by that? Assuming if it's a binary classification problem. If there is a sentence of 10 words, then each word is classified as 0 or 1, so the ouput dimension will be 10 * 2 with 2 being the probability of 0 and 1.\n\nIf it is a multiclass problem then the number of possible classes will be N and there will be N class probablilites for each token.","metadata":{"execution":{"iopub.status.busy":"2021-06-26T02:45:57.606109Z","iopub.execute_input":"2021-06-26T02:45:57.606533Z","iopub.status.idle":"2021-06-26T02:45:57.616319Z","shell.execute_reply.started":"2021-06-26T02:45:57.606449Z","shell.execute_reply":"2021-06-26T02:45:57.615371Z"}}},{"cell_type":"markdown","source":"![image.png](attachment:3e3909f4-313a-4a46-ac51-02384c1ddc6f.png)","metadata":{},"attachments":{"3e3909f4-313a-4a46-ac51-02384c1ddc6f.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAA5MAAAGpCAYAAAAQkWJrAAAgAElEQVR4AeydB7gURdaGUVd31TWSzeQgEiQI5kUyoiJBMCJIxoQJ05oFE+qac1rRdc0CgggomDGL6KoYfhUVzBkVz/98dTmXunW7e6on98xXz3Nvz3SfSm+drq6vq7qnhjCQAAmQAAmQAAmQAAmQAAmQAAmQQEwCNWLa05wESIAESIAESIAESIAESIAESIAEhGKSTkACJEACJEACJEACJEACJEACJBCbAMVkbGSMQAIkQAIkQAIkQAIkQAIkQAIkQDFJHyABEiABEiABEiABEiABEiABEohNgGIyNjJGIAESIAESIAESIAESIAESIAESoJikD5AACZAACZAACZAACZAACZAACcQmQDEZGxkjkAAJkAAJkAAJkAAJkAAJkAAJUEzSB0iABEiABEiABEiABEiABEiABGIToJiMjYwRSIAESIAESIAESIAESIAESIAEKCbpAyRAAiRAAiRAAiRAAiRAAiRAArEJUEzGRsYIJEACJEACJEACJEACJEACJEACFJP0ARIgARIgARIgARIgARIgARIggdgEKCZjI2MEEiABEiABEiABEiABEiABEiABikn6AAmQAAmQAAmQAAmQAAmQAAmQQGwCFJOxkTECCZAACZAACZAACZAACZAACZAAxSR9gARIgARIgARIgARIgARIgARIIDYBisnYyBiBBEiABEiABEiABEiABEiABEiAYlJE6tWrJzVq1OAfGRgfgD8wkAAJkAAJkAAJkAAJkAAJRBOgmBQxAiIaE4+WEwHcWGAgARIgARIgARIgARIgARKIJsBRM8VktIeU4VGKyTJsdFaZBEiABEiABEiABEggNgGKSYrJ2E5T6hEoJku9hVk/EiABEiABEiABEiCBbBCgmKSYzIYflVQaFJMl1ZysDAmQAAmQAAmQAAmQQI4IUExSTObItZKbLMVkctuOJScBEiABEiABEiABEsgfAYpJisn8eVtCcqKYTEhDsZgkQAIkQAIkQAIkQAIFJUAxSTFZUAcsxswpJouxVVgmEiABEiABEiABEiCBYiNAMUkxWWw+WfDyUEwWvAlYABIgARIgARIgARIggQQQoJikmEyAm+a3iBST+eXN3EiABEiABEiABEiABJJJgGIyIWJy7Nix0qhRo0ovu+uuuwSiZ+HC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FVn5E/C39BGTbp91xhlnVPbvuIEY1b/fc889pjDo37XPOumkkwT9+4477ljZ/yehf/enSksSIIFcEqCYzCVdpk0COSCQahCL45988olAQJ599tlmGSsGHw8//LDsvvvu5llJ2EyZMkW23HJLeeihh+Trr7+W9957T3CHu0+fPuYFP9dcc4106NBB7r33XsEs5/Lly81MaO/evWXJkiVGlCZdTKZidemllxqBFcQKs702Kyz5TTIruCp9y/+EJSuy8ifgbwm/ipqZDOqzfvjhh8r+XfusyZMnV+vf0Wf17du3sn9Hn4WZSe3fjz76aNH+HS9YK/b+3Z8qLUmABHJJgGIyl3SZNgnkgECqQSyy/P333+Wrr74yb1p9+eWXjcgZPXq0tG7d2ryBFWlgGdQee+wh33zzjSklnqu84oorzGACz2SecMIJ0qhRIznrrLMEAxS8sOfAAw80s50YaOBNssU+2MgXq+OPPz6U1dy5cxPBCk6QL170LZ6HbteY6z4rKechzsEoMenTv6MvxzPxbv/+r3/9q7J/R5/VuHFjc8PR7d/BasGCBUXfv7s+xO8kQAKFIUAxWRjuzJUE0ibgM+DHTOQNN9xghF/btm2NCDzooINkp512MstfMdiAmNxvv/0qy4E3ACIOXsozbdo0Ofjgg6VmzZqy9957m6Ww/fr1M3e1sez16aefTsRgo1hYPfnkk4kYmBULryQMZMmqsutI+YGsUiKqNACrVGISM5Hoq5s2bSrav+NGH/p3CEYVk2H9O35WKqp/f+aZZyQpfVYlOH4gARIoGAGKyYKhZ8YkkB4BHZhtv/32ctxxxwUm8uyzz0qXLl3Mi3Peeust+eCDD8xPeHTv3t3MNCINiEn7ba5I6KKLLpK99tpLXn31VZkwYULl548++sikgVlOvMUVS14fe+yxohdImbDq1q2bF6tXXnlFxo8fn3hWaP9MeNG3qp+KPA8rmNCvqvtG2B6wgphM1b/vvPPO1fp39Fl4tAFpuP079uE5efTv2mfBHn2927+vWLEiEf17GEPuJwESyC8Bisn88mZuJJAxAR1sYInS8OHD5aeffpJly5ZV/uENrLirjOdhrr76apMfnonE5/XWW8+IROzEMzXrr7++4C41lphhthHiEj83gu+wb9eunfz73/82z9QgDRzr37+/LF26VLAUCi9sgLgs1pBNVhts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PKSgrAB2//33S61ateQvf/lLFVY4L2vWrCnXXXcd32xr+RY/kgAJ5J8AxWT+mTNHEsgaAYjJNm3ayBFHHFElTQzErr76aqldu7Zcc801VY5h6R1mStyZJcTBMWxxHLOapbRMD2LylFNOkV69elXhgS+YEdlyyy1ln332qXYM8cDDHdziuzL79ddfq/GsllDCduAnKyCEMGNrB/jFLrvsIhtuuGG1WRH4FFi4fqOckA7il9pM3TvvvCP16tWTq666ykZlPp999tmG47x586r4EBiBlTuzBFZ6boJTEM9qmSRsx5AhQ2S33XYzqyfsomO2bYsttpDhw4fL8uXLKw+BCVgEnYfqa+BYiufhf/7zH9NngY0dcHNi4MCB0qpVK3n++eftQ8Z/wErZ6EFw1HOxFM9DrSe3JEAC+SVAMZlf3syNBLJKQMXk4YcfXi3dN954Q1q2bCnHHHOMOYZBxLfffitz5syRyy67TO6++275v//7v8oBx2effSbPPfecGZhAiGI2BUtoMUArhaBiskePHtWqA8E0btw4I771IAZjS5YskRtuuMHwwm9NKgvYQ4DiOJaCTpo0yfwG5ddff11FMGhaSdyqmMQPoLsBSxLXWmsteeWVV8wh+BZ86cEHH5STTz7ZLB3GckUEDGgXL14sTz/9tGAG75xzzpFLL73UfFbR5KaftO8qJi+//PJqS8u///572XzzzeWKK66o9B8si33sscfMzY1bb71VsKRYWXz11VdmCSh44kYQboDgPIQ/lkqAmMQNCfiDG/bcc08jnlB/BIieV199VcAWPonP2KcBHLGkHxzhe+jXSul3FSEme/bsKbgZ4Qb0TU2bNhXYIOBc++STT0xfhD5+1qxZAn/C+YmAPmvp0qXy7LPPyrnnnmuYfvjhh5W+Z4z4jwRIgARiEqCYjAmM5iRQTARUTB566KFmBgkiB38YyGN5VP369WXKlCmmyB9//LFAdOLO/6BBg2SnnXYySzsXLlxojuP5LiyZbdCggZmhww/P161bV84666xqsyfFxMC3LComu3XrVoUVeGFA1bp168qZSQzc77zzTll//fUF9gcffLBhicEqBv2ffvqpjBgxwgzkmjdvbj43bNjQDJAxmCuFoGISz2WpX2GLGRH8EDpmJjVggA8OuHkBodCsWTOBKMCgHnGOOuooI6gwezd+/HjZe++9ZeON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j4oIiIAI5DIBiclc7l21TQQiRIDMivvuu6+VL1/e7aNGohr2gGPfvFwXliThIcEFiWb8/ooR6rqkq8p6Pjab9/t7Jn0BnSACISGAcPR7Y/oqsW58woQJLqvuo48+6l/WbxEQARHISQISkznZrWqUCESTAAke2AqiVatWVrduXatQoYITmF26dDH2GczVDIKk2997771t6623trPPPtvYzP3rr7+OZicGqPW3335rxx57rFWqVMlmzpwZ4AwdIgLhIYBYJBENz2nPnj2tf//+hVYun6INCgWgF0VABPKCgMRkXnSzGikC0SJANkoyeLIdRNu2ba1+/fp2zz33bOEBiFariq4t3o0pU6bYZZdd5tpapUoVJyrHjBmTk9leae8777xjzZs313YfRZtFpN7Jh5DlJUuW2KRJk+zGG2+0Zs2aWcWKFa1WrVrWsWPHSPWVKisCIiAC6SQgMZlOmrqWCIhA2gn88ssv9tZbb9lXX31lmzdvLnD9N954w4VLvvrqqzmzdcTkyZOtc+fOVq9ePatatar16dPH8OTlYmGLlFzf/JyQXuw0V9u5fv16t//gXXfd5ba6yUU75TOIPWFPPPFE23777a169erOs84+lWwtkqvPZy72pdokAiKQfgISk+lnqiuKgAhkiEDfvn2d4Npxxx2tdevWdvvtt7vEF+xJGGVPCXXHM3vRRRe5QWwuh7xmyFSydpv777/feZsXLVqUtTqUxY2Z2GGSB68ckx4km8nVkGUmBA466CBr2rSpXXLJJTkfhl4W9qJrioAI5C4Bicnc7Vu1TARyngDJakaOHGmdOnVyA71tt93WEJYnnXSS9ejRw1avXh1pBgzYE72xNOjHH380QkVVwk0AEbLXXnvZHnvsYd988024K5tE7T755BO78847nfeckGwEJWHLUV7TzITNm2++6cKu165dW4AGzxrbfCxcuLDA6/pDBERABETATGJSViACIpATBBYsWOCEJZ4D1uIxiM/FPd7IbNuvXz/r3r27G8DnROeZuYy9L730Uk4lHnrqqadcEikyem7atCnyXUU45xNPPGFHHXWU80aecMIJ7m8mN6JYVq1a5QQkmYXbtWvnkn7VqFHD5s+fH8XmqM4iIAIikBUCEpNZwa6bioAIlCWBZcuW2dSpU421TvEFzwlru4YMGeK2HIniAJ+1d2S8rVy5su2zzz52yy232IwZM+KbGcn/I/x32203u+mmmyJZ/8RK45UkLLJOnTpuvW/i+1H8++OPP7YWLVpYo0aN7O6777YVK1ZEsRlGIp14Acl2RISxXnDBBTZs2DDbsGFDJNulSouACIhANghITGaDuu4pAiKQFQKISwQYWRgZEF9++eWG14i1X2vWrMlKnUpzUzxE7ElJOG+5cuWsYcOG1rt3bycqoxpqiJeI7ULwDJHUJOrlySefdF5JEij9/PPPUW+Oqz/hny+++KLbpifKDRo9erTbhufAAw+0Cy+80AYOHGjsc1tYSHmU26m6i4AIiEAmCEhMZoKy7iECIhAKAgwW3377bbfe64wzzrBdd93VtttuO5cghb/xWEapkOGWgXDLli1tq622cqKSzdLZBy9qhb4hgQvbwCD0WZcX1bJu3To79NBDnVcyqqHWTFiQyCqqhaiDadOmGYmPEkUiIfGDBw+2uXPnau1xVDtY9RYBEQgNAYnJ0HSFKiICIpBJAuxl+corr9gDDzzgvBOEuZ122mmZrELa7rV06VJ76KGHnKeSvSmjGL4LDETw0KFDnbe1Q4cOkd1XdNasWW77CLySGzduTFs/Z+JCeFHHjh3r9jnt0qVL5MQW4p1oA9ZOE4XQtWvXyPVBJvpZ9xABERCBdBGQmEwXSV1HBEQgsgQQX3gp5syZU6ANeDTI4njzzTcbyWEWL15c4P2w/YGnsjDxUthrYau7rw9rDVm7VqFCBRswYIB/OVK/6Qc8X1Hb0mX27Nluj9NddtnFeVVZXxyFrME8lyQ7uvLKK11yIEK/iTo4++yzbfjw4ZH01EfK4FVZERCBvCYgMZnX3a/Gi4AIFEcAMfnqq686T9nOO+/sssReffXVNmLECJfEo7hzw/IeSVNYG3rPPfeEXgx7ZiRIOeywwwzmYRfwvs5R/o3oZasP1hCynhgRxuRJYgKrMLZx/fr1duqpp1qlSpXctkDHH3+83Xrrre65JfpARQREQAREoGwJSEyWLV9dXQREIOIEGKyS7AYRSYKYmjVrGvtZHnPMMW4vS0Iaw1zmzZtnzZo1c4KYOt933332+eefh7nKbo0b2XjZK5QQXpWyIfD77787j3zr1q2NjKZHHHGEPf7446HdE5NnMXH9I9mNeTYRkCRukr2Uja3oqiIgAiJQFAGJyaLI6HUREAERSCCAl4z1ZGzHwV6WZFEljC7s5b333rO+ffu67Q9I1IMoZr9A9qwMc4mCZyzM/EqqG2KSTMZNmjSx66+/3vBih62sXLnSSCpF/VjTPGXKlC0EZa5kyw0be9VHBERABIIQkJgMQknHiIAIiEACgYULF7oNz5cvX17gHbwnCEzE2zvvvGNh2tCdNaH9+vVziUmqV69ubdu2NTKPqqROAGH29NNPu/Bn/h+Vgn1+8MEHha61zVYbVq9eHROQrVq1slq1asWiAd59990txGS26qn7ioAIiIAImElMygpEQAREII0EGAhfeumlLqx0r732svbt27sN3hGWYfEEEkJKspIjjzwyckli0thVab3Ua6+9ZiSuGTVqlIVxr0+SMJHpl0mQMBcyLJ9++ukuARDh5ITeXnvttfbMM8+4bT6iJNTDzFl1EwEREIF0EZCYTBdJXUcEREAE/n97C8IFBw0a5LYn2HfffV1SE4RlmzZt3Jq0MGRXxSM1f/78SGwjgoBgbSrZRVkjF8ZCCOY222xTaBhmtutLEimS6uy2227OLrNdn+Luj1cfbyQTMghz9htNXCdZ3Pl6TwREQAREILMEJCYzy1t3EwERyCMCeCJnzJhhjzzyiHXq1MkQlhdffLGx/UVYC15L9uYjm2eYCls/sOUDYbphK5MnT7aqVavaRRddZGHKIMqeizfccIPVq1fPKleubN26dXMhrdnmN3PmTOvdu7c99thjtnbt2gLV4e8FCxaExotfoHL6QwREQAREYAsCEpNbINELIiACIpB+AogMBtGsT0vcu4+kIiQYYcsREo5ksxCuueOOO1rdunWd8H355ZezWZ3YvRctWmRs+0DdwlInXzm8klWqVHFeyTCEYZKQhqy9hIiyZcbJJ5/sQlyzGWaN3d9///12/vnn23777ecmBthPNGp7cfo+128REAEREIE/CEhMyhJEQAREIMsEWA+GSKpWrZodffTRdsUVVzivzaeffprxmuE1nThxop133nluuwhEJR63MAg4PICsS2StJ163MJTXX3/dtttuO7vwwgtDEYL7008/2U033eT6rkGDBvboo49mbU9UwlOff/5569Chg+2///629dZbW+3ate2cc86xgQMH2ocffmi//vprGLpRdRABERABESglAYnJUoLTaSIgAiKQLgLffPONy17Zp08fa9GihRMnDLwbN25seG/IwprpsmrVKnvhhRfs3HPPdV4k1tuRtCfRq5rJeuFxw7vF9iaEDWd7SwiEEF4/vJIkWArD2j6YED7aq1cvI/NpNgsTE0xEbL/99m7N5uDBg+2NN94wbEtFBERABEQgNwhITOZGP6oVIiACOUAAMUK2TfbVI0yRrTsQcXgus1UY+LO3Jt6lU045JeuZSllTd9ZZZ7lkN4iTbBaSGO2zzz5OMLElTBgKYbabNm3KaGKlL7/80iZNmrSFt5h6IGjxKCucNQzWoTqIgAiIQPoJSEymn6muKAIiIAJpIcAg/e23395iHSUesWHDhln//v1dgp9MhAqylpPMmmFYEzh37lz729/+Zk2aNMnqPp5sAcIa0yVLlmTFKzlu3Djr3LlzVpL+IA5Z49uxY0dr2rSp28qD0FUVERABERCB/CIgMZlf/a3WioAI5AAB1sWRFZatKPbcc0+XmKZnz57G+r1ffvklYy1EWD744IMuSyjr3zJVEHGzZ8923jC8X/lWSOTEVh916tRx/Z+pDLKErRKm2r17dzv88MOtRo0aLiS7ZcuWdscdd1g21vjmW9+rvSIgAiIQNgISk2HrEdVHBERABEogwLpF9rJ8/PHH3TYeBx98sMvaueuuu9pxxx1n9957r3377bclXCU9b994441uTWWjRo2cqNR6uPRwLewq69ats9tuu81tMcM2Kf/6179s2rRpGfOKEspKAiTW8+KNvOWWW4w9LBcvXpzVtbSFsdJrIiACIiACmSEgMZkZzrqLCIiACJQJAbxS8+bNc1s/4DEig2ebNm3siy++KJP7JV6UUFz2gDzmmGOcqGQ7irvuuktJVhJBpfj3yJEjXRZbRCQZf5999lkjcVNZlTVr1mxxaTyPAwYMcBla+f/GjRu3OEYviIAIiIAI5BcBicn86m+1VgREIIcJbNiwwe1jyZ5+hMLGFxL7IPLYKgIBmO7CPpCISsQsggdRiQDKVCF5EQlxMlGGDh3qPIKE22airFixwqpWrerCWh9++GGXpKks7ouXs2/fvi5smq1hVq9eXeA2YVgvW6BC+kMEREAERCDrBCQms94FqoAIiIAIlD0Btq4gFLVy5cp24IEHui0/EJaIzHSW999/33mvDjjgALvuuuvSeekir0UymB49ergw27L2lpH8hwyueIG/++67IuuUzjdYq/jEE0/YrFmz0nlZd63p06e79Y4nnnii7b777laxYkWXQZg1kJkS52lvlC4oAiIgAiKQMQISkxlDrRuJgAiIQPYIIHymTp1qgwYNstatW7vEKeyPuN9++7m/X3755bRt++HXdH7++ecZafD333/v9sBECD300ENles/LL7/ceV5HjRpVJttvZCqBEl7su+++2+rVq2cVKlRwQvKKK66wp59+2t57772MCeUy7SxdXAREQAREoMwJSEyWOWLdQAREQATCQ4Bw0GXLljlhyT6N7du3t9q1a7tkPmWdGRUPW69evVw4bLqJfPTRR25NIRlO2a6jLAoia4899jCyly5fvjztt5g4caLby7Nbt25lnlSHvnjsscdcVmAEJB7XTCVtSjs4XVAEREAERCBrBCQms4ZeNxYBERCB7BLAg8h6PEQSyVwS18SNHj3a+vXrZ4TIpqOsX7/eDjvsMKtWrZpbl5fONZW0ZezYsW5d4UknneQEczrqHH8NPHesB33uuefS5sXl+oQad+rUyWVK3Wqrrdweooj+VAuTBmzdctFFF9kzzzxT4HJcH291WSbxKXBD/SECIiACIpCTBCQmc7Jb1SgREAERSJ1A7969XQjkX/7yF7evIOsS2R7i559/LtXFSVgzZ84ct76RPQqrV6/uRCWesXQUkg7deuutVr58ebdeMx2CzNeLevs9Pb/66iv/ckq/qR9bfTRs2NCJVETwW2+9tUXypGRuQvgqYrddu3YuGVKlSpWcwCY5kooIiIAIiIAImI8UvgAAECBJREFUpJuAxGS6iep6IiACIpAjBMj6On78eLvqqqtigmennXayxo0buwQ0K1euLFVL2c5kxowZMVGJsDzrrLOch7RUF4w7iTqxNQrZT5988sm4d1L772WXXeYEH97adGRxnTJlijVv3tzwRJKsaMyYMaX2puJRZn0qdSS5Us2aNV1d2XOUvUhnz55teIVVREAEREAERCDdBCQm001U1xMBERCBHCOAEFmwYIG9+eab1rNnT7dhPZk/E7eOSLbZXlSSGRXv3Lhx45K9RKHHk6GUcNp0ZpO99NJLje0y0rVWcvjw4S7pTZ8+fYw9G1MthMqy9vWoo45y2VkR6+w1mk7vbKp11PkiIAIiIAK5R0BiMvf6VC0SAREQgTIjQOZUvGAkbEmHh46Ksnbvk08+SZv37Ndff7XFixendT9NvLRsQcLazHSUtWvX2rx584xEOOkoZIFl7evSpUtTCpNNR110DREQAREQgfwhIDGZP32tloqACIiACIiACIiACIiACIhA2ghITKYNpS4kAiIgAiIgAiIgAiIgAiIgAvlDQGIyf/paLRUBERABERABERABERABERCBtBGQmEwbSl1IBERABERABERABERABERABPKHgMRk/vS1WioCIiACIiACIiACIiACIiACaSMgMZk2lLqQCIiACIiACIiACIiACIiACOQPAYnJ/OlrtVQEREAEREAEREAEREAEREAE0kZAYjJtKHUhERABERABERABERABERABEcgfAhKT+dPXaqkIiIAIFElg0aJFNm/evCLfT8cbv//+u/3666/uUr/88ks6LqlriIAIiIAIiIAIZJGAxGQW4evWIiACIpBtAj169LC6detatWrVbLvttrO//vWvdu+999rmzZtjVdt7773tzTffLPBa7M0k/oOYnDVrlh1wwAG2atWqJM7889DVq1fba6+9Zl9//fWfL6bwv08++cSmTJli//3vf1O4ik4VAREQAREQgfwkIDGZn/2uVouACIiAXXvttbbPPvvYPffcY/Pnz7ePPvrIunfvblWrVrUXX3zRfvvtN0fp0ksvtY8//tgQg6kUzn/77betSpUqtnLlylJdauLEiXbooYfal19+WarzE0+6+uqr7ZJLLrHvvvsu8S39LQIiIAIiIAIiUAIBickSAOltERABEchVAvXq1bMrrrjC1q9fH2vi999/b4cffrgddthh9sMPP8ReL+w/y5Yts6+++qqwt+zbb781vH7xBTH5zjvvOC9oopj86aefbOHChfGHF/r/SZMmOe/punXrCryP8CVUd8OGDQVeL+kPhPIFF1xgmzZtKvJQ3luwYIH7KeqgxYsXF+stJYQ41dDeDz/8sMT2MSFQVL/Bh3YUVWhDIteijtXrIiACIiACIgABiUnZgQiIgAjkKYEDDzzQTjjhhC0ExNq1a50w8qGueC8Jc6Wcc845hgDba6+9rE6dOk4YtmnTpoBQ6tWrl1WvXt15PRs2bGh9+vRxoa2cnygmV6xYYZy//fbbu2P23Xdfe+mllwrtkTfeeMN5TcuXL2/UnXBXylNPPWUIY8J1d999d7vssstioguv65FHHunCazl29uzZdtRRR9mjjz5qt912m22zzTa29dZb26mnnuq8s4k3fuWVV6xRo0Z28MEHG+G+3Nez4Nhp06a51+rXr+9YcO0vvvgidpnp06fbIYcc4s7fZZddbOjQoe46iGIKQvbOO++MrSXltQ4dOrhQY+8JHj58uOPN/WvUqGHnn39+zEtMeO4ee+xho0ePtpo1a9rOO+9s1OXZZ5+N1QHBf+yxx7o+IcSYUGY8vJSff/7ZBg8ebLvuuqu7B/zwWBclSGMX1X9EQAREQAREQGJSNiACIiAC+UuAUFZEBCLk5JNPtv79+xfquapYsWJMfCBKEH4TJkxwXkmusdVWW9njjz/uBM6oUaOsVq1aTughFJ955hkX1rrjjjs60F5MsmaS0FKEUfPmzc17OVmvuf/++xcq7BA+jzzyiBNLiMKNGzfa+PHjrUGDBk6QLV++3BBvtAVBRMHb2aJFC/vnP/9pS5YssTPPPNNatWrlwmS5/1lnnWVt27Z1Xk2fHMhbBF5O6nbdddcZbeGHa5100knGvb755htDLN94443u2ojI8847z9q1a2es7cSjiTi++OKL7fPPP7elS5day5YtrVy5cjZmzBh3G8Q861bjPaPHHHOM3XzzzY7ne++959aywpX78/dxxx1nXbt2defTBq5Hv+BZxPvYqVMnJzDx9vL+ueeea40bN3ZtRlj++9//du8zaYBY3m+//Vw/cf3XX3/diV/CnVVEQAREQAREoCQC8kyWREjvi4AIiECOEkA8IYDwjLVu3dp22GEH5/lr1qyZWz/pPWN477y3EDHEjxde/CYktm/fvva///3PTjzxRBc6672ahM3+4x//sEQxiRBDQOJpmzp1aozwmjVrnBhjLWNhZezYsc6zhhglPBcxilcxvgwbNsx5I99//32XNAivHess8eDRNgSTb9u//vUvJwALC4/l+ogwxCZrSikIWkJ4Cau94YYbrGnTpk5I+vsTRkpbEa4ww0MbH+5L/StVqhQTkwjT66+/voCYRCzi3aWOtA1xHF/wKpIwCd7UsUKFCvb888/HDqF92267rRPSMCaxEgx8gfELL7zg+pj1oqeccop/y/3Gq4lITleSowIX1x8iIAIiIAI5RUBiMqe6U40RAREQgeQJ4OHDg4U3beTIkS5sE28fQpASLyYROnjivBhDNOKtu/32250gQtggTn1BbBJSimikeM8knj3EFl41hBHv88P/8XQmCkR/PUQTYZqISYQSQgtxhneV8/lNffG2+XBURFfv3r3dve64444CWWk7duzoPHe0P7HQNkJMCfOtXLmy84givhCKFIQo90qsP23Ck/jggw+69afxoox1k4g775ksTEwi1r2YPOiggwzPsG8fbSSBEffAS0mYK+/zf1+YIOAY1k+S8Ij6JW77ApPPPvvMmjRpUuD63IdzCRv2/Px19VsEREAEREAEEglITCYS0d8iIAIikAcEZsyY4byIhDrGF0QGIayIQp+YJ1FMeqHDeQguQkERkwhHRBzhsr4gngjjJDSW4sUkIZWTJ0926xXvv/9+J67wiOFBw3tHuGphJV5MIuoIWUXMsgaR8/lBqLHdh08mQ4gp3kUEmA9p9dcuTkz6YxCaXA8RzXpE1k8SLnrllVe6NaeI5eeee87dm9/jxo1zwhwxiRiMF5N4QBPFJB7O+DDXv//97zExyRpM1qnCxbcPBrSX/uEnUUyS6Rbx++mnnzrBSHbe+ORG3mtMG2BHqC19Hn99hCSTCyoiIAIiIAIiUBwBicni6Og9ERABEchRAggtwjFJjuPFhW8q4ggBmayYJPTz9NNPd2LLXwuRhDjaaaed3EteTCJUEHmEY+L9o+DtRNwS9ok4LawgpPAUEiaLR5VkOwgu1gd6bymiiCRBXJ/XWPPIMffdd5/7jRj2BTFJqOyPP/7oX4r9Royx3nHOnDnuNdqC5xbP3cyZM51oJukP26ZQuBdrFtu3b+/CYufOneuEI8f6QggqCX+8ZxIh16VLl1gfwBD2PXv2dNdjTSdeYn997gFDkhYRcluSmERYkihpxIgRvgpubSXhuUOGDHHrK1mj6a+PLbAOlXZ7D2zsRP1HBERABERABBIISEwmANGfIiACIpAPBBAleNYQNoiJfv36ObF1zTXXOE/XrbfeGvOWEUbqs39yrBc6cEJ8INTIjEoh3JLjEZV33323E1aIo3gxiYAkTJUwWpLFELr55JNPOm9k586drXbt2i5LamH9gNcSDyMCERGHB40kQmeffbY7H9GE2EQM0UY8emQoxUuIGBw0aJDzLhKGSuH+u+22m2s/YbPxBbGG55N1k4hYxOEZZ5xhxx9/vBOq1J/srrSfRDZkmyVbKn+z9QnC8LTTTnPHIB5hSEZW6s/1KHBD1P/nP/9xnlrORaz6BDyst+Rvsr4iap9++mknDvmb9iEmyW7rBS/XREDSr347Eu7B2k0YI2aPPvpoVyfE+Msvv+wEL9ebNWuWPfzwwy6rK+G81F9FBERABERABIojIDFZHB29JwIiIAI5TAAxQUgmoZ9sn0FyGtbr4X2L99Sx76QPO7388sud4EDIUBCTeAFJeuMLHq1u3bq5DKqsnyQzKGsDKQgWBBbCjWvgIUV04r0k5JKsq4TgFiVkEKGEhVJXtgThOI4nS+sRRxzhMp2SrZRwUrKnIioJs/VbXfAbIUo78I7ifSQDKx7CeA9ifFvwHCLAYET9aIP35rL2k/aRTZX7X3jhhS6pkecDRxiw1pTkRKzZ9Al4qDthwAhHQoURkrSJtZhkreUa/JBIiPbBhx/ajyeWQjvxMsbvHwkj6kJ2VwqCE8YkIaKeV111lROcvEdYMyIY0QxTEjEhKD0vdwH9IwIiIAIiIAJFEJCYLAKMXhYBERCBfCCAoEGYIB74QfwgMOILr3lxhwCNX9/HcbzGeknOw/OHOOFvhBLXZGsK1v1R/P28GOM1jvX3xxsY/547Ke4fxJW/rq8Hx3Oer3/867SN4+MLf/v7cD3+H9/G+GN5n/YVVz9fH47h2MRCfXzd8CCynhFPpWfq3+cYGCYypg7xfRTfHt6j7vHMCnstnnFiHTmXa/g6cqyKCIiACIiACAQhIDEZhJKOEQEREAERKJEA4mjgwIEuTJWtJ/AYEhJLyCXhlCrmvIzwIFGPF5PiIgIiIAIiIAJRJSAxGdWeU71FQAREIIQE8HoNGDDAhYQSkkkyGtY1Sjj90VlkVSWcFSbx3sQQdqWqJAIiIAIiIAIlEpCYLBGRDhABERABEUiGgA/VRFgSkinR9Cc9QlDF5E8e+p8IiIAIiEC0CUhMRrv/VHsREAEREAEREAEREAEREAERyAoBicmsYNdNRUAEREAEREAEREAEREAERCDaBCQmo91/qr0IiIAIiIAIiIAIiIAIiIAIZIWAxGRWsOumIiACIiACIiACIiACIiACIhBtAhKT0e4/1V4EREAEREAEREAEREAEREAEskJAYjIr2HVTERABERABERABERABERABEYg2AYnJaPefai8CIiACIiACIiACIiACIiACWSEgMZkV7LqpCIiACIiACIiACIiACIiACESbgMRktPtPtRcBERABERABERABERABERCBrBCQmMwKdt1UBERABERABERABERABERABKJNQGIy2v2n2ouACIiACIiACIiACIiACIhAVghITGYFu24qAiIgAiIgAiIgAiIgAiIgAtEmIDEZ7f5T7UVABERABERABERABERABEQgKwQkJrOCXTcVAREQAREQAREQAREQAREQgWgTkJiMdv+p9iIgAiIgAiIgAiIgAiIgAiKQFQISk1nBrpuKgAiIgAiIgAiIgAiIgAiIQLQJSExGu/9UexEQAREQAREQAREQAREQARHICgGJyaxg101FQAREQAREQAREQAREQAREINoE/g9pgkwk+cZawAAAAABJRU5ErkJggg=="}}},{"cell_type":"markdown","source":"# About the data.\nThe data that we are going to be using for this tutorial is from the recently concluded \n[Coleridge Initiative - Show US the Data](https://www.kaggle.com/c/coleridgeinitiative-show-us-the-data) competition. The summary of the competition is to find the excerpt from the publication which represents the name of a dataset used for that particular analysis.\n\nThe textual information are from different publications, and each of them are stored as a json file with ids as unique key to identify them. The labels from publications are stored in the train.csv which we will use to label the textual documents from the publication. I would recommend you to go through the competition overview to understand in details about the data.","metadata":{}},{"cell_type":"markdown","source":"# Contents\n* Declare configurations\n* Reading the train dataset and preprocessing the text files\n* Tokenization and Data Labelling for the NER task\n* Define the DataLoader to batch the train dataset for training\n* Model training using BertForTokenClassification\n* Evaluation function to evaluate the model while training\n* Reading the test dataset\n* Prediction function to get the prediction for the test data\n* Result consolidation","metadata":{}},{"cell_type":"markdown","source":"#### I have written a similar notebook on how we can use Roberta for NER tasks. Do check this [notebook](https://www.kaggle.com/thanish/roberta-token-classification-training-inference) for the tutorial. Consider leaving an upvote if you like and comment for any questions :)\n","metadata":{}},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport json\nimport re\nfrom nltk.tokenize import sent_tokenize \nfrom transformers import BertTokenizer, AutoTokenizer\nfrom torch.utils.data import DataLoader\nimport torch\nimport torch.nn as nn\nimport transformers\nfrom tqdm import tqdm\nimport glob\nfrom sklearn.model_selection import train_test_split\nimport datetime \nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:20:23.806522Z","iopub.execute_input":"2021-06-27T03:20:23.806907Z","iopub.status.idle":"2021-06-27T03:20:26.824888Z","shell.execute_reply.started":"2021-06-27T03:20:23.806825Z","shell.execute_reply":"2021-06-27T03:20:26.824023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Config","metadata":{}},{"cell_type":"code","source":"platform = 'Kaggle'\nmodel_name = 'model1_bert_base_uncased.bin'\n\nif platform == 'Kaggle':\n    bert_path = '../input/huggingface-bert/bert-base-uncased/'\n    train_path = '/kaggle/input/coleridgeinitiative-show-us-the-data/train/'\n    test_path = '/kaggle/input/coleridgeinitiative-show-us-the-data/test/*'\n    model_path = '../input/coleridgemodels/'+ model_name\n    \nconfig = {'MAX_LEN':128,\n          'tokenizer': AutoTokenizer.from_pretrained(bert_path , do_lower_case=True),\n          'batch_size':5,\n          'Epoch': 1,\n          'train_path':train_path,\n          'test_path':test_path, \n          'device': 'cuda' if torch.cuda.is_available() else 'cpu',\n          'model_path':model_path,\n          'model_name':model_name\n         }","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:20:26.828404Z","iopub.execute_input":"2021-06-27T03:20:26.828642Z","iopub.status.idle":"2021-06-27T03:20:26.976670Z","shell.execute_reply.started":"2021-06-27T03:20:26.828618Z","shell.execute_reply":"2021-06-27T03:20:26.975815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Read the train data and combine the labels together","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv(\"../input/coleridgeinitiative-show-us-the-data/train.csv\")\n\ntrain_df = train.groupby(['Id']).agg(label_count = ('cleaned_label', 'count'),\n                                     label = ('cleaned_label', '|'.join)).reset_index()\ntrain_df","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:20:26.980139Z","iopub.execute_input":"2021-06-27T03:20:26.980396Z","iopub.status.idle":"2021-06-27T03:20:27.260777Z","shell.execute_reply.started":"2021-06-27T03:20:26.980370Z","shell.execute_reply":"2021-06-27T03:20:27.260015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Reading all the json train files","metadata":{}},{"cell_type":"code","source":"def read_all_json(df, path):\n    '''\n    This function reads all the json input files and \n    return a dictionary containing the id as the key and all the \n    contents of the json as values\n    '''\n    text_data = {}\n    for i, rec_id in tqdm(enumerate(df.Id), total = len(df.Id)):\n        location = f'{path}{rec_id}.json'\n\n        with open(location, 'r') as f:\n            text_data[rec_id] = json.load(f)\n        \n    print(\"All files read\")\n    \n    return text_data","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:20:27.262325Z","iopub.execute_input":"2021-06-27T03:20:27.262628Z","iopub.status.idle":"2021-06-27T03:20:27.271174Z","shell.execute_reply.started":"2021-06-27T03:20:27.262597Z","shell.execute_reply":"2021-06-27T03:20:27.270415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data_dict = read_all_json(df=train_df, path=config['train_path'])","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:20:27.272498Z","iopub.execute_input":"2021-06-27T03:20:27.272856Z","iopub.status.idle":"2021-06-27T03:21:47.324364Z","shell.execute_reply.started":"2021-06-27T03:20:27.272821Z","shell.execute_reply":"2021-06-27T03:21:47.323464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data cleaning and Joining functions","metadata":{"execution":{"iopub.status.busy":"2021-06-25T01:47:27.575446Z","iopub.execute_input":"2021-06-25T01:47:27.575806Z","iopub.status.idle":"2021-06-25T01:47:27.579859Z","shell.execute_reply.started":"2021-06-25T01:47:27.575767Z","shell.execute_reply":"2021-06-25T01:47:27.579032Z"}}},{"cell_type":"code","source":"def clean_text(txt):\n    '''\n    This is text cleaning function\n    '''\n    return re.sub('[^A-Za-z0-9]+', ' ', str(txt).lower())\n\ndef data_joining(data_dict_id):\n    '''\n    This function is to join all the text data from different \n    sections in the json to a single text file. \n    '''\n    data_length = len(data_dict_id)\n\n    #     temp = [clean_text(data_dict_id[i]['text']) for i in range(data_length)]\n    temp = [data_dict_id[i]['text'] for i in range(data_length)]\n    temp = '. '.join(temp)\n    \n    return temp\n\ndef make_shorter_sentence(sentence):\n    '''\n    This function is to split the long sentences into chunks of shorter sentences upto the \n    maximum length of words specified in config['MAX_LEN']\n    '''\n    sent_tokenized = sent_tokenize(sentence)\n    \n    max_length = config['MAX_LEN']\n    overlap = 20\n    \n    final_sentences = []\n    \n    for tokenized_sent in sent_tokenized:\n        sent_tokenized_clean = clean_text(tokenized_sent)\n        sent_tokenized_clean = sent_tokenized_clean.replace('.','').rstrip() \n        \n        tok_sent = sent_tokenized_clean.split(\" \")\n        \n        if len(tok_sent)<max_length:\n            final_sentences.append(sent_tokenized_clean)\n        else :\n#             print(\"Making shorter sentences\")\n            start = 0\n            end = len(tok_sent)\n            \n            for i in range(start, end, max_length-overlap):\n                temp = tok_sent[i: (i + max_length)]\n                final_sentences.append(\" \".join(i for i in temp))\n\n    return final_sentences","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:21:47.326012Z","iopub.execute_input":"2021-06-27T03:21:47.326603Z","iopub.status.idle":"2021-06-27T03:21:47.338430Z","shell.execute_reply.started":"2021-06-27T03:21:47.326562Z","shell.execute_reply":"2021-06-27T03:21:47.337630Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n","metadata":{}},{"cell_type":"markdown","source":"# Tokenization and Labeling the data\n\n### Bert tokenization:\nBefore we move into labelling, let's understand how Bert tokenizer works. Tokenization is nothing but splitting the sentence into words, however Bert tokenizer splits sentences into words that are in the vocabulary. If there are compound words or words that are not part of the vocabulary then Bert splits them into multiple sub-words with each subword except the first subword starting with <B>\"##\"</B>. \n\nCheck out this [blog](https://blog.floydhub.com/tokenization-nlp/) on different methods of tokenizer to understand why BERT tokenizes the sentence the way it does\n\n### Labelling\n\nThe function form_labels() is actually where we label the data to be fed to the algorithms later in the notebook. \n\nNote: The label will be an excerpt from the train text.\n\n<B>Example sentence</B>:\n\"control samples were selected from individuals who had participated in genomewide association studies performed by our group 787 samples from the neurogenetics collection at the coriell cell repository and 728 from the baltimore longitudinal study of aging blsa\"\n\n","metadata":{}},{"cell_type":"markdown","source":"<B>Label</B>:\n\"genomewide association studies\", \"baltimore longitudinal study of aging\".\nAs you could see there are two labels of interest to us from the example sentence.","metadata":{}},{"cell_type":"markdown","source":"<B>Portion to label</B>:\n\"control samples were selected from individuals who had participated in <B>genomewide association studies</B> performed by our group 787 samples from the neurogenetics collection at the coriell cell repository and 728 from the <B>baltimore longitudinal study of aging</B> blsa\"","metadata":{}},{"cell_type":"markdown","source":"### How do we do this?\n* Tokenize the train sentence.\n<br>['control', 'samples', 'were', 'selected', 'from', 'individuals', 'who', 'had', 'participated', 'in', 'genome', '##wide', 'association', 'studies', 'performed', 'by', 'our', 'group', '78', '##7', 'samples', 'from', 'the', 'ne', '##uro', '##gen', '##etic', '##s', 'collection', 'at', 'the', 'co', '##rie', '##ll', 'cell', 'repository', 'and', '72', '##8', 'from', 'the', 'baltimore', 'longitudinal', 'study', 'of', 'aging', 'b', '##ls', '##a']\n\n* Tokenize the labels\n<br>[['genome', '##wide', 'association', 'studies'], ['baltimore', 'longitudinal', 'study', 'of', 'aging']]\n\n* For each tokenized label, loop the tokenized train sentence and wherever you find a match label them as <B>'B'</B> and rest of them as <B>'O'</B>.\n\n    Since there are two labels we will loop the train sentence twice\n\n    At the end of the 1st loop for ['genome', '##wide', 'association', 'studies'], the label looks like this\n\n    ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B', 'B', 'B', 'B', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']\n\n    At the end of the 2nd loops for ['baltimore', 'longitudinal', 'study', 'of', 'aging'] the final label looks like this\n\n    ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B', 'B', 'B', 'B', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'B', 'B', 'B', 'B', 'B', 'O', 'O', 'O']\n\nMost tutorials follow a pattern of <B>BIO</B> labelling (B-begin, I-interior, O-outside) which is nothing but label the first word as <B>B</B>, last word as <B>O</B> and all the intermediate words as <B>I</B> and all others as some other character say <B>X</B>\n\nIf labelled in this format then our labels would look like\n\n['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'B', 'I', 'I', 'O', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'B', 'I', 'I', 'I', 'O', 'X', 'X', 'X']\n\nHowever I would like to stick to only labeling them as 'B' as I find it to be simple","metadata":{}},{"cell_type":"code","source":"def form_labels(sentence, labels_list):\n    '''\n    This function labels the training data \n    '''\n    matched_kwords = []\n    matched_token = []\n    un_matched_kwords = []\n    label = []\n\n    # Since there are many sentences which are more than 512 words,\n    # Let's make the max length to be 128 words per sentence.\n    tokens = make_shorter_sentence(sentence)\n    \n    for tok in tokens:    \n        tok_split = config['tokenizer'].tokenize(tok)\n        \n        z = np.array(['O'] * len(tok_split)) # Create final label == len(tokens) of each sentence\n        matched_keywords = 0 # Initially no kword matched    \n\n        for kword in labels_list:\n            if kword in tok: #This is to first check if the keyword is in the text and then go ahead\n                kword_split = config['tokenizer'].tokenize(kword)\n                for i in range(len(tok_split)):\n                    if tok_split[i: (i + len(kword_split))] == kword_split:\n                        matched_keywords += 1\n\n                        if (len(kword_split) == 1):\n                            z[i] = 'B'\n                        else:\n                            z[i] = 'B'\n                            z[(i+1) : (i+ len(kword_split))]= 'B'\n\n                        if matched_keywords >1:\n                            label[-1] = (z.tolist())\n                            matched_token[-1] = tok\n                            matched_kwords[-1].append(kword)\n                        else:\n                            label.append(z.tolist())\n                            matched_token.append(tok)\n                            matched_kwords.append([kword])\n                    else:\n                        un_matched_kwords.append(kword)\n                \n    return matched_token, matched_kwords, label, un_matched_kwords","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:21:47.339896Z","iopub.execute_input":"2021-06-27T03:21:47.340291Z","iopub.status.idle":"2021-06-27T03:21:47.353931Z","shell.execute_reply.started":"2021-06-27T03:21:47.340257Z","shell.execute_reply":"2021-06-27T03:21:47.352969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def labelling(dataset, data_dict):\n    '''\n    This function is to iterate each of the training data and get it labelled \n    from the form_labels() function.\n    '''\n    \n    Id_list_ = []\n    sentences_ = []\n    key_ = []\n    labels_ = []\n    un_mat = []\n    un_matched_reviews = 0\n\n    for i, Id in tqdm(enumerate(dataset.Id), total=len(dataset.Id)):\n\n        sentence = data_joining(data_dict[Id])\n        labels = train_df.label[train_df.Id == Id].tolist()[0].split(\"|\")\n\n        s, k, l, un_matched = form_labels(sentence=sentence, labels_list = labels)\n\n        if len(s) == 0:\n            un_matched_reviews += 1\n            un_mat.append(un_matched)\n        else: \n            sentences_.append(s)\n            key_.append(k)\n            labels_.append(l)\n            Id_list_.append([Id]*len(l))\n\n    print(\"Total unmatched keywords:\", un_matched_reviews)\n    sentences = [item for sublist in sentences_ for item in sublist]\n    final_labels = [item for sublist in labels_ for item in sublist]\n    keywords = [item for sublist in key_ for item in sublist]\n    Id_list = [item for sublist in Id_list_ for item in sublist]\n    \n    return sentences, final_labels, keywords, Id_list\n","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:21:47.357639Z","iopub.execute_input":"2021-06-27T03:21:47.358022Z","iopub.status.idle":"2021-06-27T03:21:47.371112Z","shell.execute_reply.started":"2021-06-27T03:21:47.357987Z","shell.execute_reply":"2021-06-27T03:21:47.370089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_sentences, train_labels, train_keywords, train_Id_list = labelling(dataset = train_df, \n                                                                         data_dict=train_data_dict)\n\nprint(\"\")\nprint(f\" train sentences: {len(train_sentences)}, train label: {len(train_labels)}, train keywords: {len(train_keywords)}, train_id list: {len(train_Id_list)}\")","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:21:47.380090Z","iopub.execute_input":"2021-06-27T03:21:47.380531Z","iopub.status.idle":"2021-06-27T03:53:28.215283Z","shell.execute_reply.started":"2021-06-27T03:21:47.380497Z","shell.execute_reply":"2021-06-27T03:53:28.214394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create DataFrame to remove the duplicates","metadata":{}},{"cell_type":"code","source":"unique_df = pd.DataFrame({'id':train_Id_list, \n                          'train_sentences': train_sentences, \n                          'kword': train_keywords, \n                          'label':train_labels})\nunique_df.label = unique_df.label.astype('str')\nunique_df.kword = unique_df.kword.astype('str')\nunique_df['sent_len'] = unique_df.train_sentences.apply(lambda x : len(x.split(\" \")))\nunique_df = unique_df.drop_duplicates()\nprint(unique_df.shape)\nunique_df","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:28.219166Z","iopub.execute_input":"2021-06-27T03:53:28.221197Z","iopub.status.idle":"2021-06-27T03:53:29.127153Z","shell.execute_reply.started":"2021-06-27T03:53:28.221160Z","shell.execute_reply":"2021-06-27T03:53:29.126294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Taking a sample of the dataset\nLet's take only a small sample of the data (0.05%) in this tutorial to train a model for experimentation. You can use the entire dataset or whatever sample size you want","metadata":{}},{"cell_type":"code","source":"unique_df = unique_df.sample(int(unique_df.shape[0]*0.10)).reset_index(drop=True)\nunique_df.shape","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.131051Z","iopub.execute_input":"2021-06-27T03:53:29.133337Z","iopub.status.idle":"2021-06-27T03:53:29.149011Z","shell.execute_reply.started":"2021-06-27T03:53:29.133298Z","shell.execute_reply":"2021-06-27T03:53:29.147917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train and validation split","metadata":{}},{"cell_type":"code","source":"np.random.seed(100)\ntrain_df, valid_df = train_test_split(unique_df, test_size=0.2)\n\ntrain_df = train_df.reset_index(drop=True)\nvalid_df = valid_df.reset_index(drop=True)\n\nprint(train_df.shape, valid_df.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.153725Z","iopub.execute_input":"2021-06-27T03:53:29.155878Z","iopub.status.idle":"2021-06-27T03:53:29.169194Z","shell.execute_reply.started":"2021-06-27T03:53:29.155842Z","shell.execute_reply":"2021-06-27T03:53:29.168324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Converting the DataFrame back to list","metadata":{}},{"cell_type":"code","source":"print(\"Let's look at a simple example\")\nprint(\"Train sentence:\", unique_df.train_sentences[0])\nprint(\"Train label:\", unique_df.kword[0])\nprint(\"Train label:\", unique_df.label[0])","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.173772Z","iopub.execute_input":"2021-06-27T03:53:29.175947Z","iopub.status.idle":"2021-06-27T03:53:29.188339Z","shell.execute_reply.started":"2021-06-27T03:53:29.175898Z","shell.execute_reply":"2021-06-27T03:53:29.187251Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We have labelled all our train dataset and our labelled positions are denoted as <B>B</B>. However when we have to pass it to the model we will have to convert them into numerical representation.\n\nWe will convert them as follows: {<B>'O'</B>: 0 , <B>'B'</B>: 1, <B>'P'</B>: 2}\n\nHere <B>P</B> means padding which is appended to our train and label when the total word count in the sentence is not equal to the mentioned <B>MAX_LEN</B> in config. We will add the padding in the class <B>form_input()</B>","metadata":{}},{"cell_type":"code","source":"tags_2_idx = {'O': 0 , 'B': 1, 'P': 2} # 'P' means padding. \n\ndef dataset_2_list(df):\n    id_list = df.id.values.tolist()\n    sentences_list = df.train_sentences.values.tolist()\n    keywords_list = df.kword.apply(lambda x : eval(x)).values.tolist()\n    \n    labels_list = df.label.apply(lambda x : eval(x)).values.tolist()    \n    labels_list = [list(map(tags_2_idx.get, lab)) for lab in labels_list]\n    \n    return id_list, sentences_list, keywords_list, labels_list\n\nfinal_train_id_list, final_train_sentences, final_train_keywords, final_train_labels = dataset_2_list(df=train_df)\nfinal_valid_id_list, final_valid_sentences, final_valid_keywords, final_valid_labels = dataset_2_list(df=valid_df)","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.192792Z","iopub.execute_input":"2021-06-27T03:53:29.194911Z","iopub.status.idle":"2021-06-27T03:53:29.669454Z","shell.execute_reply.started":"2021-06-27T03:53:29.194874Z","shell.execute_reply":"2021-06-27T03:53:29.668572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Forming the input and defining the dataloader","metadata":{}},{"cell_type":"markdown","source":"One added information to note is we have set the Max_length to be 128 words per sentence. \nHowever when we tokenize it, due to Bert's way of splitting non-vocab and compound words into multiple sub-words, the no.of tokens could be more than the no. of words. If the number of tokens is <128 then the extra positions are padded with <B>\"P\"</B>, However if they exceed the Max_Length we truncate them to 128 tokens at this portion of the code which is a common practice.\n\n```\nif len(toks)>self.max_length:\n    toks = toks[:self.max_length]\n    label = label[:self.max_length]\n```\n\nDo you feel there could be information loss due to the truncation? Well if you check <B>make_shorter_sentence(sentence)</B> function there is a variable <B>overlap=20</B>, So the begining of every sentence is from the last 20 words from the previous sentence. So the tokens truncated in the sentence1 could be captured in the sentence 2.","metadata":{}},{"cell_type":"code","source":"class form_input():\n    def __init__(self, ID, sentence, kword, label, data_type='test'):\n        self.id = ID\n        self.sentence = sentence\n        self.kword = kword\n        self.label = label\n        self.max_length = config['MAX_LEN']\n        self.tokenizer = config['tokenizer']\n        self.data_type = data_type\n    \n    def __len__(self):\n        return len(self.sentence)\n    \n    def __getitem__(self, item):\n        toks = config['tokenizer'].tokenize(self.sentence[item])\n        label = self.label[item]\n\n        if len(toks)>self.max_length:\n            toks = toks[:self.max_length]\n            label = label[:self.max_length]\n        \n        \n        ########################################\n        # Forming the inputs\n        ids = config['tokenizer'].convert_tokens_to_ids(toks)\n        tok_type_id = [0] * len(ids)\n        att_mask = [1] * len(ids)\n        \n        # Padding\n        pad_len = self.max_length - len(ids)        \n        ids = ids + [2] * pad_len\n        tok_type_id = tok_type_id + [0] * pad_len\n        att_mask = att_mask + [0] * pad_len\n        \n        ########################################            \n        # Forming the label\n        if self.data_type !='test':\n            label = label + [2]*pad_len\n        else:\n            label = 1\n            \n        \n        return {'ids': torch.tensor(ids, dtype = torch.long),\n                'tok_type_id': torch.tensor(tok_type_id, dtype = torch.long),\n                'att_mask': torch.tensor(att_mask, dtype = torch.long),\n                'target': torch.tensor(label, dtype = torch.long)\n               }\n            ","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.673779Z","iopub.execute_input":"2021-06-27T03:53:29.675830Z","iopub.status.idle":"2021-06-27T03:53:29.691314Z","shell.execute_reply.started":"2021-06-27T03:53:29.675791Z","shell.execute_reply":"2021-06-27T03:53:29.690297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_prod_input = form_input(ID=final_train_id_list, \n                              sentence=final_train_sentences, \n                              kword=final_train_keywords, \n                              label=final_train_labels, \n                              data_type='train')\n\nvalid_prod_input = form_input(ID=final_valid_id_list, \n                              sentence=final_valid_sentences, \n                              kword=final_valid_keywords, \n                              label=final_valid_labels, \n                              data_type='valid')\n\ntrain_prod_input_data_loader = DataLoader(train_prod_input, \n                                          batch_size= config['batch_size'], \n                                          shuffle=True)\n\nvalid_prod_input_data_loader = DataLoader(valid_prod_input, \n                                          batch_size= config['batch_size'], \n                                          shuffle=True)\n","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.695799Z","iopub.execute_input":"2021-06-27T03:53:29.698698Z","iopub.status.idle":"2021-06-27T03:53:29.708431Z","shell.execute_reply.started":"2021-06-27T03:53:29.698662Z","shell.execute_reply":"2021-06-27T03:53:29.707362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Checking a sample input\nind = 1\nprint(\"Input sentence:\")\nprint(final_train_sentences[ind])\n\nprint(\"\")\nprint(\"Input label:\")\nprint(final_train_keywords[ind])\n\nprint(\"\")\nprint(\"Output:\")\ntrain_prod_input[ind]#, valid_prod_input[ind]","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.712862Z","iopub.execute_input":"2021-06-27T03:53:29.715733Z","iopub.status.idle":"2021-06-27T03:53:29.764351Z","shell.execute_reply.started":"2021-06-27T03:53:29.715553Z","shell.execute_reply":"2021-06-27T03:53:29.763580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As we can see that the input sentence we passed to the function returned a dictionary of \n```ids, tok_type_ids, att_mask, target```.\n\nThe <B>ids</B> contains some numbers which is nothing but the index position of the tokens in the Bert vocabulary. \nIf you want to know how the values are obtained in the <B>ids</B> I would recommend downloading the vocab.txt from [HuggingFace repo](https://huggingface.co/bert-base-uncased/tree/main) and checking the index with respect to the token starting from 0. \n\nI have shown the token ids for the first 5 words of an example sentence (<B>\"2 comparsions with the most\"</B>) in the screenshot below. The <B>2</B> in the ids are nothing but padded value.\n\nThe <B>att_mask</B> contains <B>1</B> for the all the tokens positions and <B>0</B> for all the padded positsion, so the model give attention to the tokens and not the padded positions.\n\n<B>tok_type_id</B> is not required for this task so we can skip them.\n\n\n<B>target</B> as we saw before are lablled as <B>1</B> for the label positions(\"survey of doctorate recipients\"), <B>0</B> for the others and <B>2</B> for the padded positions. \n\n![image.png](attachment:1bb33830-8139-4f37-bd6f-00398dbd846e.png)","metadata":{},"attachments":{"1bb33830-8139-4f37-bd6f-00398dbd846e.png":{"image/png":"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"}}},{"cell_type":"markdown","source":"# Training section","metadata":{}},{"cell_type":"code","source":"def train_fn(data_loader, model, optimizer):\n    '''\n    Functiont to train the model\n    '''\n    \n    train_loss = 0\n    for index, dataset in enumerate(tqdm(data_loader, total = len(data_loader))):\n        batch_input_ids = dataset['ids'].to(config['device'], dtype = torch.long)\n        batch_att_mask = dataset['att_mask'].to(config['device'], dtype = torch.long)\n        batch_tok_type_id = dataset['tok_type_id'].to(config['device'], dtype = torch.long)\n        batch_target = dataset['target'].to(config['device'], dtype = torch.long)\n                \n        output = model(batch_input_ids, \n                       token_type_ids=None,\n                       attention_mask=batch_att_mask,\n                       labels=batch_target)\n        \n        step_loss = output[0]\n        prediction = output[1]\n        \n        step_loss.sum().backward()\n        optimizer.step()        \n        train_loss += step_loss\n        optimizer.zero_grad()\n        \n    return train_loss.sum()","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.767927Z","iopub.execute_input":"2021-06-27T03:53:29.769860Z","iopub.status.idle":"2021-06-27T03:53:29.780018Z","shell.execute_reply.started":"2021-06-27T03:53:29.769826Z","shell.execute_reply":"2021-06-27T03:53:29.779031Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def eval_fn(data_loader, model):\n    '''\n    Functiont to evaluate the model on each epoch. \n    We can also use Jaccard metric to see the performance on each epoch.\n    '''\n    \n    model.eval()\n    \n    eval_loss = 0\n    predictions = np.array([], dtype = np.int64).reshape(0, config['MAX_LEN'])\n    true_labels = np.array([], dtype = np.int64).reshape(0, config['MAX_LEN'])\n    \n    with torch.no_grad():\n        for index, dataset in enumerate(tqdm(data_loader, total = len(data_loader))):\n            batch_input_ids = dataset['ids'].to(config['device'], dtype = torch.long)\n            batch_att_mask = dataset['att_mask'].to(config['device'], dtype = torch.long)\n            batch_tok_type_id = dataset['tok_type_id'].to(config['device'], dtype = torch.long)\n            batch_target = dataset['target'].to(config['device'], dtype = torch.long)\n\n            output = model(batch_input_ids, \n                           token_type_ids=None,\n                           attention_mask=batch_att_mask,\n                           labels=batch_target)\n\n            step_loss = output[0]\n            eval_prediction = output[1]\n\n            eval_loss += step_loss\n            \n            eval_prediction = np.argmax(eval_prediction.detach().to('cpu').numpy(), axis = 2)\n            actual = batch_target.to('cpu').numpy()\n            \n            predictions = np.concatenate((predictions, eval_prediction), axis = 0)\n            true_labels = np.concatenate((true_labels, actual), axis = 0)\n            \n    return eval_loss.sum(), predictions, true_labels","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.784659Z","iopub.execute_input":"2021-06-27T03:53:29.787517Z","iopub.status.idle":"2021-06-27T03:53:29.803157Z","shell.execute_reply.started":"2021-06-27T03:53:29.787477Z","shell.execute_reply":"2021-06-27T03:53:29.801995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model initialization and train\n\nWe have initialized the model in the function below as\n\n```\nmodel = transformers.BertForTokenClassification.from_pretrained('bert-base-uncased',  num_labels = len(tags_2_idx))\n```\n\n<U>Note</U>: \nDo you know why the label ```num_labels = len(tags_2_idx)```? because we have only 3 classes <B>[O, B, P]</B> so each of the token can be classified as any of the 3 i.e.\n```tags_2_idx={'O':0 , 'B':1, 'P':2}```\n\nHowever if we had labelled them in the <B>BIO</B> format then there would be 5 classes <B>[X, B, I, O, P]</B> then ```tags_2_idx={'X':0 , 'B':1, 'I':2, 'O':3, 'P':5}``` so num_labels would have been ```num_labels = 5```","metadata":{}},{"cell_type":"code","source":"def train_engine(epoch, train_data, valid_data):\n    model = transformers.BertForTokenClassification.from_pretrained('bert-base-uncased',  num_labels = len(tags_2_idx))\n    model = nn.DataParallel(model)\n    model = model.to(config['device'])\n    \n    params = model.parameters()\n    optimizer = torch.optim.Adam(params, lr= 3e-5)\n    \n    best_eval_loss = 1000000\n    for i in range(epoch):\n        train_loss = train_fn(data_loader = train_data, \n                              model=model, \n                              optimizer=optimizer)\n        eval_loss, eval_predictions, true_labels = eval_fn(data_loader = valid_data, \n                                                           model=model)\n        \n        print(f\"Epoch {i} , Train loss: {train_loss}, Eval loss: {eval_loss}\")\n\n        if eval_loss < best_eval_loss:\n            best_eval_loss = eval_loss           \n            \n            print(\"Saving the model\")\n            torch.save(model.state_dict(), config['model_name'])\n            \n    return model, eval_predictions, true_labels ","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.807791Z","iopub.execute_input":"2021-06-27T03:53:29.810670Z","iopub.status.idle":"2021-06-27T03:53:29.822730Z","shell.execute_reply.started":"2021-06-27T03:53:29.810633Z","shell.execute_reply":"2021-06-27T03:53:29.821586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model, val_predictions, val_true_labels = train_engine(epoch=config['Epoch'],\n                                                       train_data=train_prod_input_data_loader, \n                                                       valid_data=valid_prod_input_data_loader)","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:53:29.831345Z","iopub.execute_input":"2021-06-27T03:53:29.834080Z","iopub.status.idle":"2021-06-27T03:56:59.491286Z","shell.execute_reply.started":"2021-06-27T03:53:29.834044Z","shell.execute_reply":"2021-06-27T03:56:59.490216Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Reading the test data","metadata":{}},{"cell_type":"code","source":"def read_test_json(test_data_folder):\n    '''\n    This function reads all the json input files and return a dictionary containing the id as the key\n    and all the contents of the json as values\n    '''\n\n    test_text_data = {}\n    total_files = len(glob.glob(test_data_folder))\n    \n    for i, test_json_loc in enumerate(glob.glob(test_data_folder)):\n        filename = test_json_loc.split(\"/\")[-1][:-5]\n\n        with open(test_json_loc, 'r') as f:\n            test_text_data[filename] = json.load(f)\n\n        if (i%1000) == 0:\n            print(f\"Completed {i}/{total_files}\")\n\n    print(\"All files read\")\n    return test_text_data","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:56:59.568834Z","iopub.execute_input":"2021-06-27T03:56:59.569328Z","iopub.status.idle":"2021-06-27T03:56:59.576519Z","shell.execute_reply.started":"2021-06-27T03:56:59.569291Z","shell.execute_reply":"2021-06-27T03:56:59.575790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data_dict = read_test_json(test_data_folder=config['test_path'])","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:56:59.577622Z","iopub.execute_input":"2021-06-27T03:56:59.578125Z","iopub.status.idle":"2021-06-27T03:56:59.632569Z","shell.execute_reply.started":"2021-06-27T03:56:59.578088Z","shell.execute_reply":"2021-06-27T03:56:59.631403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prediction function\n\nFor the prediction part we pass the text data sentence.\n\n<U>Example test input:</U> \n```\n\"in section 5 the proposed method is illustrated by analyzing a diffusion tensor imaging dti data set from the alzheimer disease neuroimaging initiative adni database\"\n```\n<U>Tokenize the input text</U>:\n```\n['in', 'section', '5', 'the', 'proposed', 'method', 'is', 'illustrated', 'by', 'analyzing', 'a', 'diffusion', 'tensor', 'imaging', 'dt', '##i', 'data', 'set', 'from', 'the', 'alzheimer', 'disease', 'ne', '##uro', '##ima', '##ging', 'initiative', 'ad', '##ni', 'database']\n ```\n<U>Get the token ids</U>:\n```\n[1999, 2930, 1019, 1996, 3818, 4118, 2003, 7203, 2011, 20253, 1037, 19241, 23435, 12126, 26718, 2072, 2951, 2275, 2013, 1996, 21901, 4295, 11265, 10976, 9581, 4726, 6349, 4748, 3490, 7809]\n```\n\n<U>Prediction output</U>: \n\nThe token Ids are passed to the trained model which outputs the predicted probabilites for each token and the argmax is taken to get the class with max probability and it looks like this.\n```\n[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n```\n<U>Final predicted keyword</U>:\n\nCompare the prediction and the test input tokenized text. Get all the tokens that are predicted as <B>1</B> from the test input Tokenized text which is \n\n<B>[['tensor', 'imaging', 'dt', '##i', 'data', 'set'], ['alzheimer', 'disease', 'ne', '##uro', '##ima', '##ging', 'initiative', 'ad', '##ni', 'database']]</B>. \n\nCombine the subwords with <B>\"##\"</B>, Separate each element in the list by spaces and return them as the identified entity by the model \n\n<B>\"tensor imaging dti data set\", \"alzheimer disease neuroimaging initiative adni database\"</B>\n\n<U>Note</U>: If you labelled your dataset in the <B>BIO</B> format then you will have to modify the <B>prediction_fn()</B> function accordingly","metadata":{}},{"cell_type":"code","source":"# Prediction\ndef prediction_fn(tokenized_sub_sentence):\n\n    tkns = tokenized_sub_sentence\n    indexed_tokens = config['tokenizer'].convert_tokens_to_ids(tkns)\n    segments_ids = [0] * len(indexed_tokens)\n\n    tokens_tensor = torch.tensor([indexed_tokens]).to(config['device'])\n    segments_tensors = torch.tensor([segments_ids]).to(config['device'])\n    \n    model.eval()\n    with torch.no_grad():\n        logit = model(tokens_tensor, \n                      token_type_ids=None,\n                      attention_mask=segments_tensors)\n\n        logit_new = logit[0].argmax(2).detach().cpu().numpy().tolist()\n        prediction = logit_new[0]\n\n        kword = ''\n        kword_list = []\n\n        for k, j in enumerate(prediction):\n            if (len(prediction)>1):\n\n                if (j!=0) & (k==0):\n                    #if it's the first word in the first position\n                    #print('At begin first word')\n                    begin = tkns[k]\n                    kword = begin\n\n                elif (j!=0) & (k>=1) & (prediction[k-1]==0):\n                    #begin word is in the middle of the sentence\n                    begin = tkns[k]\n                    previous = tkns[k-1]\n\n                    if begin.startswith('##'):\n                        kword = previous + begin[2:]\n                    else:\n                        kword = begin\n\n                    if k == (len(prediction) - 1):\n                        #print('begin and end word is the last word of the sentence')\n                        kword_list.append(kword.rstrip().lstrip())\n\n                elif (j!=0) & (k>=1) & (prediction[k-1]!=0):\n                    # intermediate word of the same keyword\n                    inter = tkns[k]\n\n                    if inter.startswith('##'):\n                        kword = kword + \"\" + inter[2:]\n                    else:\n                        kword = kword + \" \" + inter\n\n\n                    if k == (len(prediction) - 1):\n                        #print('begin and end')\n                        kword_list.append(kword.rstrip().lstrip())\n\n                elif (j==0) & (k>=1) & (prediction[k-1] !=0):\n                    # End of a keywords but not end of sentence.\n                    kword_list.append(kword.rstrip().lstrip())\n                    kword = ''\n                    inter = ''\n            else:\n                if (j!=0):\n                    begin = tkns[k]\n                    kword = begin\n                    kword_list.append(kword.rstrip().lstrip())\n\n    return kword_list","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:56:59.633906Z","iopub.execute_input":"2021-06-27T03:56:59.634295Z","iopub.status.idle":"2021-06-27T03:56:59.667009Z","shell.execute_reply.started":"2021-06-27T03:56:59.634247Z","shell.execute_reply":"2021-06-27T03:56:59.665330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def long_sent_split(long_tokens):\n    '''\n    If the token length is >the max length this function splits it into \n    mutiple list of specified smaller max_length\n    '''\n    \n    start = 0\n    end = len(long_tokens)\n    max_length = 64\n\n    final_long_tok_split = []\n    for i in range(start, end, max_length):\n        temp = long_tokens[i: (i + max_length)]\n        final_long_tok_split.append(temp)\n    return final_long_tok_split","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:56:59.670589Z","iopub.execute_input":"2021-06-27T03:56:59.671008Z","iopub.status.idle":"2021-06-27T03:56:59.683075Z","shell.execute_reply.started":"2021-06-27T03:56:59.670947Z","shell.execute_reply":"2021-06-27T03:56:59.682144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_predictions(data_dict):\n    \n    results = {}\n\n    for i, Id in enumerate(data_dict.keys()):\n        current_id_predictions = []\n        \n#         print(Id)\n        sentences = data_joining(data_dict[Id])\n        sentence_tokens = sent_tokenize(sentences)\n        \n        for sub_sentence in sentence_tokens:\n            cleaned_sub_sentence = clean_text(sub_sentence)\n        \n            # Tokenize the sentence\n            tokenized_sub_sentence = config['tokenizer'].tokenize(cleaned_sub_sentence)\n            \n            if len(tokenized_sub_sentence) == 0:\n                # If the tokenized sentence are empty\n                sub_sentence_prediction_kword_list = []\n                \n            elif len(tokenized_sub_sentence) <= 512:\n                # If the tokenized sentence are less than 512\n                sub_sentence_prediction_kword_list = prediction_fn(tokenized_sub_sentence)\n\n            else:\n                # If the tokenized sentence are >512 which is long sentences\n                long_sent_kword_list = []\n                \n                tokenized_sub_sentence_tok_split = long_sent_split(tokenized_sub_sentence)\n                for i, sent_tok in enumerate(tokenized_sub_sentence_tok_split):\n                    if len(sent_tok) != 0:\n                        kword_list = prediction_fn(sent_tok)\n                        long_sent_kword_list.append(kword_list)\n                flat_long_sent_kword = [item for sublist in long_sent_kword_list for item in sublist]\n                sub_sentence_prediction_kword_list = flat_long_sent_kword\n                            \n            if len(sub_sentence_prediction_kword_list) !=0:\n                current_id_predictions = current_id_predictions + sub_sentence_prediction_kword_list\n\n        results[Id] = list(set(current_id_predictions))\n                \n    print(\"All predictions completed\")\n    \n    return results","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:56:59.684387Z","iopub.execute_input":"2021-06-27T03:56:59.685011Z","iopub.status.idle":"2021-06-27T03:56:59.697264Z","shell.execute_reply.started":"2021-06-27T03:56:59.684971Z","shell.execute_reply":"2021-06-27T03:56:59.696389Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"results = get_predictions(data_dict = test_data_dict)","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:56:59.699570Z","iopub.execute_input":"2021-06-27T03:56:59.700806Z","iopub.status.idle":"2021-06-27T03:57:48.751260Z","shell.execute_reply.started":"2021-06-27T03:56:59.700769Z","shell.execute_reply":"2021-06-27T03:57:48.749818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.DataFrame({'Id': list(results.keys()),\n                       'PredictionString': list(results.values())})\nsub_df.PredictionString = sub_df.PredictionString.apply(lambda x : \"|\".join(x))\nsub_df","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:57:48.752569Z","iopub.execute_input":"2021-06-27T03:57:48.752909Z","iopub.status.idle":"2021-06-27T03:57:48.764494Z","shell.execute_reply.started":"2021-06-27T03:57:48.752871Z","shell.execute_reply":"2021-06-27T03:57:48.763522Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2021-06-27T03:57:48.765831Z","iopub.execute_input":"2021-06-27T03:57:48.766538Z","iopub.status.idle":"2021-06-27T03:57:48.890593Z","shell.execute_reply.started":"2021-06-27T03:57:48.766360Z","shell.execute_reply":"2021-06-27T03:57:48.889706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# --------- Do upvote if you like :) ---------","metadata":{}}]}