From c7a245e2362a7f2d92d3873f5908eff5554bb736 Mon Sep 17 00:00:00 2001 From: ilia Date: Sun, 28 Aug 2022 11:16:54 +0300 Subject: [PATCH] add ai --- api.ipynb | 226 +++++++++ test_pipeline.ipynb | 592 ++++++++++++++++++++++  fit_pipeline.ipynb | 1178 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1996 insertions(+) create mode 100644 api.ipynb create mode 100644 test_pipeline.ipynb create mode 100644  fit_pipeline.ipynb diff --git a/api.ipynb b/api.ipynb new file mode 100644 index 0000000..6fb2bd7 --- /dev/null +++ b/api.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "725d124e-41e4-46e3-b2a1-634fff176e73", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ubuntu/venv/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "from flask import Flask\n", + "from flask import request, jsonify\n", + "\n", + "from transformers import BertTokenizer, BertForSequenceClassification\n", + "import torch\n", + "import re\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import pickle" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "442c6390-eb1d-4477-9286-36af054c7214", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import nltk\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "from nltk.corpus import stopwords\n", + "from nltk.stem import SnowballStemmer\n", + "from nltk.tokenize import word_tokenize\n", + "import torch.nn.functional as nnf\n", + "\n", + "# ...\n", + "\n", + "\n", + "#load models\n", + "model = torch.load('bert_opossum_best_0.6753.pt')\n", + "tokenizer = BertTokenizer.from_pretrained('sberbank-ai/ruBert-base')\n", + "device = 'cuda'\n", + "model.to(device)\n", + "pass" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "531f8c36-63d6-4811-a210-44434e41c45b", + "metadata": {}, + "outputs": [], + "source": [ + "#tokenize, predict, text preprocessing functions\n", + "\n", + "def tokenize_text(text):\n", + " return tokenizer.encode_plus(\n", + " text,\n", + " add_special_tokens=True,\n", + " max_length=512,\n", + " return_token_type_ids=False,\n", + " truncation=True,\n", + " padding='max_length',\n", + " return_attention_mask=True,\n", + " return_tensors='pt',\n", + " )\n", + "\n", + "def predict(df):\n", + " batch = pd.DataFrame.from_records(df['text'].apply(tokenize_text).values)\n", + " input_ids = [a.numpy()[0] for a in batch.iloc[:,1].values]\n", + " input_ids = torch.from_numpy(np.array([a for a in input_ids],dtype=int)).to(device)\n", + " attention_mask = [a.numpy()[0] for a in batch.iloc[:,0].values]\n", + " attention_mask = torch.from_numpy(np.array([a for a in attention_mask],dtype=int)).to(device)\n", + " \n", + " outputs = model(\n", + " input_ids=input_ids,\n", + " attention_mask=attention_mask\n", + " )\n", + " \n", + " prediction = outputs.logits\n", + "\n", + " prob = nnf.softmax(prediction , dim=1)\n", + "\n", + " top_p, top_class = prob.topk(1, dim = 1)\n", + " \n", + " df['score'] = (top_p.cpu().detach().numpy().reshape(-1)*100).astype(int)\n", + " df['type']=top_class.cpu().detach().numpy().reshape(-1)\n", + "\n", + "russian_stopwords = stopwords.words(\"russian\")\n", + "\n", + "russian_stopwords.append('российской')\n", + "russian_stopwords.append('федерации')\n", + "russian_stopwords.append('федерального')\n", + "russian_stopwords.append('настоящих')\n", + "russian_stopwords.append('соответствии')\n", + "russian_stopwords.append('также')\n", + "russian_stopwords.append('рф')\n", + "russian_stopwords.append('ред')\n", + "\n", + "russian_stopwords.append('субсидии')\n", + "russian_stopwords.append('предоставления')\n", + "\n", + "\n", + "def lowercase(text):\n", + " return str(text).lower()\n", + "\n", + "def clean_symb(text):\n", + " return re.sub(r'[^\\w]', ' ', text)\n", + "\n", + "def clear_token(text):\n", + " return word_tokenize(text)\n", + "\n", + "def clean_stopwords(token):\n", + " return ' '.join([i for i in token.split(' ') if i not in russian_stopwords])" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "074dd494-2671-4950-a728-d83b18203021", + "metadata": {}, + "outputs": [], + "source": [ + "#test json data\n", + "\n", + "json = {'1': '1. {2} Настоящие Правила устанавливают цели, условия и порядок предоставления субсидии из федерального бюджета Фонду \"Центр стратегических разработок\" (далее - Фонд) в целях оценки эффектов от реализации инвестиционных проектов в сфере транспорта в рамках государственной программы Российской Федерации \"Экономическое развитие и инновационная экономика\" (далее - субсидия). {2}', '2': '2. {3} Предоставление субсидии осуществляется в пределах лимитов бюджетных обязательств, доведенных в установленном порядке до Министерства экономического развития Российской Федерации как получателя средств федерального бюджета на цели, указанные в пункте 1 настоящих Правил. {3}', '3': '3. {24} Субсидия предоставляется на основании соглашения о предоставлении субсидии, заключаемого между Министерством экономического развития Российской Федерации и Фондом (далее - соглашение о предоставлении субсидии). {24}', '4': '4. {24} Соглашение о предоставлении субсидии содержит в том числе: {24}', '5': '5. {24} Соглашение о предоставлении субсидии и дополнительные соглашения к нему, предусматривающие внесение изменений, или дополнительное соглашение о расторжении соглашения о предоставлении субсидии заключаются в государственной интегрированной информационной системе управления общественными финансами \"Электронный бюджет\" в соответствии с типовой формой, установленной Министерством финансов Российской Федерации.{24}', '6': '6. {4} Субсидия предоставляется на финансовое обеспечение затрат, связанных с достижением целей, указанных в пункте 1 настоящих Правил, в том числе понесенных Фондом в текущем финансовом году до заключения соглашения о предоставлении субсидии (при наличии документов, подтверждающих фактически произведенные затраты), в размере, определяемом по формуле: {4}', '7': '7. {22} Размер субсидии (Рсуб) определяется в пределах лимитов бюджетных обязательств, утвержденных и доведенных в установленном порядке до Министерства экономического развития Российской Федерации как получателя средств федерального бюджета на цели, указанные в пункте 1 настоящих Правил. {22}', '8': '8. {11} Фонд по состоянию на 1-е число месяца, предшествующего месяцу, в котором заключается соглашение о предоставлении субсидии, должен соответствовать следующим требованиям: {11}', '9': '9. {19} Для заключения соглашения о предоставлении субсидии Фонд представляет в Министерство экономического развития Российской Федерации документы, подписанные руководителем Фонда (иным уполномоченным лицом), подтверждающие соответствие Фонда каждому из требований, предусмотренных пунктом 8 настоящих Правил. {19}'}" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "56c8a1bc-4863-4256-b721-10917765b357", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'1': [2, 99], '2': [4, 46], '3': [24, 90], '4': [24, 99], '5': [24, 96], '6': [4, 91], '7': [22, 99], '8': [11, 86], '9': [19, 99]}\n" + ] + } + ], + "source": [ + "#test prediction from data\n", + "\n", + "content =json\n", + "df = pd.DataFrame.from_dict(content,orient='index',columns=['text'])\n", + "df['text'] = df.text.apply(lowercase)\n", + "df['text'] = df.text.apply(clean_symb)\n", + "df['text'] = df.text.apply(lambda x:''.join([a for a in x if not a.isdigit()]))\n", + "df['text'] = df.text.apply(lambda x:' '.join([a for a in x.split(' ') if len(a)>1]))\n", + "df['text'] = df.text.apply(clean_stopwords)\n", + "predict(df)\n", + "df['type']+=1\n", + "\n", + "print(df[['type','score']].T.to_dict(orient='list'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc4cefb8-d8be-440c-b428-a2706446e82c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#flask api\n", + "\n", + "app = Flask(__name__)\n", + "\n", + "@app.route('/api', methods=['GET', 'POST'])\n", + "def info():\n", + " content = request.json\n", + " df = pd.DataFrame.from_dict(content,orient='index',columns=['text'])\n", + " print(df.shape)\n", + " df['text'] = df.text.apply(lowercase)\n", + " df['text'] = df.text.apply(clean_symb)\n", + " df['text'] = df.text.apply(lambda x:''.join([a for a in x if not a.isdigit()]))\n", + " df['text'] = df.text.apply(lambda x:' '.join([a for a in x.split(' ') if len(a)>1]))\n", + " df['text'] = df.text.apply(clean_stopwords)\n", + " if df.shape[0]>0:\n", + " predict(df)\n", + " df['type']+=1\n", + "\n", + " return df[['type','score']].T.to_dict(orient='list')\n", + "\n", + "if __name__ == '__main__':\n", + " app.run(host='172.19.0.178',port=5000)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hack", + "language": "python", + "name": "hack" + }, + "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.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/test_pipeline.ipynb b/test_pipeline.ipynb new file mode 100644 index 0000000..ebcd357 --- /dev/null +++ b/test_pipeline.ipynb @@ -0,0 +1,592 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 6, + "id": "a371550d-cbd7-4435-a41b-3fb35cccaa74", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Archive: test_dataset/Тестовый датасет (2).zip\n", + " inflating: test_dataset/2.docx \n", + " inflating: test_dataset/3.docx \n", + " inflating: test_dataset/4.docx \n", + " inflating: test_dataset/5.docx \n", + " inflating: test_dataset/6.docx \n", + " inflating: test_dataset/7.docx \n", + " inflating: test_dataset/8.docx \n", + " inflating: test_dataset/9.docx \n", + " inflating: test_dataset/10.docx \n", + " inflating: test_dataset/Название_команды.csv \n", + " inflating: test_dataset/Пояснения к валидации.docx \n", + " inflating: test_dataset/1.docx \n" + ] + } + ], + "source": [ + "!unzip test_dataset/Тестовый\\ датасет\\ \\(2\\).zip -d test_dataset/" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "969b75f5-a211-44d2-b704-c3c4c90f4401", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ubuntu/venv/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import torch\n", + "import numpy as np\n", + "from transformers import AutoTokenizer, AutoModel\n", + "from tqdm import tqdm\n", + "tqdm.pandas()\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "sns.set()\n", + "import numpy as np\n", + "\n", + "import pandas as pd\n", + "import docx\n", + "import os\n", + "import re\n", + "\n", + "device = 'cuda'" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "358aad5c-210b-450f-a273-8b759ed88b9c", + "metadata": {}, + "outputs": [], + "source": [ + "#word preprocessing functions\n", + "\n", + "import nltk\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "from nltk.corpus import stopwords\n", + "from nltk.stem import SnowballStemmer\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "russian_stopwords = stopwords.words(\"russian\")\n", + "\n", + "russian_stopwords.append('российской')\n", + "russian_stopwords.append('федерации')\n", + "russian_stopwords.append('федерального')\n", + "russian_stopwords.append('настоящих')\n", + "russian_stopwords.append('соответствии')\n", + "russian_stopwords.append('также')\n", + "russian_stopwords.append('рф')\n", + "russian_stopwords.append('ред')\n", + "\n", + "russian_stopwords.append('субсидии')\n", + "russian_stopwords.append('предоставления')\n", + "\n", + "\n", + "def lowercase(text):\n", + " return str(text).lower()\n", + "\n", + "def clean_symb(text):\n", + " return re.sub(r'[^\\w]', ' ', text)\n", + "\n", + "def clear_token(text):\n", + " return word_tokenize(text)\n", + "\n", + "def clean_stopwords(token):\n", + " return ' '.join([i for i in token.split(' ') if i not in russian_stopwords])\n", + "\n", + "def clean_stem(token):\n", + " return [st.stem(i) for i in token]\n", + "\n", + "### combo 3 prev\n", + "def make_clean(s):\n", + " return ' '.join(clean_stem(clean_stopwords(clear_token(s))))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4d884c5c-cb0f-44ef-8127-175497c7da47", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "11" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#find all docs\n", + "\n", + "data_path = './test_dataset/'\n", + "documents = os.listdir(data_path)\n", + "documents = [data_path+d for d in documents]\n", + "len(documents)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e009af9e-97bf-4e9f-928b-c6bd50424b4b", + "metadata": {}, + "outputs": [], + "source": [ + "#load and parse doc functions\n", + "\n", + "from nltk.corpus import stopwords\n", + "from nltk.stem import SnowballStemmer\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "\n", + "def get_text(filename):\n", + " doc = docx.Document(filename)\n", + " fullText = ''\n", + " for para in doc.paragraphs:\n", + " for run in para.runs:\n", + " fullText+=run.text\n", + " fullText+='\\n'\n", + " return fullText\n", + "\n", + "def split_text(text):\n", + " texts, groups = [],[]\n", + " regt = re.findall(r\"{(.*?)}(.*?){(.*?)}\",text.replace('\\n',''))\n", + " for t in regt:\n", + " if t[0]==t[-1]:\n", + " texts.append(t[1])\n", + " groups.append(int(t[0]))\n", + " else:\n", + " print(t)\n", + " \n", + " return texts, groups" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c1ee24fe-988f-4d9e-97e6-522bf2e41798", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('66', '18. ', '67')\n", + "('67', '', '68')\n", + "('68', '', '69')\n", + "('69', '', '70')\n", + "('Q = (К1 x ГС1) + (К2 x ГС1),где:{42', 'К1 - кандидаты на назначение государственных стипендий, являющиеся молодыми (до 35 лет включительно) творческими деятелями в области культуры и искусства;', '42')\n" + ] + } + ], + "source": [ + "#load data\n", + "\n", + "all_text, all_groups, doc_paths, doc_names = [],[],[],[]\n", + "for d in documents:\n", + " if 'ipynb' not in d:\n", + " text = get_text(d)\n", + " texts,groups = split_text(text)\n", + " all_text.extend(texts)\n", + " all_groups.extend(groups)\n", + " doc_paths.extend([d for a in range(len(texts))])\n", + " doc_names.extend([d.split('/')[-1] for a in range(len(texts))])" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "f3d481a5-b3e4-4367-bfa9-c41c43c05a7b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(846, 7)" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#load documents\n", + "#apply preprocessing to documents\n", + "\n", + "df = pd.DataFrame([doc_paths, doc_names,all_text, all_groups]).T\n", + "df.columns = ['path','doc','text','id']\n", + "df['r_text']='r'\n", + "df['r_text'] = df.text.apply(lowercase)\n", + "df['r_text'] = df.r_text.apply(clean_symb)\n", + "df['r_text'] = df.r_text.apply(lambda x:''.join([a for a in x if not a.isdigit()]))\n", + "df['r_text'] = df.r_text.apply(lambda x:' '.join([a for a in x.split(' ') if len(a)>1]))\n", + "df['r_text'] = df.r_text.apply(clean_stopwords)\n", + "df['text_size'] = df['text'].apply(lambda x: len(x.strip()))\n", + "df['is_text'] = df.r_text.apply(lambda x:x.strip().isdigit())\n", + "df = df[~df.is_text]\n", + "df = df[df['text_size']>5]\n", + "df = df.reset_index(drop=True)\n", + "df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "2e3997a7-7e66-4077-8827-007b64f663f5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "правил 175\n", + "организации 155\n", + "предоставлении 123\n", + "соглашения 115\n", + "конкурса 90\n", + "министерством 85\n", + "средств 82\n", + "финансового 79\n", + "числе 76\n", + "заявок 74\n", + "dtype: int64" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#show most popular words in datset\n", + "\n", + "all_words = np.hstack([np.array(a) for a in df.r_text.apply(lambda x:[a for a in x.split(' ') if len(a)>0]).values])\n", + "pd.Series(all_words).value_counts()[:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "a3b50eb7-e8b4-4503-92dd-9f0c50b7c2e9", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import torch\n", + "from transformers import BertTokenizer, BertForSequenceClassification\n", + "from torch.utils.data import Dataset, DataLoader\n", + "from transformers import AdamW, get_linear_schedule_with_warmup\n", + "\n", + "from bert_dataset import CustomDataset" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "b227db93-5193-4851-95dc-1b89277e3c2d", + "metadata": {}, + "outputs": [], + "source": [ + "#load model\n", + "model = torch.load('bert_opossum_best_0.6753.pt')\n", + "model.to(device)\n", + "pass\n", + "\n", + "#load tokenizer\n", + "tokenizer = BertTokenizer.from_pretrained('sberbank-ai/ruBert-base')" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "e1a0c200-ec37-4058-96d1-b625f839e922", + "metadata": {}, + "outputs": [], + "source": [ + "#predict function\n", + "def predict(text):\n", + " encoding = tokenizer.encode_plus(\n", + " text,\n", + " add_special_tokens=True,\n", + " max_length=512,\n", + " return_token_type_ids=False,\n", + " truncation=True,\n", + " padding='max_length',\n", + " return_attention_mask=True,\n", + " return_tensors='pt',\n", + " )\n", + "\n", + " out = {\n", + " 'text': text,\n", + " 'input_ids': encoding['input_ids'].flatten(),\n", + " 'attention_mask': encoding['attention_mask'].flatten()\n", + " }\n", + " \n", + " input_ids = out[\"input_ids\"].to(device)\n", + " attention_mask = out[\"attention_mask\"].to(device)\n", + "\n", + " outputs = model(\n", + " input_ids=input_ids.unsqueeze(0),\n", + " attention_mask=attention_mask.unsqueeze(0)\n", + " )\n", + "\n", + " prediction = torch.argmax(outputs.logits, dim=1).cpu().numpy()[0]\n", + " return prediction" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "b4095596-35ac-44e0-b6bb-dfc10bd712db", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|█████████████████████████████████████████| 846/846 [00:29<00:00, 28.49it/s]\n" + ] + } + ], + "source": [ + "#apply predict funtcion to text\n", + "df['class'] = df.r_text.progress_apply(predict)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "0392b3c9-7e93-47cf-8729-98be9dbb9285", + "metadata": {}, + "outputs": [], + "source": [ + "#get file_id\n", + "df['file_id'] = df.doc.apply(lambda x:int(x.split('.')[0]))" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "id": "3a8c8d64-4f5e-466b-a48f-79a18cf7de09", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
file_ididclass
0112
1122
2132
3143
4157
............
847106738
848106838
849106938
850107038
85110717
\n", + "

852 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " file_id id class\n", + "0 1 1 2\n", + "1 1 2 2\n", + "2 1 3 2\n", + "3 1 4 3\n", + "4 1 5 7\n", + ".. ... .. ...\n", + "847 10 67 38\n", + "848 10 68 38\n", + "849 10 69 38\n", + "850 10 70 38\n", + "851 10 71 7\n", + "\n", + "[852 rows x 3 columns]" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#create submission\n", + "\n", + "pred = df[['file_id','id','class']]\n", + "sub = pd.read_csv('Название_команды.csv',delimiter=';')\n", + "sub = pd.merge(sub,pred,how='left',on=['file_id','id'])\n", + "sub.drop(columns=['class_x'],inplace=True)\n", + "sub.columns = ['file_id','id','class']\n", + "sub = sub.fillna(23).astype(int)\n", + "sub['class']+=1\n", + "sub" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "id": "e26e3480-9486-4dcb-927e-3f85cfb0fc77", + "metadata": {}, + "outputs": [], + "source": [ + "#save submission data\n", + "sub.to_csv('MAGNUM_OPOSSUM.csv',index=False,header=True,sep=';')" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "038fa0f9-afc8-4750-8b72-36711d41b4e8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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1LJlS02bNk3NmjXT7t27NWPGDJ09e1apqakVtrt06ZK6dOmikSNHKiwsTEePHtXSpUt19OhRrVq1yqvX+uqrr8pms3m1riStXLnSZfA2b9680jYrVqxQenq6xo8fr7i4OF28eFF79uzx2O/MmTN1+fJll2Vr1qzRRx99pMTERLdt9u3bpwkTJig5OVlTpkzRsWPHtGjRIhUUFOjpp592rufNPtq8ebNmzJih8ePHKyEhQRaLRS+88IKaNWum7t27V9guIyNDWVlZuuuuu7Ru3Tqv+jtz5ozWrVune++9V5MmTdKVK1e0cOFCff755/rVr35VYV95eXlKSUlRdHS0TCaTtmzZonnz5qlp06ZKSEiodPwVFhZq7ty5+tnPfqaioiKvxu2tt97qsi3/93//V3/9618VFxdXYbv8/HyNHDlSQUFBmj59um688UZ9+OGH2rRpU4Wv76abbnJuv6v7WrhwoSIiIhQWFua2r9mzZ+ujjz7SlClTFBMTo3379mnx4sVq0KCBevbsWWGNc+fO1fvvv69JkyYpKipKTz75pLKysjR58mR16dLF7XvS3RhJT0/Xr371K4/vZXdjpLJjgLsxsmrVKr388svq3bu3x/7KjpOnnnpKWVlZevDBB9W/f3+Px5urx8ilS5fUoEGDSo9TZcfIc889p7CwMI/t3I2R6dOnq169ehW2czdGHA6H7r//fkVERHjsr+w4mTZtmr777jv169dPDz74oNs2ZcfIxo0btWTJEg0ZMsTjMfiLL75Qamqqfve732n69On67LPPtGLFCvXt21ezZs2qsN2nn36qb7/9VrfffrtycnIkVX7MLywsVFpamn77299qzJgxMpvNWrx4sQ4dOqQJEyYoPj7e4+8Jh8OhF198UeHh4bJarV79fomMjNSCBQucjz/99FPl5OTo9ttvr7Cd3W7XhAkTlJWVpdTUVLVq1UqbNm3St99+q9GjR1fYruz+lqSnn35aDRo08Dr0lL5QlPHaa6854uLiHBcvXnQu+/vf/+7o0KGD4+zZsx7b2mw257+ffvppR3JycqX9nT9/vtyy5557znHrrbe6/DxvrFu3ztGuXbtK63Q4HI5jx4454uLiHG+//bajXbt2jgMHDlS47rvvvuto166d21o9OX78uKNjx46O7du3+9TOnb59+zrGjBlT4fOPPPKI47e//a3LsjfeeMPRqVMnR3Z2tnOZN/vo17/+tWPKlCkuy+677z7Ho48+6rHd1T+7Xbt2jpUrV1baX15eniM/P99lmdVqdfTo0cMxe/Zsr8dRaY0PP/ywxxpLLVq0yPHAAw84nn76acegQYM81uhwOBwPPvigY+zYsS7LvNmWf/7znx39+vVz5OXl+dSurN27dzvatWvnsFgsbtvYbDZH165dHUuWLHFZ/uSTTzr69etXYV9nz551dOjQwfHmm286l50/f94xePBgx/jx453Lyr4n3Y2Re++91zlGKmrnboxUdgxwN0YuX77s6N69u2P27Nke+yvr/PnzjuHDhzvHiac2V4+RgQMHeqzR4XA/Rrw5vrkbI1U5Ln722WfOMVJRO3fj5Pz5846nnnrKOU7KtnE3Rux2e7kx4nCUPwY/8sgjjuHDh7usM2XKFEdSUpLHdle/xj59+jhmzZrl9jVf3a6kpMRx6dIll+dLSkocAwcOdIwbN67Cvkpt2LDBcffddzsWLlzoiIuL89iXw+H9e7dsu/Xr1ztuu+02x7lz53xqV1ZWVpajXbt2jvT09EpruBpzfNzYuXOnEhMTFRYW5lyWlJQku92uXbt2eWxrNvu+ScPDw8st69Chgy5fvqz8/HyfflZpzcXFxZWuO2fOHI0YMUJRUVE+9eGLjRs3qlWrVrrzzjuv6ef8+9//1qlTpzRkyJAK1zl8+HC5L6rt2bOniouL9a9//cu5rLJ9lJWVpRMnTigpKclleXJysvbs2aOioqIK27r72ZX117BhQzVo0MBlWZMmTdS6dWv98MMPHtuW1axZM6/2/cmTJ7V69Wo999xzkuTxkqon3oz3d955R/fee68aNmzoU7uyLBaLGjdurL59+7p93uFwqKSkpNzp+9DQUI9nvr799lvZbDaXsRMeHq6ePXvqX//6l3N/X/2erGiMDB06tNwYKftedvfaKzsGuBsjjRo1Ups2bcqNkcqOHeHh4QoLC3MZJ+7alB0jV18u9rYvb16b5H6MVOW4uGnTJrdj5Op27sZJeHi4mjRp4jJOrm7jboyYTKZyY0RyPQYXFRVp7969GjhwoEs9gwYN0vHjx3Xq1Cm37STv3yNXtwsKClLTpk1dng8KClL79u1dxom73xNWq1ULFy7UM888o+Dg4Er78kXZdhs2bNDAgQMrPUtTWX+bNm2SyWTS4MGDfaqH4ONGZmamoqOjXZaFhoYqIiJCmZmZNVLDl19+qebNm6tx48aVrmuz2XTlyhUdOnRIy5cvV9++fdWqVSuPbTIyMnTkyBE9/vjjPtU1ePBgdejQQf369dPrr79e6WWy/fv3q127dnr11VeVmJiozp07a8SIEdq/f79P/W7atEkNGzas8Jq+9NM147JzsEofHz9+3Ou+Svdx2UAYExOj4uJiZWVlef2zqspqtTrno3hSehC3Wq36n//5H+3atUsPPPBApT//v//7vzVs2DD98pe/9Kmuzz//XHFxcYqNjdWDDz6o//3f//W4/qlTp5Sdna1mzZpp/Pjx6ty5s3r06KHnnntOeXl5XvdbXFysjz76SHfffbfq16/vdp2goCDdc889Wrt2rQ4cOKC8vDzt3r1b77//vh588MEKf3bpLy13Y6eoqMj5y+nq96QvY8SX9/LVKmtX0Rhx166yceKujTdjxF07b8bI1e18GSOetomnMXJ1O2/HydVtKhsj33//vdtj8MmTJ1VcXFxuH8XExEiSjh075vOxW/LtmF9SUqL9+/crKirKY5tFixapU6dO6tOnj099ff/997rtttvUuXNn3XPPPfr44489tisuLtY333yjFi1a6KmnnlJcXJy6deumJ554QtnZ2T69ts2bN+v222/XzTffXOk2uxpzfNywWq0KDQ0tt7xp06bOa63V6YsvvpDFYnG5Tu5Jnz59dO7cOUlSr169tHDhQo/rFxQUaP78+Zo8ebLXB+OIiAhNnDhRXbt2lclkck7WO3funMd5T9nZ2Tp48KCOHDmimTNnqkGDBnrttdf0yCOP6KOPPtKNN95Yad8lJSX68MMP1bdvX5e/CMu65ZZbdODAAZdl+/btkySf9lvpumXHQOnjmhgDL7/8skwmk/7rv/5LixYtqnC9PXv26OGHH5Yk1atXTzNmzCj312VZW7du1VdffaWMjAyfarr99ts1bNgw51mGN954Qw8//LD++te/qlu3bm7b/Pjjj5J+mmD761//Wunp6Tpx4oQWLlyo/Px8vfLKK171vXPnTl26dKnSv+xmzpypmTNnKiUlxbls3Lhxzm3kzi233CJJOnDggMsB9uqxU/Y96e0Y8fW9XMqbdlePkcraeRon7tp4M0bctfNmjJRt5+0YqWybVDRG3LWrbJyUbVPZGBk1apQuXLggyfUYXNk4eeqpp5zreHPsLuXLMX/lypU6d+6cdu/erS5durhtc/jwYb3zzjtuJyp76qtDhw6KjY1V27ZtlZubq7fffluPP/64Fi9erLlz57ptd+nSJRUXFys9PV233367li1bpgsXLujll1/WxIkTdebMGa9e27fffqsjR45o9uzZXm2zqxF8/MzZs2c1efJkxcfHa9SoUV61SUtLU0FBgY4dO6YVK1Zo/PjxWr16tdtT09JPk41LP/HkrV69eqlXr17Oxz179lT9+vW1Zs0ajR8/vsJTlg6HQ/n5+Vq8eLHzL8euXbuqb9++Wrt2rZ544olK+961a5cuXLhQ6S+9+++/X88++6zWrFmjYcOGOSc3V7Qd/NW7776r9evXa/78+ZX+JdOlSxe98847unz5snbu3Kk5c+YoKCjI5YB+tStXrmju3LmaOHGi20sJnvzhD39weXzXXXdp8ODBevXVV5Wenu62jd1ul/TTmZE//elPkqTExETVq1dPzz33nCZPnuxV3x988IF+9rOfVTixvdSCBQu0fft2zZkzR23atNG+ffu0fPlyhYaG6tFHH3Xbpl27durevbsWLFign//852rTpo02btzoPFNx4cIFvfDCCz69J6WqvZe9bedujHhqV9E46dWrV7k23oyRivqqbIy4a+fNGAkODq50m7gbIxXV6WmcDB48uFybysbItGnT1Lp163LH4MqMHj1aPXr08PrYXcrbY/6uXbu0dOlSTZgwQf3793fbxmw2a9asWbr//vudZ6K87euhhx5yWbdv374aMWKElixZUmG70v3dqFEjLVu2zHkW7Wc/+5kefvhhvfjii/rFL35R6Wv74IMPFBwcrAEDBlS6ncsi+LgRGhqq3NzccstzcnLKXT+9nqxWq8aMGaOwsDAtXbrU62u8pYGiW7duio2N1bBhw/TPf/7T7V/+p0+f1qpVq7R8+XLnayy9Xp6fn6+8vDw1atTIq36TkpK0atUqHT58uMLgExoaqrCwMJfT5WFhYerYsaOOHTvmVT+bNm1SWFiYevbs6XG9e+65R0eOHNFLL72kuXPnKjg4WKmpqVqzZo1PM/5L93Fubq4iIiKcy61Wq8vz1WHHjh16/vnnNWHCBP32t7+tdP3GjRs7b0GQmJgom82m+fPn65577nG7/po1a2Q2m5WcnOx8PcXFxbLb7bJarRXeXsCdhg0b6s4779SWLVsq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3wkPD1fjxo119OhRr9scOXJEJ06c0LRp0zR27Fj1799fv/rVr3TTTTe5Xb9169Z65JFHtGrVKm3atEnFxcVatWqVyzpxcXGaPHmyNm7cqAULFujo0aOyWCzX9NoA1C6CDwC/Yzab1b9/f23btk1ff/11uefdTW42m83lnnM4HHrzzTdd1isoKNCVK1dclrVu3VqNGjVSUVGRJCknJ6dcHx06dJAk5zoAAhNzfAD4pSlTpmjXrl0aOXKk7rvvPsXExCg7O1sZGRn629/+Vm796OhotW7dWn/605907tw5NW7cWFu2bJHVanVZ78SJE/r973+vgQMHqm3btgoKCtLHH3+sH3/8UcnJyZKk9957T2+//bb69++v1q1bKy8vT+vXr1fjxo3Vu3fvGnn9AKoHwQeAX2revLnWr1+vxYsX64MPPtDly5fVvHlz9e7d2+XTW6WCg4P12muvac6cOXr99ddVv3593X333XrggQc0bNgw53o333yzkpOTtWfPHv3jH/9QUFCQoqOjtWjRIg0YMEDST5Obv/76a1ksFv34449q0qSJunTpogULFigyMrLGtgGA68/kqOiGGAAAAHUMc3wAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBh/H/Qs60peumbxQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#show class distribution\n", + "\n", + "f = sub.groupby('class').count().reset_index()[['class','id']]\n", + "f['class'] = f['class']-1\n", + "\n", + "sns.barplot(x=f['class'],y=f['id'],color='#ff6666',errwidth=.32)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hack", + "language": "python", + "name": "hack" + }, + "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.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ fit_pipeline.ipynb b/ fit_pipeline.ipynb new file mode 100644 index 0000000..f2d6c33 --- /dev/null +++ b/ fit_pipeline.ipynb @@ -0,0 +1,1178 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "10e636e2-5f38-43cb-adc6-b2f928d61136", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/ubuntu/venv/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import torch\n", + "import numpy as np\n", + "from transformers import AutoTokenizer, AutoModel\n", + "from tqdm import tqdm\n", + "tqdm.pandas()\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "sns.set()\n", + "import numpy as np\n", + "\n", + "import pandas as pd\n", + "import docx\n", + "import os\n", + "import re\n", + "\n", + "device = 'cuda'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "19c1e5b6-30d7-4684-87be-2777cc14006c", + "metadata": {}, + "outputs": [], + "source": [ + "#word preprocessing functions\n", + "\n", + "import nltk\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "from nltk.corpus import stopwords\n", + "from nltk.stem import SnowballStemmer\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "russian_stopwords = stopwords.words(\"russian\")\n", + "\n", + "russian_stopwords.append('российской')\n", + "russian_stopwords.append('федерации')\n", + "russian_stopwords.append('федерального')\n", + "russian_stopwords.append('настоящих')\n", + "russian_stopwords.append('соответствии')\n", + "russian_stopwords.append('также')\n", + "russian_stopwords.append('рф')\n", + "russian_stopwords.append('ред')\n", + "\n", + "russian_stopwords.append('субсидии')\n", + "russian_stopwords.append('предоставления')\n", + "\n", + "\n", + "def lowercase(text):\n", + " return str(text).lower()\n", + "\n", + "def clean_symb(text):\n", + " return re.sub(r'[^\\w]', ' ', text)\n", + "\n", + "def clear_token(text):\n", + " return word_tokenize(text)\n", + "\n", + "def clean_stopwords(token):\n", + " return ' '.join([i for i in token.split(' ') if i not in russian_stopwords])\n", + "\n", + "def clean_stem(token):\n", + " return [st.stem(i) for i in token]\n", + "\n", + "### combo 3 prev\n", + "def make_clean(s):\n", + " return ' '.join(clean_stem(clean_stopwords(clear_token(s))))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "193b640f-d312-440c-9c89-5cb868132e2c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "162" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#find all docs\n", + "\n", + "data_path = './data/Документы/'\n", + "documents = os.listdir(data_path)\n", + "documents = [data_path+d for d in documents]\n", + "len(documents)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f8dfdf00-ef42-411c-b629-a1fb349c5c94", + "metadata": {}, + "outputs": [], + "source": [ + "#load and parse doc functions\n", + "\n", + "from nltk.corpus import stopwords\n", + "from nltk.stem import SnowballStemmer\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "\n", + "def get_text(filename):\n", + " doc = docx.Document(filename)\n", + " fullText = ''\n", + " for para in doc.paragraphs:\n", + " for run in para.runs:\n", + " fullText+=run.text\n", + " fullText+='\\n'\n", + " return fullText\n", + "\n", + "def split_text(text):\n", + " texts, groups = [],[]\n", + " regt = re.findall(r\"{(.*?)}(.*?){(.*?)}\",text.replace('\\n',''))\n", + " for t in regt:\n", + " if t[0]==t[-1]:\n", + " texts.append(t[1])\n", + " groups.append(int(t[0]))\n", + " else:\n", + " print(t)\n", + " \n", + " return texts, groups" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8fdc799a-6ee7-4188-9c70-39b0c11a5833", + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('36', '42. ', '37')\n", + "('37', ' (в ред. Правительства РФ от 04.05.2021 N 699) 43. ', '38')\n", + "('38', ' 48.', '7')\n", + "('10', '6. ', '24')\n", + "('24', ' 7. ', '11')\n", + "('11', '8. ', '10')\n", + "('13', 'м) ', '10')\n", + "('10', '(пп. \"о\" в ред. Правительства РФ от 16.08.2021 N 1337)9. ', '13')\n", + "('13', '(в ред. Правительства РФ от 16.08.2021 N 1337)12. ', '11')\n", + "('11', ' ', '24')\n", + "('24', ' ', '17')\n", + "('17', '14. ', '21')\n", + "('21', '15. ', '15')\n", + "('15', '(в ред. Правительства РФ от 16.08.2021 N 1337)16. ', '22')\n", + "('22', ' 17. ', '21')\n", + "('21', '18. ', '28')\n", + "('28', ' ', '12')\n", + "('12', ' ', '30')\n", + "('28', '', '30')\n", + "('30', 'ж) утратил силу. - Правительства РФ от 16.08.2021 N 1337.19. ', '23')\n", + "('23', ' 20. ', '13')\n", + "('12', ' 21. ', '13')\n", + "('13', ' 22. ', '22')\n", + "('22', '23. ', '11')\n", + "(' 11', ' 24. ', '11')\n", + "('11', '25. ', '21')\n", + "('21', 'ж) утратил силу. - Правительства РФ от 16.08.2021 N 1337.26. ', '24')\n", + "('24', ' 28. ', '27')\n", + "('27', ' ', '22')\n", + "('22', '29. ', '24')\n", + "('24', ' 31. ', '37')\n", + "('37', ' (в ред. Правительства РФ от 16.08.2021 N 1337)32. ', '38')\n", + "('38', ' (в ред. Правительства РФ от 16.08.2021 N 1337)33. ', '35')\n", + "('2', ' сведения об организационной структуре реализации исследовательской программы, планы по изменению организационно-штатной структуры организации, на базе которой реализуется исследовательская программа, в целях обеспечения эффективной и независимой реализации исследовательской программы; ', '12')\n", + "('11', ' отказ от участия в конкурсе. ', '15')\n", + "('21', ' недостоверность информации, содержащейся в представленных организацией документах, указанных в настоящих Правил; ', '2')\n", + "('38', ' В случае установления в ходе проверок, проведенных Министерством науки и высшего образования Российской Федерации и (или) органом государственного финансового контроля, фактов нарушения целей, условий и порядка предоставления гранта средства гранта в размере, определенном на основании выявленных нарушений, подлежат возврату в доход федерального бюджета: ', '238')\n", + "('27', 'Результатом предоставления грантов является количество завершенных проектов открытых библиотек, размещенных в открытом доступе в информационно-телекоммуникационной сети \"Интернет\" и предоставляемых любым лицам на условиях безвозмездной бессрочной открытой лицензии, завершенных технологических проектов и проектов по акселерации, по которым завершена акселерационная программа. ', '22')\n", + "('36', ' при получении кредита по льготной процентной ставке направлять ежеквартально в Министерство строительства и жилищно-коммунального хозяйства Российской Федерации актуальную информацию об имеющихся депозитах и иных финансовых документах. ', '136')\n", + "('10', 'даты размещения результатов отбора на едином портале и на сайте http://favt.ru/ в сети \"Интернет\", которая не может быть позднее 14-го календарного дня, следующего за днем определения победителя отбора (принятия решения о заключении договора о предоставлении субсидии или об отказе в заключении договора). ', '7')\n", + "('10', ' наименование производителей, с которыми заключается соглашение, и размер предоставляемой субсидии. ', '11')\n", + "('37', ' Министерство промышленности и торговли Российской Федерации и органы государственного финансового контроля проводят проверки соблюдения производителем целей, условий и порядка предоставления субсидии, которые предусмотрены настоящими Правилами. ', '35')\n", + "('30', ' оплата услуг по переводам документов, аудиторских, бухгалтерских, юридических и консультационных услуг, а также патентных и нотариальных услуг, услуг по таможенному оформлению, по проведению экспертиз и получению заключений, связанных с производственной деятельностью и эксплуатацией технического оборудования; ', '33')\n", + "('11', 'соответствовать следующим требованиям:', '18')\n", + "('26', 'порядок согласования новых условий соглашения о предоставлении гранта или расторжения соглашения о предоставлении гранта при недостижении согласия по новым условиям в случае уменьшения ранее доведенных до Министерства промышленности и торговли Российской Федерации лимитов бюджетных обязательств, приводящих к невозможности предоставления гранта в размере, определенном в соглашении о предоставлении гранта.', '2')\n", + "('1', '3. ', '24')\n", + "('24', '4. ', '10')\n", + "('10', '5. ', '23')\n", + "('23', '6. ', '24')\n", + "('24', '7. ', '19')\n", + "('19', '8. ', '26')\n", + "('26', '9. ', '19')\n", + "('19', '10. ', '38')\n", + "('38', '11. ', '35')\n", + "('35', '(п. 11 в ред. Правительства РФ от 21.04.2022 N 723) 12.', '10')\n", + "('10', '13. ', '26')\n", + "('26', '14. ', '37')\n", + "('37', '15. ', '35')\n", + "('35', '16. ', '19')\n", + "('19', '17. ', '26')\n", + "('26', '18. ', '20')\n", + "('20', '19. ', '16')\n", + "('16', '20. ', '20')\n", + "('20', '21. ', '35')\n", + "('35', '23. ', '24')\n", + "('24', '24. ', '35')\n", + "('35', '26. ', '22')\n", + "('22', '27. ', '19')\n", + "('19', '28. ', '38')\n", + "('38', '29. ', '3')\n", + "('3', '30. ', '38')\n", + "('38', '31. ', '37')\n", + "('37', '', '27')\n", + "('27', '35. ', '37')\n", + "('37', '37. ', '38')\n", + "('3', ' формирование и ведение которого осуществляется Министерством финансов Российской Федерации в установленном им порядке при формировании проекта федерального закона о федеральном бюджете (проекта федерального закона о внесении изменений в федеральный закон о федеральном бюджете). ', ' 3')\n", + "('38', 'Возврат указанной суммы денежных средств осуществляется в порядке, предусмотренном бюджетным законодательством Российской Федерации. ', '35')\n", + "('24', 'Федеральное агентство по туризму не позднее 10-го рабочего дня со дня принятия решения о заключении соглашения о предоставлении субсидии заключает с организацией указанное соглашение по форме, установленной Министерством финансов Российской Федерации. ', '36')\n", + "('30', ' оплата услуг по переводам документов, аудиторских, бухгалтерских, юридических и консультационных услуг, а также патентных и нотариальных услуг, услуг по таможенному оформлению, по проведению экспертиз и получению заключений, связанных с производственной деятельностью и эксплуатацией технического оборудования; ', '33')\n", + "('38', 'на основании требования Федерального агентства по делам молодежи - не позднее 10-го рабочего дня со дня получения получателем гранта указанного требования;', '37')\n", + "('22', 'предельный размер гранта; ', '24')\n", + "('38', 'III. Особенности предоставления субсидии в части поддержкипроектов, предусматривающих разработку стандартных образцов(введен Правительства РФ от 14.04.2022 N 653)27. ', '33')\n", + "('33', '28. ', '5')\n", + "('5', ' ', '24')\n", + "('24', 'б) ', '36')\n", + "('36', 'в) ', '27')\n", + "('27', 'г) ', '32')\n", + "('32', 'д) ', '24')\n", + "('24', 'е) ', '37')\n", + "('37', ';ж) ', '38')\n", + "('38', 'з) ', '31')\n", + "('31', 'и) ', '38')\n", + "('38', 'к) ', '24')\n", + "('24', 'л) ', '25')\n", + "('25', 'м) ', '24')\n", + "('24', 'н) ', '26')\n", + "('26', 'о) ', '24')\n", + "('24', '29. ', '22')\n", + "('22', '30. ', '30')\n", + "('30', '31. ', '19')\n", + "('19', '32. ', '20')\n", + "('20', '', '21')\n", + "('21', '', '14')\n", + "('14', '', '24')\n", + "('24', '34. ', '27')\n", + "('27', '35. ', '36')\n", + "('36', '37. ', '35')\n", + "('35', 'ж) ', '7')\n", + "('7', 'з) ', '35')\n", + "('35', '38. ', '8')\n", + "('8', '', '10')\n", + "('10', 'р) ', '17')\n", + "('17', '39. ', '11')\n", + "('11', '', '12')\n", + "('12', '40. ', '19')\n", + "('19', '41. ', '24')\n", + "('24', 'б) ', '22')\n", + "('22', 'г) ', '30')\n", + "('30', 'д) ', '24')\n", + "('24', 'е) ', '36')\n", + "('36', 'з) ', '24')\n", + "('24', 'и) ', '38')\n", + "('38', 'к) ', '31')\n", + "('31', 'л) ', '24')\n", + "('24', 'о) ', '27')\n", + "('27', ' ', '38')\n", + "('38', 'п) ', '24')\n", + "('24', 'р) ', '26')\n", + "('26', 'с) ', '24')\n", + "('24', 'у) ', '38')\n", + "('38', '42. ', '35')\n", + "('35', '43. ', '27')\n", + "('27', '44. ', '29')\n", + "('29', '', '28')\n", + "('28', '45. ', '37')\n", + "('37', '46. ', '38')\n", + "('20', 'Министерство науки и высшего образования Российской Федерации рассматривает документы, указанные в настоящих Правил, и в 20-дневный срок со дня их поступления принимает решение о заключении соглашения или об отказе в заключении соглашения, о чем уведомляет оператора в течение 5 рабочих дней со дня принятия решения', '19')\n", + "('19', '(пп. \"ж\" введен Правительства РФ от 30.12.2020 N 2373)7. ', '20')\n", + "('20', '', '21')\n", + "('21', '(в ред. Правительства РФ от 30.12.2020 N 2373)8. ', '27')\n", + "('27', '9. ', '29')\n", + "('29', ' ', '28')\n", + "('28', '(п. 9 в ред. Правительства РФ от 30.12.2020 N 2373)10. Утратил силу. - Правительства РФ от 30.12.2020 N 2373.11. ', '36')\n", + "('36', '12. ', '37')\n", + "('37', '13. ', '38')\n", + "('11', ' организация не является иностранным юридическим лицом, а также российским юридическим лицом, в уставном (складочном) капитале которого доля участия иностранных юридических лиц, местом регистрации которых является государство или территория, ', '24')\n", + "('24', 'включенные в утвержденный Министерством финансов Российской Федерации государств и территорий, предоставляющих льготный налоговый режим налогообложения и (или) не предусматривающих раскрытия и предоставления информации при проведении финансовых операций (офшорные зоны), в совокупности превышает 50 процентов; ', '11')\n", + "('11) за исключением случаев, если указанные иностранные юридические лица находятся под контролем российских юридических лиц или физических лиц (конечными бенефициарами являются Российская Федерация, российские юридические лица или физические лица), в том числе в случае, если этот контроль осуществляется через иные иностранные юридические лица; {11', 'з) ', '11')\n", + "('11', '9. ', '35')\n", + "('35', '11. ', '15')\n", + "('15', '12. ', '35')\n", + "('35', '15. ', '19')\n", + "('19', '', '11')\n", + "('11', '16. ', '19')\n", + "('19', '17. ', '20')\n", + "('20', '', '21')\n", + "('21', '19. ', '35')\n", + "('35', '', '22')\n", + "('22', '20. ', '35')\n", + "('35', '21. ', '24')\n", + "('24', '22. ', '26')\n", + "('26', 'д) ', '25')\n", + "('25', 'е) ', '26')\n", + "('26', '23. ', '35')\n", + "('35', '24. ', '6')\n", + "('6', '25. ', '22')\n", + "('22', '26. ', '19')\n", + "('19', '', '20')\n", + "('20', '27. ', '35')\n", + "('35', '28. ', '3')\n", + "('3', 'а) ', '20')\n", + "('20', 'б) ', '29')\n", + "('29', ' ', '28')\n", + "('28', '29. ', '21')\n", + "('21', '30. ', '35')\n", + "('35', '31. ', '36')\n", + "('36', '34. ', '27')\n", + "('27', '35. ', '35')\n", + "('35', '36. ', '37')\n", + "('37', '37. ', '38')\n", + "('25', ' Министерство экономического развития Российской Федерации:', '35')\n", + "('10', 'доменное имя, и (или) сетевой адрес, и (или) указатели страниц сайта в информационно-телекоммуникационной сети \"Интернет\", на котором обеспечивается проведение отбора; ', '24')\n", + "('15', ' обязательство Фонда о проведении отбора в соответствии с порядком, установленным настоящих Правил; ', '24')\n", + "('27', 'значения показателей, необходимых для достижения результата предоставления субсидии, указанные в настоящих Правил; ', '24')\n", + "('10', ' кредитная организация по состоянию на дату не ранее чем за 30 календарных дней до даты подачи заявки на получение субсидии не имеет просроченной задолженности по возврату в федеральный бюджет субсидий, бюджетных инвестиций, предоставленных из федерального бюджета в том числе в соответствии с иными правовыми актами, и иной просроченной (неурегулированной) задолженности по денежным обязательствам перед Российской Федерацией; ', '12')\n", + "('35', ' включения заемщика, содержащегося в реестре потенциальных заемщиков, в реестр заемщиков устанавливается ', '3')\n", + "('3', '', '35')\n", + "('22', ' Размер субсидии (S) по направлениям ее использования рассчитывается по формуле: ', '21')\n", + "('30', 'Расходы на оплату труда работников, на начисления на выплаты по оплате труда работников в соответствии с законодательством Российской Федерации, а также на иные указанные в настоящих Правил направления расходов не могут превышать 15 процентов размера субсидии.', '3')\n", + "('22', ' Si_март - размер субсидии i-му российскому аэропорту за март, рублей; ', '221')\n", + "('где:{22', ' Рмарт - размер расходной ставки аэропорта за март, равный 772 рублям на 1 \"потерянного\" пассажира, руб./пасс.; ', '22')\n", + "('22', ' Si_март - размер субсидии i-му российскому аэропорту за март, рублей; ', '221')\n", + "('где:{22', ' Рмарт - размер расходной ставки аэропорта за март, равный 772 рублям на 1 \"потерянного\" пассажира, руб./пасс.; ', '22')\n", + "('38', 'где: ', '22')\n", + "('22', '22. ', '38')\n", + "('36', ' сроки и формы представления отчета оператором о ходе реализации программ по развитию отдельных направлений Национальной технологической инициативы и отчета о расходах, источником финансового обеспечения которых является субсидия, а также отчета о достижении значения результата предоставления субсидии в соответствии с настоящих Правил;', '46')\n", + "('4', ' цели, условия и порядок предоставления и использования гранта;', '2')\n", + "('16', ' Отбор проводится образуемой Министерством промышленности и торговли Российской Федерации комиссией по проведению отбора (далее - комиссия). ', '316')\n", + "('12', ' выписка из Единого государственного реестра юридических лиц, заверенная в установленном порядке (в случае непредставления российской компанией такого документа Министерство промышленности и торговли Российской Федерации запрашивает его самостоятельно); ', '13')\n", + "('24', ' Основаниями для расторжения соглашения, в том числе расторжения соглашения Министерством промышленности и торговли Российской Федерации в одностороннем порядке, являются: ', '21')\n", + "('', '15указанных в настоящих Правил, полноту содержащихся в них сведений и направляет их на рассмотрение Комиссии. ', '15')\n", + "('15', ' заключает с производителями соглашения о предоставлении субсидии в течение 15 рабочих дней со дня окончания проверки, предусмотренной настоящего пункта. ', '35')\n", + "('35', 'уведомляет об этом производителя и возвращает заявление о включении в реестр получателей субсидии по договорам о реализации, заключенным в 2018 - 2019 годах, и документы, представленные производителем в соответствии с настоящих Правил; ', '15')\n", + "('7', 'Субсидии в целях осуществления мероприятий по приобретению объектов особо ценного движимого имущества в части транспортных средств. ', '2')\n", + "('35', 'отсутствие бюджетных ассигнований федерального бюджета, предусмотренных в целях предоставления субсидии.', '38')\n", + "('28', 'В случае если совокупный размер выплаты за период оплаты не превышает объем лимитов бюджетных обязательств, доведенных до ', '3')\n", + "('3', ' в соответствии с настоящих Правил, Федеральное агентство по туризму вправе установить очередной период оплаты.', '28')\n", + "('11', ' основные направления деятельности некоммерческой организации в соответствии с учредительными документами должны соответствовать тематике конкурса, в котором участвует некоммерческая организация; ', '25')\n", + "('26', ' Соглашение о предоставлении субсидии (дополнительное соглашение к соглашению о предоставлении субсидии, в том числе дополнительное соглашение о расторжении соглашения о предоставлении субсидии) с соблюдением требований о защите государственной тайны заключается', '24')\n", + "('38', 'В случае если требование, указанное в настоящих Правил, не выполнено в установленный срок, организация возвращает в федеральный бюджет полученные средства на основании: ', '36')\n", + "('21', 'Основаниями для отказа в предоставлении обществу субсидии являются: ', '23')\n", + "('27', 'Результатом предоставления субсидии является обеспечение страховой и гарантийной поддержки в отношении проектов, включенных в перечень. ', '28')\n", + "('11', 'соответствовать следующим требованиям:', '18')\n", + "('20', 'Перечисление субсидии получателю субсидии осуществляется на казначейский счет для осуществления и отражения операций с денежными средствами юридических лиц, не являющихся участниками бюджетного процесса, бюджетными и автономными учреждениями, открытый в территориальном органе Федерального казначейства, ', '29')\n", + "('37', 'Федеральное агентство воздушного транспорта осуществляет проверку соблюдения авиакомпанией условий и порядка предоставления субсидий, в том числе в части достижения результата предоставления субсидии, а органы государственного финансового контроля осуществляют проверки в соответствии со и Бюджетного кодекса Российской Федерации.', '7')\n" + ] + } + ], + "source": [ + "#load data\n", + "\n", + "all_text, all_groups, doc_paths, doc_names = [],[],[],[]\n", + "for d in documents:\n", + " if 'ipynb' not in d:\n", + " text = get_text(d)\n", + " texts,groups = split_text(text)\n", + " all_text.extend(texts)\n", + " all_groups.extend(groups)\n", + " doc_paths.extend([d for a in range(len(texts))])\n", + " doc_names.extend([d.split('/')[-1] for a in range(len(texts))])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "1413bdb0-ed8d-453d-9b67-fde0cfacd4e5", + "metadata": {}, + "outputs": [], + "source": [ + "#load documents\n", + "#apply preprocessing to documents\n", + "\n", + "df = pd.DataFrame([doc_paths, doc_names,all_text, all_groups]).T\n", + "df.columns = ['path','doc','text','type']\n", + "df['r_text']='r'\n", + "df['r_text'] = df.text.apply(lowercase)\n", + "df['r_text'] = df.r_text.apply(clean_symb)\n", + "df['r_text'] = df.r_text.apply(lambda x:''.join([a for a in x if not a.isdigit()]))\n", + "df['r_text'] = df.r_text.apply(lambda x:' '.join([a for a in x.split(' ') if len(a)>1]))\n", + "df['r_text'] = df.r_text.apply(clean_stopwords)\n", + "df['text_size'] = df['text'].apply(lambda x: len(x.strip()))\n", + "df['is_text'] = df.r_text.apply(lambda x:x.strip().isdigit())\n", + "df = df[~df.is_text]\n", + "df = df[df['text_size']>5]\n", + "df = df.reset_index(drop=True)\n", + "df.shape\n", + "df.type = df.type.astype(int)-1" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "1f4d8205-7f3f-430b-ac84-9e19ee913f81", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "правил 3588\n", + "организации 2263\n", + "отбора 2042\n", + "соглашения 1940\n", + "предоставлении 1747\n", + "результата 1578\n", + "гранта 1556\n", + "министерством 1544\n", + "дня 1360\n", + "заявок 1344\n", + "dtype: int64" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#show most popular words in datset\n", + "\n", + "all_words = np.hstack([np.array(a) for a in df.r_text.apply(lambda x:[a for a in x.split(' ') if len(a)>0]).values])\n", + "pd.Series(all_words).value_counts()[:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "4c22b4c2-9155-4655-bc95-6e3387b28ac4", + "metadata": {}, + "outputs": [], + "source": [ + "#split data to train/test\n", + "\n", + "from sklearn.utils import resample\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "X_data, X_val, y_data, y_val = train_test_split(list(df['r_text']), list(df['type']), test_size=0.1, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "eaac3775-7552-49c7-a891-c8ef5cccf6d9", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import torch\n", + "from transformers import BertTokenizer, BertForSequenceClassification\n", + "from torch.utils.data import Dataset, DataLoader\n", + "from transformers import AdamW, get_linear_schedule_with_warmup\n", + "\n", + "from bert_dataset import CustomDataset" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "c75236ca-e832-4748-a312-9cc7f7935f51", + "metadata": {}, + "outputs": [], + "source": [ + "#Bert Classifier class\n", + "\n", + "class BertClassifier:\n", + "\n", + " def __init__(self, model_path, tokenizer_path, n_classes=2, epochs=1, model_save_path='/content/bert.pt'):\n", + " self.model = BertForSequenceClassification.from_pretrained(model_path)\n", + " self.tokenizer = BertTokenizer.from_pretrained(tokenizer_path)\n", + " self.device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n", + " self.model_save_path=model_save_path\n", + " self.max_len = 512\n", + " self.epochs = epochs\n", + " self.out_features = self.model.bert.encoder.layer[1].output.dense.out_features\n", + " self.model.classifier = torch.nn.Linear(self.out_features, n_classes)\n", + " self.model.to(self.device)\n", + " \n", + " def preparation(self, X_train, y_train, X_valid, y_valid):\n", + " # create datasets\n", + " self.train_set = CustomDataset(X_train, y_train, self.tokenizer)\n", + " self.valid_set = CustomDataset(X_valid, y_valid, self.tokenizer)\n", + "\n", + " # create data loaders\n", + " self.train_loader = DataLoader(self.train_set, batch_size=8, shuffle=True)\n", + " self.valid_loader = DataLoader(self.valid_set, batch_size=8, shuffle=True)\n", + "\n", + " # helpers initialization\n", + " self.optimizer = AdamW(self.model.parameters(), lr=2e-5, correct_bias=False)\n", + " self.scheduler = get_linear_schedule_with_warmup(\n", + " self.optimizer,\n", + " num_warmup_steps=0,\n", + " num_training_steps=len(self.train_loader) * self.epochs\n", + " )\n", + " self.loss_fn = torch.nn.CrossEntropyLoss().to(self.device)\n", + " \n", + " def fit(self):\n", + " self.model = self.model.train()\n", + " losses = []\n", + " correct_predictions = 0\n", + "\n", + " for data in tqdm(self.train_loader):\n", + " input_ids = data[\"input_ids\"].to(self.device)\n", + " attention_mask = data[\"attention_mask\"].to(self.device)\n", + " targets = data[\"targets\"].to(self.device)\n", + "\n", + " outputs = self.model(\n", + " input_ids=input_ids,\n", + " attention_mask=attention_mask\n", + " )\n", + "\n", + " preds = torch.argmax(outputs.logits, dim=1)\n", + " loss = self.loss_fn(outputs.logits, targets)\n", + "\n", + " correct_predictions += torch.sum(preds == targets)\n", + "\n", + " losses.append(loss.item())\n", + " \n", + " loss.backward()\n", + " torch.nn.utils.clip_grad_norm_(self.model.parameters(), max_norm=1.0)\n", + " self.optimizer.step()\n", + " self.scheduler.step()\n", + " self.optimizer.zero_grad()\n", + "\n", + " train_acc = correct_predictions.double() / len(self.train_set)\n", + " train_loss = np.mean(losses)\n", + " return train_acc, train_loss\n", + " \n", + " def eval(self):\n", + " self.model = self.model.eval()\n", + " losses = []\n", + " correct_predictions = 0\n", + "\n", + " with torch.no_grad():\n", + " for data in self.valid_loader:\n", + " input_ids = data[\"input_ids\"].to(self.device)\n", + " attention_mask = data[\"attention_mask\"].to(self.device)\n", + " targets = data[\"targets\"].to(self.device)\n", + "\n", + " outputs = self.model(\n", + " input_ids=input_ids,\n", + " attention_mask=attention_mask\n", + " )\n", + "\n", + " preds = torch.argmax(outputs.logits, dim=1)\n", + " loss = self.loss_fn(outputs.logits, targets)\n", + " correct_predictions += torch.sum(preds == targets)\n", + " losses.append(loss.item())\n", + " \n", + " val_acc = correct_predictions.double() / len(self.valid_set)\n", + " val_loss = np.mean(losses)\n", + " return val_acc, val_loss\n", + " \n", + " def train(self):\n", + " best_accuracy = 0\n", + " for epoch in range(self.epochs):\n", + " print(f'Epoch {epoch + 1}/{self.epochs}')\n", + " train_acc, train_loss = self.fit()\n", + " print(f'Train loss {train_loss} accuracy {train_acc}')\n", + "\n", + " val_acc, val_loss = self.eval()\n", + " print(f'Val loss {val_loss} accuracy {val_acc}')\n", + " print('-' * 10)\n", + "\n", + " if val_acc > best_accuracy:\n", + " torch.save(self.model, self.model_save_path)\n", + " best_accuracy = val_acc\n", + "\n", + " self.model = torch.load(self.model_save_path)\n", + " \n", + " def predict(self, text):\n", + " encoding = self.tokenizer.encode_plus(\n", + " text,\n", + " add_special_tokens=True,\n", + " max_length=self.max_len,\n", + " return_token_type_ids=False,\n", + " truncation=True,\n", + " padding='max_length',\n", + " return_attention_mask=True,\n", + " return_tensors='pt',\n", + " )\n", + " \n", + " out = {\n", + " 'text': text,\n", + " 'input_ids': encoding['input_ids'].flatten(),\n", + " 'attention_mask': encoding['attention_mask'].flatten()\n", + " }\n", + " \n", + " input_ids = out[\"input_ids\"].to(self.device)\n", + " attention_mask = out[\"attention_mask\"].to(self.device)\n", + " \n", + " outputs = self.model(\n", + " input_ids=input_ids.unsqueeze(0),\n", + " attention_mask=attention_mask.unsqueeze(0)\n", + " )\n", + " \n", + " prediction = torch.argmax(outputs.logits, dim=1).cpu().numpy()[0]\n", + "\n", + " return prediction" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "38cf183b-a3ee-4ef2-94b9-051bcb8918c7", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Some weights of the model checkpoint at sberbank-ai/ruBert-base were not used when initializing BertForSequenceClassification: ['cls.predictions.bias', 'cls.predictions.transform.dense.weight', 'cls.predictions.transform.dense.bias', 'cls.predictions.transform.LayerNorm.weight', 'cls.predictions.transform.LayerNorm.bias', 'cls.predictions.decoder.weight', 'cls.predictions.decoder.bias', 'cls.seq_relationship.weight', 'cls.seq_relationship.bias']\n", + "- This IS expected if you are initializing BertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", + "- This IS NOT expected if you are initializing BertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", + "Some weights of BertForSequenceClassification were not initialized from the model checkpoint at sberbank-ai/ruBert-base and are newly initialized: ['classifier.weight', 'classifier.bias']\n", + "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n" + ] + } + ], + "source": [ + "#make bert\n", + "\n", + "classifier = BertClassifier(\n", + " model_path='sberbank-ai/ruBert-base',\n", + " tokenizer_path='sberbank-ai/ruBert-base',\n", + " n_classes=39,\n", + " epochs=10,\n", + " model_save_path='bert_fit_models/bert.pt'\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "2b3a3cb5-1dd5-42aa-9df7-903604ba28c4", + "metadata": {}, + "outputs": [], + "source": [ + "#prepare data to classification\n", + "classifier.preparation(\n", + " X_train=list(X_data),\n", + " y_train=list(y_data),\n", + " X_valid=list(X_val),\n", + " y_valid=list(y_val),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "54dacb80-c43f-47b1-83f9-490ad0d6d176", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:31<00:00, 1.33it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 1.6872646148563648 accuracy 0.5666815485681486\n", + "Val loss 1.412977649804649 accuracy 0.6115892139988525\n", + "----------\n", + "Epoch 2/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:32<00:00, 1.33it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 1.1436501777863928 accuracy 0.6886918808597488\n", + "Val loss 1.2984553687616225 accuracy 0.6374067699368904\n", + "----------\n", + "Epoch 3/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:32<00:00, 1.33it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 0.9005808831667718 accuracy 0.7508131896166848\n", + "Val loss 1.2479785930946332 accuracy 0.6666666666666666\n", + "----------\n", + "Epoch 4/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:32<00:00, 1.33it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 0.7234191348244037 accuracy 0.7962242489954717\n", + "Val loss 1.2792062138062004 accuracy 0.6580608146873207\n", + "----------\n", + "Epoch 5/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:30<00:00, 1.33it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 0.5877058356572703 accuracy 0.8332164041074048\n", + "Val loss 1.3536883816464778 accuracy 0.6678141135972461\n", + "----------\n", + "Epoch 6/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:30<00:00, 1.33it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 0.49206937486923547 accuracy 0.8616620957969259\n", + "Val loss 1.4424607625248236 accuracy 0.6752725186460126\n", + "----------\n", + "Epoch 7/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:25<00:00, 1.34it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 0.40955075885392533 accuracy 0.8821353402640475\n", + "Val loss 1.5361568299250319 accuracy 0.6620768789443487\n", + "----------\n", + "Epoch 8/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1960/1960 [24:25<00:00, 1.34it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train loss 0.3543910782568024 accuracy 0.899292046686651\n", + "Val loss 1.6124461362428895 accuracy 0.6712564543889844\n", + "----------\n", + "Epoch 9/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " 58%|██████████████████████▌ | 1132/1960 [14:04<10:16, 1.34it/s]IOPub message rate exceeded.\n", + "The Jupyter server will temporarily stop sending output\n", + "to the client in order to avoid crashing it.\n", + "To change this limit, set the config variable\n", + "`--ServerApp.iopub_msg_rate_limit`.\n", + "\n", + "Current values:\n", + "ServerApp.iopub_msg_rate_limit=1000.0 (msgs/sec)\n", + "ServerApp.rate_limit_window=3.0 (secs)\n", + "\n" + ] + } + ], + "source": [ + "#train\n", + "classifier.train()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "8dece2c7-b3be-4e69-b51b-a5a1b70bfaaf", + "metadata": {}, + "outputs": [], + "source": [ + "#save best model again\n", + "\n", + "torch.save(classifier.model,'bert_magnus_opum.pt')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0e3977a9-ddeb-46e1-9b2a-46fc7b31ea1a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#load bert and truncate last layer\n", + "#get the embeddings layer\n", + "\n", + "model = torch.load('bert_opossum_best_0.6753.pt')\n", + "model = model.bert\n", + "model.to(device)\n", + "pass\n", + "\n", + "#load tokenizer\n", + "tokenizer = BertTokenizer.from_pretrained('sberbank-ai/ruBert-base')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "defe53ec-baa1-45f8-8d52-74ef2b425828", + "metadata": {}, + "outputs": [], + "source": [ + "#get token and embedding functions\n", + "\n", + "def get_token(text):\n", + " return tokenizer.encode_plus(\n", + " text,\n", + " add_special_tokens=True,\n", + " max_length=512,\n", + " return_token_type_ids=False,\n", + " truncation=True,\n", + " padding='max_length',\n", + " return_attention_mask=True,\n", + " return_tensors='pt')\n", + "\n", + "def get_embeddings(text):\n", + " encoding = get_token(text)\n", + " out = {\n", + " 'text': text,\n", + " 'input_ids': encoding['input_ids'].flatten(),\n", + " 'attention_mask': encoding['attention_mask'].flatten()\n", + " }\n", + "\n", + " input_ids = out[\"input_ids\"].to(device)\n", + " attention_mask = out[\"attention_mask\"].to(device)\n", + "\n", + " outputs = model(\n", + " input_ids=input_ids.unsqueeze(0),\n", + " attention_mask=attention_mask.unsqueeze(0)\n", + " )\n", + " return outputs[1].cpu().detach().numpy()[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "14627fdd-fa38-4cb8-b4c0-70a83f22c00e", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|█████████████████████████████████████| 17422/17422 [10:11<00:00, 28.48it/s]\n" + ] + } + ], + "source": [ + "#get embeddings from text\n", + "\n", + "df['emb'] = df.r_text.progress_apply(get_embeddings)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "b23c2f54-9533-4fac-a28f-db02f97d4ce6", + "metadata": {}, + "outputs": [], + "source": [ + "#split data again\n", + "\n", + "X_full = np.asarray([a for a in df['emb'].values])\n", + "y_full = df['type'].values.astype(int)\n", + "\n", + "X_data, X_val, y_data, y_val = train_test_split(X_full, y_full, test_size=0.1, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "142b7f1a-4701-48a0-a801-f275efe683a4", + "metadata": {}, + "outputs": [], + "source": [ + "## check upsampling data\n", + "## permutation data\n", + "\n", + "\n", + "np.random.seed(77112)\n", + "\n", + "class_size=833\n", + "X_data_r, y_data_r = [],[]\n", + "\n", + "\n", + "for d in np.unique(y_data):\n", + " X_data_r.append(resample(X_data[y_data==d],\n", + " replace=True,\n", + " n_samples=833,\n", + " random_state=42))\n", + " y_data_r.append(np.full([class_size],d))\n", + "\n", + "X_data, y_data = np.vstack(X_data_r), np.hstack(y_data_r)\n", + "\n", + "permutations = np.random.permutation(len(X_data))\n", + "\n", + "X_data, y_data = X_data[permutations], y_data[permutations]" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "dc89ab58-527d-4691-8ae0-37281426f3e9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(32487, 768)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X_data.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "565440c4-0f36-4b20-804b-74ea26e03fdc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.03843947217441193\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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QoUKRnO/cuVKHDp0yGpzf+HCBURERJg87yKCw4cPY8mSJQXOvWFOzJ37+vXrw87OzuJ5v3DhgsnzrtFoHtvcz5gxAx06dMhz7o8fP46VK1di3759Js07AOzZswfh4eG4cOECGjRogB9//BEpKSmoV68eunTpgl69esHDw8Mo5tq1ayhTpgxcXV2N9k1+RY1er8fp06exfPly7N69G9WqVYODgwMGDBiAMWPG5Dn/u3fvxpIlS3D16lW4urpi165dmDlzJgICApCUlKS8f9vb2yv7Lzw8HCtXrkSNGjXw9NNP47nnnoO3t7fyGs/KysLp06fRsmVLpWhdvnw59u3bh9dee81oX964cQM6nQ6NGjUyGtOaNWuQmJiIrl27QqvVQqfT4ebNm9i2bRu0Wi3q1KmDxo0b48knn1QKxu+++w6Ojo5ISEjA22+/jenTp8Pf37/AgmTz5s1YsmQJsrOzUaNGDUyePBnJyckICQlBXFwcHBwcoNVqUalSpUcqbkrMl0bGxcWhW7duWL16dZ5/6e7fvx9fffUVDh8+jGHDhmHChAlITU1FQEAAatasCQCoVKkSfH190aNHD7Rp08boOVJSUnD48GFUrVoVI0aMwKJFi9C+fXsA9yvuadOm4fr169iwYYPRm+WePXswduxYfPHFF0oxsHfvXsydOxcZGRl48skn8c8//+DEiRPw8/PDggULlPibN29i8uTJqFevHmbNmoWMjAycPHkSBw4cwHfffYfMzEy0aNECgYGBCAgIwH/+8x+sW7cOHh4e0Gq1mDhxIn799Vd4enqiVq1aiIyMRFRUFEJDQxEaGorhw4cjLCxMKey6d++OmjVrYvTo0dBoNPj999/x888/w97eHsuWLUO5cuXQqVMnbNy4EU2bNsXFixcxffp0REdHY/z48bneRIH7f8F1794dX331lTIvp0+fxuuvvw6tVotWrVohLS0NR48ehZubG6ZPn46XXnoJX375pVGhEhcXh7CwMOXAP3XqFObNm4eePXsa9Wd4wx8yZAicnJyQlZWFy5cvY+fOnTh48CAcHBwQGhqKF198UXkzHDNmDCpUqAB/f380b94crq6uRn/B5fUCe+mll3Dv3j0MHToUer0eP/zwA37//XfMmzcPvXv3zhXzzDPPwM3NTfnLd9q0aXj66afh7e2N9evXIyoqCj169EBYWBiqV68O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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def classes_plot(y_val,y_pred):\n", + " vd = pd.DataFrame([y_pred,y_val],index=['pred','real']).T\n", + " vd_pred_true = vd[vd.pred==vd.real].groupby(by='real').count()\n", + " vd_pred_all = vd.groupby(by='real').count()\n", + " vd_pred = pd.concat([vd_pred_true,vd_pred_all-vd_pred_true],axis=1)\n", + " # vd_pred.false[vd_pred.isna().iloc[:,0]]=vd.real[vd_pred.isna().iloc[:,0]].values\n", + " vd_pred.columns = ['true','false']\n", + " #print(vd_pred_all.pred[vd_pred.false.isna().values])\n", + " #print(vd_pred_true.pred[vd_pred_true[vd_pred.false.isna()]])\n", + " vd_pred.false[vd_pred.false.isna()]=vd_pred_all.pred[vd_pred.false.isna().values]\n", + " vd_pred = vd_pred.fillna(0)\n", + " vd_pred_sum = vd_pred.sum()\n", + " print(vd_pred_sum.true/(vd_pred_sum.true+vd_pred_sum.false))\n", + " return vd_pred.plot(kind='bar',stacked=True,color=['#66FF99','#ff6666'],rot=70)\n", + "\n", + "classes_plot(y_val, y_pred)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "78fc9075-6f7f-442a-addc-42eee1a6d83e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.6523235800344234\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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T8fevXvRsmVLZVn79u2RnJyMQ4cOKcuuXLmCs2fPon379rZIi4iIiOyc2WdkMjIysG/fPgDAjRs3kJaWhq1btwIAAgICcPnyZSxfvhxdu3aFu7s74uLisGLFCsTHx2P+/PnK+/j5+SE4OBhvv/02Jk6ciLJly2Lu3Lnw9PREaGhoETWPiIiISjKzC5nExESMGTPGaJnh55UrV6JWrVrIzs7G3LlzcffuXTg7O8PPzw/Tpk2Dt7e3Udy8efMwc+ZMTJkyBTk5OQgODsa7777LWX2JiIjIJGZXDB4eHrhw4UKB60RFRZn0XpUqVcKMGTMwY8YMc9MgIiIiss0YGSIiIiJrYCFDREREdouFDBEREdktFjJERERkt1jIEBERkd1iIUNERER2i4UMERER2S0WMkRERGS3WMgQERGR3WIhQ0RERHaLhQwRERHZLRYyREREZLdYyBAREZHdYiFDREREdouFDBEREdktFjJERERkt1jIEBERkd1iIUNERER2i4UMERER2S0WMkRERGS3WMgQERGR3WIhQ0RERHaLhQwRERHZLRYyREREZLdYyBAREZHdYiFDREREdouFDBEREdktFjJERERkt1jIEBERkd1iIUNERER2i4UMERER2S0WMkRERGS3WMgQERGR3WIhQ0RERHbLsbgTILIGrVYDrVYDAHBw0Br9X68X6PVSbLkREVHRYSFDJY5Wq0EVN2doHByMlru4OAMARKdD0t0MFjNERCUACxkqcbRazf0iJioKiI01frF2bWgiIqDValjIEBGVACxkqOSKjQViYoo7CyIisiKzC5lr164hKioKJ06cQHR0NBo1aoSNGzcqr6elpWHFihXYt28frl69CicnJ3h7e2PcuHHw9PRU1vv777/RuXPnXO/v4+ODNWvWWNgcIiIiKk3MLmSio6Oxb98++Pj4QK/XQ8T49PzNmzfx/fff45lnnsHYsWNx7949fPHFFxgwYADWr1+Pxo0bG60/fvx4tGnTRvm5QoUKFjaFiIiIShuzC5mQkBB06dIFADBp0iScPn3a6HUPDw/s2LEDzs7OyrLAwECEhITgm2++weTJk43Wr1+/Pnx9fS1InYiIiEo7swsZrbbgqWfKly+fa1mFChVQr149xMXFmbs5IiIionzZZLBvSkoKoqOj8eSTT+Z6berUqRg3bhzc3NzQuXNnTJgwAW5u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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#fit svc\n", + "\n", + "import numpy as np\n", + "from sklearn.pipeline import make_pipeline\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.metrics import f1_score\n", + "\n", + "from sklearn.svm import SVC\n", + "clf = make_pipeline(StandardScaler(),\n", + " SVC(gamma='auto'))\n", + "clf.fit(X_data, y_data)\n", + "y_pred = clf.predict(X_val)\n", + "classes_plot(y_val, y_pred)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "2e8eeba1-44d6-4036-8413-785cc99bc9c9", + "metadata": {}, + "outputs": [], + "source": [ + "#fit random_forest\n", + "\n", + "import numpy as np\n", + "from sklearn.pipeline import make_pipeline\n", + "from sklearn.ensemble import RandomForestClassifier\n", + "from sklearn.metrics import f1_score\n", + "\n", + "from sklearn.svm import SVC\n", + "clf = make_pipeline(RandomForestClassifier(n_jobs=-1))\n", + "clf.fit(X_data, y_data)\n", + "y_pred = clf.predict(X_val)\n", + "classes_plot(y_val, y_pred)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2cc2f449-c297-4294-a03e-235d76a5ad7f", + "metadata": {}, + "outputs": [], + "source": [ + "#fit Linear SVC\n", + "\n", + "\n", + "from sklearn.pipeline import make_pipeline\n", + "from sklearn.naive_bayes import MultinomialNB, ComplementNB\n", + "from sklearn.metrics import f1_score\n", + "\n", + "from sklearn.svm import LinearSVC\n", + "clf = make_pipeline(LinearSVC(C=1000, penalty='l1', max_iter=500, dual=False))\n", + "clf.fit(X_data, y_data)\n", + "y_pred = clf.predict(X_val)\n", + "classes_plot(y_val, y_pred)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hack", + "language": "python", + "name": "hack" + }, + "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.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}