Upload 42 files
Browse files- .gitattributes +9 -35
- LICENSE +21 -0
- README.md +37 -13
- UIT-ViCoV19QA/README.md +52 -0
- UIT-ViCoV19QA/UIT-ViCoV19-QA_main.ipynb +1 -0
- UIT-ViCoV19QA/dataset/1_ans/UIT-ViCoV19QA_test.csv +3 -0
- UIT-ViCoV19QA/dataset/1_ans/UIT-ViCoV19QA_train.csv +3 -0
- UIT-ViCoV19QA/dataset/1_ans/UIT-ViCoV19QA_val.csv +3 -0
- UIT-ViCoV19QA/dataset/2_ans/UIT-ViCoV19QA_test.csv +3 -0
- UIT-ViCoV19QA/dataset/2_ans/UIT-ViCoV19QA_train.csv +3 -0
- UIT-ViCoV19QA/dataset/2_ans/UIT-ViCoV19QA_val.csv +3 -0
- UIT-ViCoV19QA/dataset/3_ans/UIT-ViCoV19QA_test.csv +3 -0
- UIT-ViCoV19QA/dataset/3_ans/UIT-ViCoV19QA_train.csv +3 -0
- UIT-ViCoV19QA/dataset/3_ans/UIT-ViCoV19QA_val.csv +3 -0
- UIT-ViCoV19QA/dataset/4_ans/UIT-ViCoV19QA_test.csv +3 -0
- UIT-ViCoV19QA/dataset/4_ans/UIT-ViCoV19QA_train.csv +3 -0
- UIT-ViCoV19QA/dataset/4_ans/UIT-ViCoV19QA_val.csv +3 -0
- UIT-ViCoV19QA/dataset/UIT-ViCoV19QA.csv +3 -0
- UIT-ViCoV19QA/models/cnn.py +274 -0
- UIT-ViCoV19QA/models/layers.py +68 -0
- UIT-ViCoV19QA/models/rnn1.py +241 -0
- UIT-ViCoV19QA/models/rnn2.py +206 -0
- UIT-ViCoV19QA/models/seq2seq.py +39 -0
- UIT-ViCoV19QA/models/transformer.py +271 -0
- app.py +81 -0
- dataset/1_ans/UIT-ViCoV19QA_test.csv +3 -0
- dataset/1_ans/UIT-ViCoV19QA_train.csv +3 -0
- dataset/1_ans/UIT-ViCoV19QA_val.csv +3 -0
- dataset/2_ans/UIT-ViCoV19QA_test.csv +3 -0
- dataset/2_ans/UIT-ViCoV19QA_train.csv +3 -0
- dataset/2_ans/UIT-ViCoV19QA_val.csv +3 -0
- dataset/3_ans/UIT-ViCoV19QA_test.csv +3 -0
- dataset/3_ans/UIT-ViCoV19QA_train.csv +3 -0
- dataset/3_ans/UIT-ViCoV19QA_val.csv +3 -0
- dataset/4_ans/UIT-ViCoV19QA_test.csv +3 -0
- dataset/4_ans/UIT-ViCoV19QA_train.csv +3 -0
- dataset/4_ans/UIT-ViCoV19QA_val.csv +3 -0
- dataset/UIT-ViCoV19QA.csv +3 -0
- models/README.md +3 -0
- models/vi-medical-t5-finetune-qa/tokenizer_config.json +3 -0
- notebooks/vi-medical-t5-finetune-qa.ipynb +0 -0
- requirements.txt +11 -0
.gitattributes
CHANGED
@@ -1,35 +1,9 @@
|
|
1 |
-
*.
|
2 |
-
|
3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
-
|
5 |
-
*.
|
6 |
-
*.
|
7 |
-
*.
|
8 |
-
|
9 |
-
|
10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
1 |
+
*.csv filter=lfs diff=lfs merge=lfs -text
|
2 |
+
models/* filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
models/vi-medical-t5-finetune-qa/* filter=lfs diff=lfs merge=lfs -text
|
5 |
+
*.safetensorsin filter=lfs diff=lfs merge=lfs -text
|
6 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
7 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
8 |
+
models/vi-medical-t5-finetune-qa/checkpoint-75969/*.safetensors filter=lfs diff=lfs merge=lfs -text
|
9 |
+
models/vi-medical-t5-finetune-qa/model.safetensors filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2025 Danh Tran
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README.md
CHANGED
@@ -1,13 +1,37 @@
|
|
1 |
-
---
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
license: mit
|
3 |
+
title: Vietnames Medical T5 Finetune Question and Answer
|
4 |
+
sdk: gradio
|
5 |
+
colorFrom: green
|
6 |
+
colorTo: green
|
7 |
+
python_verison: 3.10.12
|
8 |
+
sdk_version: 5.23.3
|
9 |
+
---
|
10 |
+
# Vietnames Medical T5 Finetune Question and Answer
|
11 |
+
|
12 |
+
## Dataset
|
13 |
+
You can download dataset at this url: https://github.com/triet2397/UIT-ViCoV19QA
|
14 |
+
## Metrics
|
15 |
+
- Loss:
|
16 |
+
- Trainging Set: 0.306100.
|
17 |
+
- Validation Set: 0.322764.
|
18 |
+
|
19 |
+
## Demo
|
20 |
+
You can try this project demo at:
|
21 |
+
|
22 |
+
## Usage
|
23 |
+
- Install Denpendencies:
|
24 |
+
```bash
|
25 |
+
pip install -r requirements.txt
|
26 |
+
```
|
27 |
+
- Download download the 'danhtran2mind/vi-medical-t5-finetune-qa' model from Hugging Face using the following commands:
|
28 |
+
```bash
|
29 |
+
cd models
|
30 |
+
git lfs clone https://huggingface.co/danhtran2mind/vi-medical-t5-finetune-qa
|
31 |
+
cd ..
|
32 |
+
```
|
33 |
+
- Run Gradio app:
|
34 |
+
```bash
|
35 |
+
python app.py
|
36 |
+
```
|
37 |
+
- Your app will run at `localhost:7860`
|
UIT-ViCoV19QA/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# UIT-ViCoV19QA: A Dataset for COVID-19 Community-based Question Answering on Vietnamese Language
|
2 |
+
Authors: Triet Minh Thai, Ngan Ha-Thao Chu, Anh Tuan Vo, and Son T. Luu.
|
3 |
+
|
4 |
+
Description: The UIT-ViCoV19QA dataset comprises 4,500 Vietnamese question-answer pairs about COVID-19 pandemic collected from trusted medical FAQ sources, each question has at least one answer and at most four unique paraphrased answers.
|
5 |
+
|
6 |
+
The statistics of the dataset are shown in the table below.
|
7 |
+
|
8 |
+
|No. | Stats. | Train | Dev. | Test | All |
|
9 |
+
| :-------- | :------------------------------- | ------: | ------: | ------: | ------: |
|
10 |
+
| Answer 1 | Number of question-answer pairs | 3500 | 500 | 500 | 4500 |
|
11 |
+
| | Average question length | 31.44 | 33.66 | 32.32 | 31.79 |
|
12 |
+
| | Average answer length | 120.53 | 116.04 | 118.11 | 119.76 |
|
13 |
+
| | Question vocabulary size | 4396 | 1869 | 1770 | 4924 |
|
14 |
+
| | Answer vocabulary size | 8537 | 3689 | 3367 | 9411 |
|
15 |
+
|Answer 2 | Number of question-answer pairs | 1390 | 209 | 201 | 1800 |
|
16 |
+
| | Average question length | 35.56 | 39.22 | 39.72 | 36.45 |
|
17 |
+
| | Average answer length | 40.54 | 39.25 | 42.73 | 40.64 |
|
18 |
+
| | Question vocabulary size | 2883 | 1269 | 1207 | 3305 |
|
19 |
+
| | Answer vocabulary size | 2632 | 1098 | 1129 | 2949 |
|
20 |
+
| Answer 3 | Number of question-answer pairs | 542 | 79 | 79 | 700 |
|
21 |
+
| | Average question length | 34.77 | 36.7 | 39.28 | 35.49 |
|
22 |
+
| | Average answer length | 28.68 | 26.43 | 30.89 | 28.67 |
|
23 |
+
| | Question vocabulary size | 1836 | 717 | 693 | 2111 |
|
24 |
+
| | Answer vocabulary size | 1554 | 503 | 585 | 1753 |
|
25 |
+
| Answer 4 | Number of question-answer pairs | 272 | 39 | 39 | 350 |
|
26 |
+
| | Average question length | 36.57 | 37.59 | 42.15 | 37.1 |
|
27 |
+
| | Average answer length | 29.75 | 29.03 | 35.72 | 30.25 |
|
28 |
+
| | Question vocabulary size | 1315 | 470 | 460 | 1519 |
|
29 |
+
| | Answer vocabulary size | 924 | 353 | 374 | 1075 |
|
30 |
+
|
31 |
+
Link to publication: https://aclanthology.org/2022.paclic-1.88/.
|
32 |
+
|
33 |
+
The dataset is used only for research purposes.
|
34 |
+
|
35 |
+
Some parts of the source code were inherited from the publication at https://github.com/barshana-banerjee/ParaQA_Experiments.git.
|
36 |
+
|
37 |
+
# Contact information
|
38 |
+
Mr. Triet Minh Thai: [email protected]
|
39 |
+
Mr. Son T. Luu: [email protected]
|
40 |
+
|
41 |
+
# Citation
|
42 |
+
@inproceedings{thai-etal-2022-uit,
|
43 |
+
title = "{UIT}-{V}i{C}o{V}19{QA}: A Dataset for {COVID}-19 Community-based Question Answering on {V}ietnamese Language",
|
44 |
+
author = "Thai, Triet and Thao-Ha, Ngan Chu and Vo, Anh and Luu, Son",
|
45 |
+
booktitle = "Proceedings of the 36th Pacific Asia Conference on Language, Information and Computation",
|
46 |
+
month = oct,
|
47 |
+
year = "2022",
|
48 |
+
address = "Manila, Philippines",
|
49 |
+
publisher = "De La Salle University",
|
50 |
+
url = "https://aclanthology.org/2022.paclic-1.88",
|
51 |
+
pages = "801--810",
|
52 |
+
}
|
UIT-ViCoV19QA/UIT-ViCoV19-QA_main.ipynb
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Import Packages and libraries","metadata":{}},{"cell_type":"code","source":"%%capture\n!pip install numpy==1.17.4\n!pip install nltk==3.4.5\n!pip install torchtext==0.4.0\n!pip install scikit_learn==0.23.2\n!pip install spacy==2.3.5\n!pip install textblob==0.15.3\n!pip install torch==1.6.0 \n!pip install torchvision==0.7.0\n!pip install tqdm\n!pip install underthesea==1.3.3\n!pip install rouge_score","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:54:40.390494Z","iopub.execute_input":"2023-02-12T04:54:40.390942Z","iopub.status.idle":"2023-02-12T04:56:23.604920Z","shell.execute_reply.started":"2023-02-12T04:54:40.390903Z","shell.execute_reply":"2023-02-12T04:56:23.603544Z"},"trusted":true},"execution_count":9,"outputs":[]},{"cell_type":"code","source":"import nltk\nnltk.download('wordnet')\n\nimport os\nimport math\nimport random\nimport argparse\nfrom pathlib import Path\nimport re\nimport numpy as np\nimport pandas as pd\nimport time\nimport gc\nimport sys\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchtext.data import Field, Example, Dataset\nfrom torchtext.data import BucketIterator\nimport torch.nn.functional as F\n\nfrom sklearn.model_selection import train_test_split\n\nfrom tqdm import tqdm\nfrom tqdm.notebook import tqdm_notebook\n\n%rm -rf ./UIT-ViCoV19QA\n!git clone https://github.com/minhtriet2397/UIT-ViCoV19QA.git\n\nsys.path.insert(0, '..')\nsys.path.insert(0, '/kaggle/working/UIT-ViCoV19QA/models')\n%cd /kaggle/working/UIT-ViCoV19QA/models\n%pwd\n\nsys.argv=['']\ndel sys","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:56:23.607682Z","iopub.execute_input":"2023-02-12T04:56:23.608107Z","iopub.status.idle":"2023-02-12T04:56:27.462112Z","shell.execute_reply.started":"2023-02-12T04:56:23.608063Z","shell.execute_reply":"2023-02-12T04:56:27.460470Z"},"trusted":true},"execution_count":10,"outputs":[{"name":"stderr","text":"[nltk_data] Downloading package wordnet to /usr/share/nltk_data...\n[nltk_data] Package wordnet is already up-to-date!\n","output_type":"stream"},{"name":"stdout","text":"Cloning into 'UIT-ViCoV19QA'...\nremote: Enumerating objects: 62, done.\u001b[K\nremote: Counting objects: 100% (62/62), done.\u001b[K\nremote: Compressing objects: 100% (43/43), done.\u001b[K\nremote: Total 62 (delta 20), reused 51 (delta 15), pack-reused 0\u001b[K\nUnpacking objects: 100% (62/62), 1.72 MiB | 1.50 MiB/s, done.\n/kaggle/working/UIT-ViCoV19QA/models\n","output_type":"stream"}]},{"cell_type":"markdown","source":"# Main","metadata":{}},{"cell_type":"code","source":"\"\"\"Constants for the baseline models\"\"\"\nSEED = 42\nQUESTION = 'question'\n\nRNN_NAME = 'rnn'\nCNN_NAME = 'cnn'\nTRANSFORMER_NAME = 'transformer'\n\nATTENTION_1 = 'bahdanau'\nATTENTION_2 = 'luong'\n\nGPU = 'gpu'\nCPU = 'cpu'\nCUDA = 'cuda'\n\nCHECKPOINT_PATH = '/model/'\n\nANSWER_TOKEN = '<ans>'\nENTITY_TOKEN = '<ent>'\nEOS_TOKEN = '<eos>'\nSOS_TOKEN = '<sos>'\nPAD_TOKEN = '<pad>'\n\nSRC_NAME = 'src'\nTRG_NAME = 'trg'\n\npath = '/kaggle/working/'","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:56:27.464159Z","iopub.execute_input":"2023-02-12T04:56:27.464596Z","iopub.status.idle":"2023-02-12T04:56:27.471151Z","shell.execute_reply.started":"2023-02-12T04:56:27.464553Z","shell.execute_reply":"2023-02-12T04:56:27.470168Z"},"trusted":true},"execution_count":11,"outputs":[]},{"cell_type":"code","source":"import random\nimport numpy as np\n\ndef parse_args():\n \"\"\"Add arguments to parser\"\"\"\n parser = argparse.ArgumentParser(description='Verbalization dataset baseline models.')\n parser.add_argument('--model', default=RNN_NAME, type=str,\n choices=[RNN_NAME, CNN_NAME, TRANSFORMER_NAME], help='model to train the dataset')\n parser.add_argument('--input', default=QUESTION, type=str,\n choices=[QUESTION], help='use question as input')\n parser.add_argument('--attention', default=ATTENTION_2, type=str,\n choices=[ATTENTION_1, ATTENTION_2], help='attention layer for rnn model')\n parser.add_argument('--batch_size', default=8, type=int, help='batch size')\n parser.add_argument('--epochs_num', default=30, type=int, help='number of epochs')\n parser.add_argument('--answer_num', default=1, type=int, \n choices=[1,2,3,4], help='number of answer')\n args = parser.parse_args()\n return args\n\ndef set_SEED():\n SEED = 42\n random.seed(SEED)\n np.random.seed(SEED)\n torch.manual_seed(SEED)\n torch.cuda.manual_seed(SEED)\n torch.cuda.manual_seed_all(SEED)\n torch.backends.cudnn.enabled = False\n torch.backends.cudnn.benchmark = False\n torch.backends.cudnn.deterministic = True\n\nclass Checkpoint(object):\n \"\"\"Checkpoint class\"\"\"\n @staticmethod\n def save(model,cell, path):\n \"\"\"Save model using name\"\"\"\n name_tmp = model.name+\"_\"+ cell if model.name==RNN_NAME else model.name\n name = f'{name_tmp}.pt'\n torch.save(model.state_dict(), path+name)\n\n @staticmethod\n def load(model,path, name):\n \"\"\"Load model using name\"\"\"\n #name = f'{model.name}.pt'\n model.load_state_dict(torch.load(path+name))\n return model","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:56:27.474094Z","iopub.execute_input":"2023-02-12T04:56:27.474784Z","iopub.status.idle":"2023-02-12T04:56:27.487154Z","shell.execute_reply.started":"2023-02-12T04:56:27.474749Z","shell.execute_reply":"2023-02-12T04:56:27.486131Z"},"trusted":true},"execution_count":12,"outputs":[]},{"cell_type":"markdown","source":"## Import data and create torchtext dataset","metadata":{}},{"cell_type":"code","source":"from underthesea import word_tokenize\n\nclass VerbalDataset(object):\n \"\"\"VerbalDataset class\"\"\"\n \n def __init__(self,train,val,test):\n self.train = train\n self.val = val\n self.test = test\n self.train_data = None\n self.valid_data = None\n self.test_data = None\n self.src_field = None\n self.trg_field = None\n\n def _make_torchtext_dataset(self, data, fields):\n examples = [Example.fromlist(i, fields) for i in tqdm_notebook(data)]\n return Dataset(examples, fields)\n\n def load_data_and_fields(self, ):\n \"\"\"\n Load verbalization data\n Create source and target fields\n \"\"\"\n train, test, val = self.train, self.test, self.val\n \n train = train.melt(id_vars=['id',\"Question\"],value_name=\"Answer\")\n train = train[train['Answer'].astype(bool)].drop(['id','variable'],axis=1).values\n \n test = test.melt(id_vars=['id',\"Question\"],value_name=\"Answer\")\n test = test[test['Answer'].astype(bool)].drop(['id','variable'],axis=1).values\n \n val = val.melt(id_vars=['id',\"Question\"],value_name=\"Answer\")\n val = val[val['Answer'].astype(bool)].drop(['id','variable'],axis=1).values\n\n # create fields\n self.src_field = Field(tokenize=word_tokenize,\n init_token=SOS_TOKEN,\n eos_token=EOS_TOKEN,\n lower=True,\n include_lengths=True,\n batch_first=True)\n \n self.trg_field = Field(tokenize=word_tokenize,\n init_token=SOS_TOKEN,\n eos_token=EOS_TOKEN,\n lower=True,\n batch_first=True)\n\n fields_tuple = [(SRC_NAME, self.src_field), (TRG_NAME, self.trg_field)]\n\n # create toechtext datasets\n self.train_data = self._make_torchtext_dataset(train, fields_tuple)\n self.valid_data = self._make_torchtext_dataset(val, fields_tuple)\n self.test_data = self._make_torchtext_dataset(test, fields_tuple)\n\n # build vocabularies\n self.src_field.build_vocab(self.train_data, min_freq=1)\n self.trg_field.build_vocab(self.train_data, min_freq=1)\n print(\"i am field tuple\",fields_tuple)\n\n def get_data(self):\n \"\"\"Return train, validation and test data objects\"\"\"\n return self.train_data, self.valid_data, self.test_data\n\n def get_fields(self):\n \"\"\"Return source and target field objects\"\"\"\n return self.src_field, self.trg_field\n\n def get_vocabs(self):\n \"\"\"Return source and target vocabularies\"\"\"\n #print('self, trg field vocab: ', self.trg_field.vocab)\n return self.src_field.vocab, self.trg_field.vocab","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:56:27.488581Z","iopub.execute_input":"2023-02-12T04:56:27.488938Z","iopub.status.idle":"2023-02-12T04:56:27.506628Z","shell.execute_reply.started":"2023-02-12T04:56:27.488904Z","shell.execute_reply":"2023-02-12T04:56:27.505736Z"},"trusted":true},"execution_count":13,"outputs":[]},{"cell_type":"code","source":"set_SEED()\nargs = parse_args()\nanswer_num = args.answer_num\n\nset_ = ['train','val','test']\ntrain = pd.read_csv(f'{path}UIT-ViCoV19QA/dataset/{answer_num}_ans/UIT-ViCoV19QA_train.csv',na_filter=False,delimiter='|')\nval = pd.read_csv(f'{path}UIT-ViCoV19QA/dataset/{answer_num}_ans/UIT-ViCoV19QA_val.csv',na_filter=False,delimiter='|')\ntest = pd.read_csv(f'{path}UIT-ViCoV19QA/dataset/{answer_num}_ans/UIT-ViCoV19QA_test.csv',na_filter=False,delimiter='|')\n\ndataset = VerbalDataset(train,val,test)\ndataset.load_data_and_fields()\nsrc_vocab, trg_vocab = dataset.get_vocabs()\ntrain_data, valid_data, test_data = dataset.get_data()\n\nprint('--------------------------------')\nprint(f\"Training data: {len(train_data.examples)}\")\nprint(f\"Evaluation data: {len(valid_data.examples)}\")\nprint(f\"Testing data: {len(test_data.examples)}\")\nprint('--------------------------------')\nprint(f'Question example: {train_data.examples[2].src}\\n')\nprint(f'Answer example: {train_data.examples[2].trg}')\nprint('--------------------------------')\nprint(f\"Unique tokens in questions vocabulary: {len(src_vocab)}\")\nprint(f\"Unique tokens in answers vocabulary: {len(trg_vocab)}\")\nprint('--------------------------------')","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:56:27.508078Z","iopub.execute_input":"2023-02-12T04:56:27.508549Z","iopub.status.idle":"2023-02-12T04:57:40.844030Z","shell.execute_reply.started":"2023-02-12T04:56:27.508515Z","shell.execute_reply":"2023-02-12T04:57:40.842961Z"},"trusted":true},"execution_count":14,"outputs":[{"output_type":"display_data","data":{"text/plain":" 0%| | 0/3500 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"05a9e8b8ae224b9da9a92c5869ecf8b1"}},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/500 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"5d4189ed992b40a9be50fe21799441c1"}},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/500 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"b9457f3414b14bbfb685897ff5fa8aeb"}},"metadata":{}},{"name":"stdout","text":"i am field tuple [('src', <torchtext.data.field.Field object at 0x7f928e083990>), ('trg', <torchtext.data.field.Field object at 0x7f928e083050>)]\n--------------------------------\nTraining data: 3500\nEvaluation data: 500\nTesting data: 500\n--------------------------------\nQuestion example: ['tôi', 'đang', 'cho', 'con', 'bú', '(', '10', 'tháng', 'tuổi', ')', 'có', 'được', 'chủng', 'ngừa', 'vaccine', 'covid-19', 'không', '?', 'trẻ nhỏ', 'bao nhiêu', 'tháng', 'tuổi', 'mới', 'chủng', 'ngừa', 'được', 'vaccine', 'covid-19', 'ạ', '?', 'xin', 'cảm ơn', '!']\n\nAnswer example: ['chào', 'chị', ',', 'theo', 'hướng dẫn', 'của', 'bộ', 'y tế', ',', 'phụ nữ', 'đang', 'cho', 'con', 'bú', 'sẽ', 'hoãn', 'tiêm', 'vaccine', 'covid-19', 'trong', 'thời gian', 'này', '.', 'hiện nay', ',', 'mỗi', 'loại', 'vaccine', 'sẽ', 'chỉ định', 'ở', 'những', 'đối tượng', 'khác', 'nhau', 'như', 'vaccine covid-19', 'của', 'astrazeneca', 'chỉ định', 'tiêm chủng', 'cho', 'người', 'từ', '18', 'tuổi', 'trở lên', ',', 'vaccine', 'của', 'pfizer', '/', 'biontech', 'chỉ định', 'cho', 'trẻ', 'từ', '12', 'tuổi', 'trở lên', ',', 'chưa', 'có', 'vắc xin', 'nào', 'chỉ định', 'cho', 'trẻ', 'nhỏ', 'dưới', '12', 'tuổi', '.', 'cảm ơn', 'câu', 'hỏi', 'của', 'chị', '.', 'cảm ơn', 'chị', '.']\n--------------------------------\nUnique tokens in questions vocabulary: 4396\nUnique tokens in answers vocabulary: 8537\n--------------------------------\n","output_type":"stream"}]},{"cell_type":"markdown","source":"## Define MODEL","metadata":{}},{"cell_type":"code","source":"class Seq2Seq(nn.Module):\n def __init__(self, encoder, decoder, name):\n super().__init__()\n self.encoder = encoder\n self.decoder = decoder\n self.name = name\n\n def forward(self, src_tokens, src_lengths, trg_tokens, teacher_forcing_ratio=0.5):\n encoder_out = self.encoder(src_tokens, \n src_lengths=src_lengths)\n \n decoder_out = self.decoder(trg_tokens, encoder_out,\n src_tokens=src_tokens,\n teacher_forcing_ratio=teacher_forcing_ratio)\n return decoder_out","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:57:40.845634Z","iopub.execute_input":"2023-02-12T04:57:40.846239Z","iopub.status.idle":"2023-02-12T04:57:40.853175Z","shell.execute_reply.started":"2023-02-12T04:57:40.846199Z","shell.execute_reply":"2023-02-12T04:57:40.852098Z"},"trusted":true},"execution_count":15,"outputs":[]},{"cell_type":"code","source":"# Choose model here\nargs.model = CNN_NAME # CNN and Transformers don't apply Attention_1, Attention_2\nargs.attention = ATTENTION_1\ncell_name = 'gru'\n\nif args.model == RNN_NAME and args.attention == ATTENTION_1:\n from rnn1 import Encoder, Decoder\nelif args.model == RNN_NAME and args.attention == ATTENTION_2:\n from rnn2 import Encoder, Decoder\nelif args.model == CNN_NAME:\n from cnn import Encoder, Decoder\nelif args.model == TRANSFORMER_NAME:\n from transformer import Encoder, Decoder, NoamOpt","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:57:40.854778Z","iopub.execute_input":"2023-02-12T04:57:40.855209Z","iopub.status.idle":"2023-02-12T04:57:40.870049Z","shell.execute_reply.started":"2023-02-12T04:57:40.855164Z","shell.execute_reply":"2023-02-12T04:57:40.869129Z"},"trusted":true},"execution_count":16,"outputs":[]},{"cell_type":"code","source":"set_SEED()\nDEVICE = torch.device(CUDA if torch.cuda.is_available() else CPU)\n\nif args.model == RNN_NAME and args.attention == ATTENTION_2:\n encoder = Encoder(src_vocab, DEVICE, cell_name)\n decoder = Decoder(trg_vocab, DEVICE, cell_name)\nelse:\n encoder = Encoder(src_vocab, DEVICE)\n decoder = Decoder(trg_vocab, DEVICE)\nmodel = Seq2Seq(encoder, decoder, args.model).to(DEVICE)\n\nparameters_num = sum(p.numel() for p in model.parameters() if p.requires_grad)\n\nprint('--------------------------------')\nprint(f'Model: {args.model}')\nprint(f'Model input: {args.input}')\nif args.model == RNN_NAME:\n print(f'Attention: {args.attention}')\n print('Cell name: ',cell_name)\nprint(f'The model has {parameters_num:,} trainable parameters')\nprint('--------------------------------')","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:57:40.871571Z","iopub.execute_input":"2023-02-12T04:57:40.872416Z","iopub.status.idle":"2023-02-12T04:57:43.496740Z","shell.execute_reply.started":"2023-02-12T04:57:40.872379Z","shell.execute_reply":"2023-02-12T04:57:43.495579Z"},"trusted":true},"execution_count":17,"outputs":[{"name":"stdout","text":"--------------------------------\nModel: cnn\nModel input: question\nThe model has 28,191,065 trainable parameters\n--------------------------------\n","output_type":"stream"}]},{"cell_type":"markdown","source":"## Train model","metadata":{}},{"cell_type":"code","source":"class Evaluator(object):\n \"\"\"Evaluator class\"\"\"\n def __init__(self, criterion):\n self.criterion = criterion\n\n def evaluate(self, model, iterator, teacher_ratio=1.0):\n model.eval()\n epoch_loss = 0\n with torch.no_grad():\n for _, batch in enumerate(iterator):\n src, src_len = batch.src\n trg = batch.trg\n input_trg = trg if model.name == RNN_NAME else trg[:, :-1]\n output = model(src, src_len, input_trg, teacher_ratio)\n trg = trg.t() if model.name == RNN_NAME else trg[:, 1:]\n output = output.contiguous().view(-1, output.shape[-1])\n trg = trg.contiguous().view(-1)\n # output: (batch_size * trg_len) x output_dim\n # trg: (batch_size * trg_len)\n loss = self.criterion(output, trg)\n epoch_loss += loss.item()\n return epoch_loss / len(iterator)","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:57:43.500533Z","iopub.execute_input":"2023-02-12T04:57:43.500824Z","iopub.status.idle":"2023-02-12T04:57:43.508605Z","shell.execute_reply.started":"2023-02-12T04:57:43.500797Z","shell.execute_reply":"2023-02-12T04:57:43.507609Z"},"trusted":true},"execution_count":18,"outputs":[]},{"cell_type":"code","source":"from torch.cuda.amp import autocast, GradScaler\n\nclass Trainer(object):\n \"\"\"Trainer Class\"\"\"\n def __init__(self, optimizer, criterion, batch_size, device):\n self.optimizer = optimizer\n self.criterion = criterion\n self.batch_size = batch_size\n self.device = device\n self.evaluator = Evaluator(criterion=self.criterion)\n\n def _train_batch(self, model, iterator, teacher_ratio, clip):\n model.train()\n epoch_loss = 0\n #scaler = GradScaler()\n for _, batch in enumerate(tqdm_notebook(iterator)):\n src, src_len = batch.src\n trg = batch.trg\n self.optimizer.zero_grad()\n input_trg = trg if model.name == RNN_NAME else trg[:, :-1]\n output = model(src, src_len, input_trg, teacher_ratio)\n trg = trg.t() if model.name == RNN_NAME else trg[:, 1:]\n output = output.contiguous().view(-1, output.shape[-1])\n trg = trg.contiguous().view(-1)\n # output: (batch_size * trg_len) x output_dim\n # trg: (batch_size * trg_len)\n torch.cuda.empty_cache()\n loss = self.criterion(output, trg)\n loss.backward()\n torch.nn.utils.clip_grad_norm_(model.parameters(), clip)\n self.optimizer.step()\n epoch_loss += loss.item()\n \n return epoch_loss / len(iterator)\n\n def _get_iterators(self, train_data, valid_data, model_name):\n return BucketIterator.splits((train_data, valid_data),\n batch_size=self.batch_size,\n sort_within_batch=True if model_name == RNN_NAME else \\\n False,\n sort_key=lambda x: len(x.src),\n device=self.device)\n\n def _epoch_time(self, start_time, end_time):\n elapsed_time = end_time - start_time\n elapsed_mins = int(elapsed_time / 60)\n elapsed_secs = int(elapsed_time - (elapsed_mins * 60))\n return elapsed_mins, elapsed_secs\n\n def _log_epoch(self, train_loss, valid_loss, epoch, start_time, end_time):\n minutes, seconds = self._epoch_time(start_time, end_time)\n print(f'Epoch: {epoch+1:02} | Time: {minutes}m {seconds}s')\n print(f'\\tTrain Loss: {train_loss:.3f} | Train PPL: {np.exp(train_loss):7.3f}')\n print(f'\\t Val. Loss: {valid_loss:.3f} | Val. PPL: {np.exp(valid_loss):7.3f}')\n\n def _train_epoches(self, model, train_data, valid_data, path_, num_of_epochs, teacher_ratio, clip):\n best_valid_loss = float('inf')\n # pylint: disable=unbalanced-tuple-unpacking\n train_iterator, valid_iterator = self._get_iterators(train_data, valid_data, model.name)\n train_loss_list = []\n val_loss_list = []\n for epoch in range(num_of_epochs):\n start_time = time.time()\n train_loss = self._train_batch(model, train_iterator, teacher_ratio, clip)\n valid_loss = self.evaluator.evaluate(model, valid_iterator, teacher_ratio)\n \n train_loss_list.append(train_loss)\n val_loss_list.append(valid_loss)\n \n end_time = time.time()\n self._log_epoch(train_loss, valid_loss, epoch, start_time, end_time)\n if valid_loss < best_valid_loss:\n best_valid_loss = valid_loss\n Checkpoint.save(model,cell_name,path_)\n return train_loss_list, val_loss_list\n\n def train(self, model, train_data, valid_data, path_, num_of_epochs=20, teacher_ratio=1.0, clip=1):\n \"\"\"Train model\"\"\"\n return self._train_epoches(model, train_data, valid_data, path_, num_of_epochs, teacher_ratio, clip)","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:57:43.510381Z","iopub.execute_input":"2023-02-12T04:57:43.511005Z","iopub.status.idle":"2023-02-12T04:57:43.531297Z","shell.execute_reply.started":"2023-02-12T04:57:43.510969Z","shell.execute_reply":"2023-02-12T04:57:43.530280Z"},"trusted":true},"execution_count":19,"outputs":[]},{"cell_type":"code","source":"# create optimizer\nif args.model ==TRANSFORMER_NAME:\n for p in model.parameters():\n if p.dim() > 1:\n nn.init.xavier_uniform_(p)\n optimizer = NoamOpt(torch.optim.Adam(model.parameters(), lr=0, betas=(0.9, 0.98), eps=1e-9))\nelse:\n optimizer = optim.Adam(model.parameters(),lr=0.001)\n\nbatch_size = 8\nepochs=10\n\n# define criterion\ncriterion = nn.CrossEntropyLoss(ignore_index=trg_vocab.stoi[PAD_TOKEN])\n\ntrainer = Trainer(optimizer, criterion, batch_size, DEVICE)\ntrain_loss, val_loss = trainer.train(model, train_data, valid_data, path, num_of_epochs=epochs)","metadata":{"execution":{"iopub.status.busy":"2023-02-12T04:57:43.532550Z","iopub.execute_input":"2023-02-12T04:57:43.533240Z","iopub.status.idle":"2023-02-12T05:02:30.402067Z","shell.execute_reply.started":"2023-02-12T04:57:43.533204Z","shell.execute_reply":"2023-02-12T05:02:30.401321Z"},"trusted":true},"execution_count":20,"outputs":[{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"8ba4c23730ce4082adc7e68434ea1782"}},"metadata":{}},{"name":"stdout","text":"Epoch: 01 | Time: 0m 28s\n\tTrain Loss: 5.281 | Train PPL: 196.623\n\t Val. Loss: 4.216 | Val. PPL: 67.775\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"5f4d0b32027b46568806a7d354a5c1d7"}},"metadata":{}},{"name":"stdout","text":"Epoch: 02 | Time: 0m 27s\n\tTrain Loss: 4.260 | Train PPL: 70.826\n\t Val. Loss: 3.829 | Val. PPL: 46.032\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"b31778e68d504eee8b47c1d222a06225"}},"metadata":{}},{"name":"stdout","text":"Epoch: 03 | Time: 0m 28s\n\tTrain Loss: 3.869 | Train PPL: 47.907\n\t Val. Loss: 3.614 | Val. PPL: 37.105\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"e721a12b8c1044d592677509df1489f6"}},"metadata":{}},{"name":"stdout","text":"Epoch: 04 | Time: 0m 28s\n\tTrain Loss: 3.628 | Train PPL: 37.635\n\t Val. Loss: 3.497 | Val. PPL: 33.008\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"e2cb9b7f88cd45e18fce9790587d22bb"}},"metadata":{}},{"name":"stdout","text":"Epoch: 05 | Time: 0m 28s\n\tTrain Loss: 3.461 | Train PPL: 31.849\n\t Val. Loss: 3.420 | Val. PPL: 30.578\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"5e508c73ac384cb4894825dfa6479f26"}},"metadata":{}},{"name":"stdout","text":"Epoch: 06 | Time: 0m 28s\n\tTrain Loss: 3.305 | Train PPL: 27.254\n\t Val. Loss: 3.359 | Val. PPL: 28.772\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"83c37918834041fb8beee9e57fb328ae"}},"metadata":{}},{"name":"stdout","text":"Epoch: 07 | Time: 0m 28s\n\tTrain Loss: 3.204 | Train PPL: 24.640\n\t Val. Loss: 3.330 | Val. PPL: 27.945\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"09ad137b3f034180a265b82800e676da"}},"metadata":{}},{"name":"stdout","text":"Epoch: 08 | Time: 0m 28s\n\tTrain Loss: 3.103 | Train PPL: 22.255\n\t Val. Loss: 3.307 | Val. PPL: 27.293\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"881a973adcce47d5b08d5cf765583076"}},"metadata":{}},{"name":"stdout","text":"Epoch: 09 | Time: 0m 28s\n\tTrain Loss: 3.017 | Train PPL: 20.422\n\t Val. Loss: 3.298 | Val. PPL: 27.063\n","output_type":"stream"},{"output_type":"display_data","data":{"text/plain":" 0%| | 0/438 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"a7403b6050274dde9704403ef6ec5160"}},"metadata":{}},{"name":"stdout","text":"Epoch: 10 | Time: 0m 28s\n\tTrain Loss: 2.958 | Train PPL: 19.267\n\t Val. Loss: 3.283 | Val. PPL: 26.656\n","output_type":"stream"}]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport os \nos.chdir(r'/kaggle/working')\nfrom IPython.display import FileLink\n\nplt.plot(train_loss)\nplt.plot(val_loss)\nplt.title('model loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'val'], loc='upper left')\n\n#plt.savefig('loss.png')\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-02-12T05:02:30.403778Z","iopub.execute_input":"2023-02-12T05:02:30.404565Z","iopub.status.idle":"2023-02-12T05:02:30.626564Z","shell.execute_reply.started":"2023-02-12T05:02:30.404525Z","shell.execute_reply":"2023-02-12T05:02:30.625678Z"},"trusted":true},"execution_count":21,"outputs":[{"output_type":"display_data","data":{"text/plain":"<Figure size 432x288 with 1 Axes>","image/png":"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\n"},"metadata":{"needs_background":"light"}}]},{"cell_type":"markdown","source":"## Evaluation","metadata":{}},{"cell_type":"code","source":"val_ref = [list(filter(None, np.delete(i,[0,1]))) for i in val.values]\ntest_ref = [list(filter(None, np.delete(i,[0,1]))) for i in test.values]\n\nval_trg = []\ntest_trg = []\ntrg_ = [val_trg,test_trg]\nfor t in trg_:\n for i in val_ref:\n tmp=[]\n for j in i:\n s = word_tokenize(j)\n tmp.append(s)\n t.append(tmp)\n\nval_src = [i.src for i in valid_data.examples]\nnew_valid = [[val_src[i],val_trg[i]] for i in range(len(val_trg)) ]\ntest_src = [i.src for i in test_data.examples]\nnew_test = [[test_src[i],test_trg[i]] for i in range(len(test_trg))]","metadata":{"execution":{"iopub.status.busy":"2023-02-12T05:10:41.155405Z","iopub.execute_input":"2023-02-12T05:10:41.155774Z","iopub.status.idle":"2023-02-12T05:10:52.815140Z","shell.execute_reply.started":"2023-02-12T05:10:41.155744Z","shell.execute_reply":"2023-02-12T05:10:52.814150Z"},"trusted":true},"execution_count":28,"outputs":[]},{"cell_type":"code","source":"import nltk\nfrom nltk.translate.bleu_score import SmoothingFunction\nfrom rouge_score import rouge_scorer\n\nsmoothie = SmoothingFunction().method4\n\nclass BleuScorer(object):\n \"\"\"Blue scorer class\"\"\"\n def __init__(self):\n self.results = []\n self.results_meteor = []\n \n self.score = 0\n self.bleu_4 = 0\n self.meteor_score = 0\n self.rouge_score = 0\n \n self.instances = 0\n self.meteor_instances = 0\n\n def example_score(self, reference, hypothesis):\n \"\"\"Calculate blue score for one example\"\"\"\n bleu_1 = nltk.translate.bleu_score.sentence_bleu(reference, hypothesis,weights=(1,0,0,0),smoothing_function=SmoothingFunction().method4)\n bleu_4 = nltk.translate.bleu_score.sentence_bleu(reference, hypothesis,weights=(0.25,0.25,0.25,0.25),smoothing_function=SmoothingFunction().method4)\n return bleu_1, bleu_4\n \n def example_score_rouge(self, reference, hypothesis):\n scorer = rouge_scorer.RougeScorer(['rougeL'], use_stemmer=False)\n scores = []\n for i in reference:\n scores.append(scorer.score(i,hypothesis)['rougeL'][-1])\n return np.max(scores) #best\n \n \n def example_score_meteor(self, reference, hypothesis):\n \"\"\"Calculate blue score for one example\"\"\"\n return nltk.translate.meteor_score.meteor_score(reference,hypothesis)\n\n def data_score(self, data, predictor):\n \"\"\"Score complete list of data\"\"\"\n results_prelim = []\n for example in tqdm_notebook(data):\n #i = 1\n# src = [t.lower() for t in example.src]\n# reference = [t.lower() for t in example.trg]\n \n src = example[0]\n reference = [[string.lower() for string in sublist] for sublist in example[1]]\n\n #and calculate bleu score average of all hypothesis\n #hypothesis = predictor.predict(example.src)\n hypothesis = predictor.predict(src)\n bleu_1,bleu_4 = self.example_score(reference, hypothesis)\n meteor_score = self.example_score_meteor([' '.join(i) for i in reference], ' '.join(hypothesis))\n rouge_score = self.example_score_rouge([' '.join(i) for i in reference], ' '.join(hypothesis))\n \n f = open(\"result.txt\", \"a\")\n f.write('Question: '+\" \".join(src)+'\\n')\n for i in range(len(reference)):\n f.write('Reference_{}: '.format(i)+\" \".join(reference[i])+'\\n')\n f.write('Hypothesis: '+\" \".join(hypothesis)+'\\n')\n f.write('BLEU-1: '+ str(bleu_1*100)+'\\n')\n f.write('BLEU-4: '+str(bleu_4*100)+'\\n')\n f.write('METEOR: '+str(meteor_score*100)+'\\n')\n f.write('ROUGE-L: '+str(rouge_score*100)+'\\n\\n')\n \n f.close()\n \n \n results_prelim.append({\n 'question': '\"' + str(src) + '\"',\n 'reference': reference,\n 'hypothesis': hypothesis,\n 'bleu_1': bleu_1,\n 'bleu_4': bleu_4,\n 'meteor_score': meteor_score,\n 'rouge_score': rouge_score,\n \n })\n \n results = [max((v for v in results_prelim if v['question'] == x), key=lambda y:y['bleu_1']) for x in set(v['question'] for v in results_prelim)] \n\n with open(path+'result_output.txt', 'w') as f:\n for elem in results:\n f.write(\"%s\\n\" % elem)\n self.results.append(elem)\n self.score += elem['bleu_1']\n self.bleu_4 += elem['bleu_4']\n self.meteor_score += elem['meteor_score']\n self.rouge_score += elem['rouge_score']\n self.instances += 1\n return self.score / self.instances, self.bleu_4 / self.instances, self.meteor_score / self.instances, self.rouge_score / self.instances\n\n def average_score(self):\n \"\"\"Return bleu average score\"\"\"\n return self.score / self.instances, self.bleu_4 / self.instances\n \n def average_rouge_score(self):\n \"\"\"Return bleu average score\"\"\"\n return self.rouge_score / self.instances\n \n \n def data_meteor_score(self, data, predictor):\n \"\"\"Score complete list of data\"\"\"\n results_prelim = []\n for example in data:\n src = [t.lower() for t in example.src]\n reference = [t.lower() for t in example.trg]\n hypothesis = predictor.predict(example.src)\n meteor_score = self.example_score_meteor(' '.join(reference), ' '.join(hypothesis))\n results_prelim.append({\n 'question': '\"' + str(src) + '\"',\n 'reference': reference,\n 'hypothesis': hypothesis,\n 'meteor_score': meteor_score\n })\n results_meteor = [max((v for v in results_prelim if v['question'] == x), key=lambda y:y['meteor_score']) for x in set(v['question'] for v in results_prelim)] \n\n with open(path+'result_meteor_output.txt', 'w') as f:\n for elem in results_meteor:\n f.write(\"%s\\n\" % elem)\n self.results_meteor.append(elem)\n self.meteor_score += elem['meteor_score']\n self.meteor_instances += 1\n return self.meteor_score/self.meteor_instances\n \n def average_meteor_score(self):\n \"\"\"Return meteor average score\"\"\"\n return self.meteor_score/self.instances\n\n def reset(self):\n \"\"\"Reset object properties\"\"\"\n self.results = []\n self.results_meteor = []\n self.score = 0\n self.meteor_score = 0\n self.instances = 0\n self.meteor_instances = 0","metadata":{"execution":{"iopub.status.busy":"2023-02-12T05:05:50.377470Z","iopub.execute_input":"2023-02-12T05:05:50.378036Z","iopub.status.idle":"2023-02-12T05:05:50.427362Z","shell.execute_reply.started":"2023-02-12T05:05:50.378000Z","shell.execute_reply":"2023-02-12T05:05:50.426483Z"},"trusted":true},"execution_count":24,"outputs":[]},{"cell_type":"code","source":"class Predictor(object):\n \"\"\"Predictor class\"\"\"\n def __init__(self, model, src_vocab, trg_vocab, device):\n self.model = model\n self.src_vocab = src_vocab\n self.trg_vocab = trg_vocab\n self.device = device\n\n def _predict_step(self, tokens):\n self.model.eval()\n tokenized_sentence = [SOS_TOKEN] + [t.lower() for t in tokens] + [EOS_TOKEN]\n numericalized = [self.src_vocab.stoi[token] for token in tokenized_sentence]\n src_tensor = torch.LongTensor(numericalized).unsqueeze(0).to(self.device)\n\n with torch.no_grad():\n encoder_out = self.model.encoder(src_tensor)\n\n outputs = [self.trg_vocab.stoi[SOS_TOKEN]]\n\n # cnn positional embedding gives assertion error for tensor\n # of size > max_positions-1, we predict tokens for max_positions-2\n # to avoid the error\n for _ in range(self.model.decoder.max_positions-2):\n trg_tensor = torch.LongTensor(outputs).unsqueeze(0).to(self.device)\n\n with torch.no_grad():\n output = self.model.decoder(trg_tensor, encoder_out, src_tokens=src_tensor)\n\n prediction = output.argmax(2)[:, -1].item()\n\n if prediction == self.trg_vocab.stoi[EOS_TOKEN] or len(outputs)==500:\n break\n \n outputs.append(prediction)\n\n translation = [self.trg_vocab.itos[i] for i in outputs]\n\n return translation[1:] # , attention\n\n def _predict_rnn_step(self, tokens):\n self.model.eval()\n with torch.no_grad():\n tokenized_sentence = [SOS_TOKEN] + [t.lower() for t in tokens] + [EOS_TOKEN]\n numericalized = [self.src_vocab.stoi[t] for t in tokenized_sentence]\n\n src_len = torch.LongTensor([len(numericalized)]).to(self.device)\n tensor = torch.LongTensor(numericalized).unsqueeze(1).to(self.device)\n\n translation_tensor_logits = self.model(tensor.t(), src_len, None)\n\n translation_tensor = torch.argmax(translation_tensor_logits.squeeze(1), 1)\n translation = [self.trg_vocab.itos[t] for t in translation_tensor]\n\n return translation[1:] # , attention\n\n def predict(self, tokens):\n \"\"\"Perform prediction on given tokens\"\"\"\n return self._predict_rnn_step(tokens) if self.model.name == RNN_NAME else \\\n self._predict_step(tokens)","metadata":{"execution":{"iopub.status.busy":"2023-02-12T05:05:54.736292Z","iopub.execute_input":"2023-02-12T05:05:54.736655Z","iopub.status.idle":"2023-02-12T05:05:54.751475Z","shell.execute_reply.started":"2023-02-12T05:05:54.736624Z","shell.execute_reply":"2023-02-12T05:05:54.750546Z"},"trusted":true},"execution_count":25,"outputs":[]},{"cell_type":"code","source":"name = args.model+\"_\"+cell_name if args.model==RNN_NAME else args.model\nmodel = Checkpoint.load(model,path,'./{}.pt'.format(name))\n\nvalid_iterator, test_iterator = BucketIterator.splits(\n (valid_data, test_data),\n batch_size=8,\n sort_within_batch=True if args.model == RNN_NAME else False,\n sort_key=lambda x: len(x.src),\n device=DEVICE)\n\n# evaluate model\nvalid_loss = trainer.evaluator.evaluate(model, valid_iterator)\ntest_loss = trainer.evaluator.evaluate(model, test_iterator)\n\n# calculate blue score for valid and test data\npredictor = Predictor(model, src_vocab, trg_vocab, DEVICE)\n\n# # train_scorer = BleuScorer()\nvalid_scorer = BleuScorer()\ntest_scorer = BleuScorer()\n\nvalid_scorer.data_score(new_valid, predictor)\ntest_scorer.data_score(new_test, predictor)","metadata":{"execution":{"iopub.status.busy":"2023-02-12T05:05:59.035087Z","iopub.execute_input":"2023-02-12T05:05:59.035456Z","iopub.status.idle":"2023-02-12T05:07:51.964640Z","shell.execute_reply.started":"2023-02-12T05:05:59.035426Z","shell.execute_reply":"2023-02-12T05:07:51.963354Z"},"trusted":true},"execution_count":26,"outputs":[{"output_type":"display_data","data":{"text/plain":" 0%| | 0/500 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"5b1e766e58d04f1eb714a08c586e5c3a"}},"metadata":{}},{"name":"stdout","text":"| Test Loss: 3.169 | Test PPL: 23.787 |\n| Test Data Average BLEU score (0.13299530736768786, 0.08383683068952133) |\n| Test Data Average METEOR score 0.14519957374057366 |\n","output_type":"stream"}]},{"cell_type":"code","source":"print(f'| Val. Loss: {valid_loss:.3f} | Test PPL: {math.exp(valid_loss):7.3f} |')\nprint(f'| Val. Data Average BLEU1, BLEU4 score {valid_scorer.average_score()} |')\nprint(f'| Val. Data Average METEOR score {valid_scorer.average_meteor_score()} |')\nprint(f'| Test Loss: {test_loss:.3f} | Test PPL: {math.exp(test_loss):7.3f} |')\nprint(f'| Test Data Average BLEU1, BLEU4 score {test_scorer.average_score()} |')\nprint(f'| Test Data Average METEOR score {test_scorer.average_meteor_score()} |')","metadata":{"execution":{"iopub.status.busy":"2023-02-12T05:02:42.325507Z","iopub.status.idle":"2023-02-12T05:02:42.325985Z","shell.execute_reply.started":"2023-02-12T05:02:42.325740Z","shell.execute_reply":"2023-02-12T05:02:42.325764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"r = {'ppl':[round(math.exp(test_loss),3)],\n 'BLEU-1':[test_scorer.average_score()[0]*100],\n 'BLEU-4':[test_scorer.average_score()[1]*100],\n 'METEOR':[test_scorer.average_meteor_score()*100],\n 'ROUGE-L':[test_scorer.average_rouge_score()*100]}\n\ndf_result = pd.DataFrame(data=r)\n\nhtml = df_result.style.set_table_styles([{'selector': 'th', 'props': [('font-size', '15pt')]}]).set_properties(**{'font-size': '15pt'})\nhtml","metadata":{"execution":{"iopub.status.busy":"2023-02-12T05:09:12.132953Z","iopub.execute_input":"2023-02-12T05:09:12.133326Z","iopub.status.idle":"2023-02-12T05:09:12.198299Z","shell.execute_reply.started":"2023-02-12T05:09:12.133295Z","shell.execute_reply":"2023-02-12T05:09:12.197237Z"},"trusted":true},"execution_count":27,"outputs":[{"execution_count":27,"output_type":"execute_result","data":{"text/plain":"<pandas.io.formats.style.Styler at 0x7f91cc4f0150>","text/html":"<style type=\"text/css\">\n#T_c7a0a_ th {\n font-size: 15pt;\n}\n#T_c7a0a_row0_col0, #T_c7a0a_row0_col1, #T_c7a0a_row0_col2, #T_c7a0a_row0_col3, #T_c7a0a_row0_col4 {\n font-size: 15pt;\n}\n</style>\n<table id=\"T_c7a0a_\">\n <thead>\n <tr>\n <th class=\"blank level0\" > </th>\n <th class=\"col_heading level0 col0\" >ppl</th>\n <th class=\"col_heading level0 col1\" >BLEU-1</th>\n <th class=\"col_heading level0 col2\" >BLEU-4</th>\n <th class=\"col_heading level0 col3\" >METEOR</th>\n <th class=\"col_heading level0 col4\" >ROUGE-L</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th id=\"T_c7a0a_level0_row0\" class=\"row_heading level0 row0\" >0</th>\n <td id=\"T_c7a0a_row0_col0\" class=\"data row0 col0\" >23.787000</td>\n <td id=\"T_c7a0a_row0_col1\" class=\"data row0 col1\" >13.299531</td>\n <td id=\"T_c7a0a_row0_col2\" class=\"data row0 col2\" >8.383683</td>\n <td id=\"T_c7a0a_row0_col3\" class=\"data row0 col3\" >14.519957</td>\n <td id=\"T_c7a0a_row0_col4\" class=\"data row0 col4\" >27.549394</td>\n </tr>\n </tbody>\n</table>\n"},"metadata":{}}]}]}
|
UIT-ViCoV19QA/dataset/1_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:d254fafb6c9340b101bf478536af6e1dd7b1ffd516a820f2580e48df88794573
|
3 |
+
size 520161
|
UIT-ViCoV19QA/dataset/1_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3660454cae6ff01e7c0046708abfe46dc67357bb239ec27bb4aa7d692c941149
|
3 |
+
size 3711672
|
UIT-ViCoV19QA/dataset/1_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:18d4db7ec783e08f8cba280109b70b029c38aeecbdd72330eedc7cc52324687b
|
3 |
+
size 520352
|
UIT-ViCoV19QA/dataset/2_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:c42f217da35a5318dacd46f85e003ac370471fc2b3e491e4ead730fcf77d0685
|
3 |
+
size 582656
|
UIT-ViCoV19QA/dataset/2_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:85130ab449d23fe672e6a91b1791fdd5bae3b5b72bfc5f32620c5099bf82013f
|
3 |
+
size 4122052
|
UIT-ViCoV19QA/dataset/2_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:109b7905010d967ade5299b0de22211606685557fd09d785179206654ec941b6
|
3 |
+
size 579852
|
UIT-ViCoV19QA/dataset/3_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:188b82c5487b3bb6ff94bf654a1702f344c753c79e8bf27fcaf9df03f9bb6f55
|
3 |
+
size 600605
|
UIT-ViCoV19QA/dataset/3_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:284958313282493c3b04c3eca2fe60c640eda64a81bd218b5a1ea0b1b07bb52a
|
3 |
+
size 4240422
|
UIT-ViCoV19QA/dataset/3_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3cb2fd30ac52b1ff58eee680fa0135208841da39d873ed379841b88a27b822b4
|
3 |
+
size 595439
|
UIT-ViCoV19QA/dataset/4_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:99860bae4ae5043e869c8047558d7db6d40e76d174aed522b7f37d7931c64fc9
|
3 |
+
size 610868
|
UIT-ViCoV19QA/dataset/4_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:8e2e7f21cef6898d42eafc5ee094e9dac285e251af19f9f6b9c274d92f446881
|
3 |
+
size 4300607
|
UIT-ViCoV19QA/dataset/4_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:dfe58d5c3e89a404c2db0620e3e9c893e8e0e29bfeaab05b6650f7ca6e82946a
|
3 |
+
size 603979
|
UIT-ViCoV19QA/dataset/UIT-ViCoV19QA.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:65b147559695843829a0932fcaab9e6d1415d9821c3a0a3c1aa7ff8118a6ac6f
|
3 |
+
size 5515361
|
UIT-ViCoV19QA/models/cnn.py
ADDED
@@ -0,0 +1,274 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Seq2seq based: Convolutional Sequence to Sequence Learning
|
3 |
+
https://arxiv.org/abs/1705.03122
|
4 |
+
"""
|
5 |
+
import math
|
6 |
+
import torch
|
7 |
+
import torch.nn as nn
|
8 |
+
import torch.nn.functional as F
|
9 |
+
from utils.constants import PAD_TOKEN
|
10 |
+
from models.layers import Embedding, Linear, Conv1d, PositionalEmbedding, LearnedPositionalEmbedding
|
11 |
+
|
12 |
+
def extend_conv_spec(convolutions):
|
13 |
+
"""
|
14 |
+
Extends convolutional spec with default residual if it is not specified
|
15 |
+
"""
|
16 |
+
extended = []
|
17 |
+
for spec in convolutions:
|
18 |
+
if len(spec) == 3:
|
19 |
+
extended.append(spec)
|
20 |
+
elif len(spec) == 2:
|
21 |
+
extended.append(spec + (1,))
|
22 |
+
else:
|
23 |
+
raise Exception('invalid number of parameters in convolution spec ' + str(spec) + '. expected 2 or 3')
|
24 |
+
return tuple(extended)
|
25 |
+
|
26 |
+
class Encoder(nn.Module):
|
27 |
+
"""Encoder"""
|
28 |
+
def __init__(self, vocabulary, device, embed_dim=512, convolutions=((512, 3),) * 3,
|
29 |
+
dropout=0.5, max_positions=5000):
|
30 |
+
super().__init__()
|
31 |
+
self.vocabulary = vocabulary
|
32 |
+
input_dim = len(vocabulary)
|
33 |
+
self.padding_idx = vocabulary.stoi[PAD_TOKEN]
|
34 |
+
self.dropout = dropout
|
35 |
+
self.device = device
|
36 |
+
|
37 |
+
self.embed_tokens = Embedding(input_dim, embed_dim, self.padding_idx)
|
38 |
+
self.embed_positions = PositionalEmbedding(max_positions, embed_dim, self.padding_idx)
|
39 |
+
|
40 |
+
convolutions = extend_conv_spec(convolutions)
|
41 |
+
in_channels = convolutions[0][0]
|
42 |
+
self.embed2inchannels = Linear(embed_dim, in_channels)
|
43 |
+
self.projections = nn.ModuleList()
|
44 |
+
self.convolutions = nn.ModuleList()
|
45 |
+
self.residuals = []
|
46 |
+
|
47 |
+
layer_in_channels = [in_channels]
|
48 |
+
for _, (out_channels, kernel_size, residual) in enumerate(convolutions):
|
49 |
+
if residual == 0:
|
50 |
+
residual_dim = out_channels
|
51 |
+
else:
|
52 |
+
residual_dim = layer_in_channels[-residual]
|
53 |
+
self.projections.append(Linear(residual_dim, out_channels)
|
54 |
+
if residual_dim != out_channels else None)
|
55 |
+
if kernel_size % 2 == 1:
|
56 |
+
padding = kernel_size // 2
|
57 |
+
else:
|
58 |
+
padding = 0
|
59 |
+
self.convolutions.append(
|
60 |
+
nn.Conv1d(in_channels=in_channels,
|
61 |
+
out_channels=out_channels * 2,
|
62 |
+
kernel_size=kernel_size,
|
63 |
+
padding=padding)
|
64 |
+
)
|
65 |
+
self.residuals.append(residual)
|
66 |
+
in_channels = out_channels
|
67 |
+
layer_in_channels.append(out_channels)
|
68 |
+
|
69 |
+
self.inchannels2embed = Linear(in_channels, embed_dim)
|
70 |
+
|
71 |
+
def forward(self, src_tokens, **kwargs):
|
72 |
+
"""
|
73 |
+
Forward pass for convolutional encoder
|
74 |
+
Args:
|
75 |
+
src_tokens (LongTensor): (batch, src_len)
|
76 |
+
Returns:
|
77 |
+
conved (LongTensor): (batch, src_len, embed_dim)
|
78 |
+
combined (LongTensor): (batch, src_len, embed_dim)
|
79 |
+
"""
|
80 |
+
# embed tokens and positions
|
81 |
+
embedded = self.embed_tokens(src_tokens) + self.embed_positions(src_tokens)
|
82 |
+
embedded = F.dropout(embedded, p=self.dropout, training=self.training)
|
83 |
+
|
84 |
+
conv_input = self.embed2inchannels(embedded) # (batch, src_len, in_channels)
|
85 |
+
|
86 |
+
# used to mask padding in input
|
87 |
+
encoder_padding_mask = src_tokens.eq(self.padding_idx) # (batch, src_len)
|
88 |
+
if not encoder_padding_mask.any():
|
89 |
+
encoder_padding_mask = None
|
90 |
+
|
91 |
+
x = conv_input.permute(0, 2, 1) # (batch, in_channels, src_len)
|
92 |
+
residuals = [x]
|
93 |
+
# temporal convolutions
|
94 |
+
for proj, conv, res_layer in zip(self.projections, self.convolutions, self.residuals):
|
95 |
+
if res_layer > 0:
|
96 |
+
residual = residuals[-res_layer]
|
97 |
+
residual = residual if proj is None else proj(residual)
|
98 |
+
else:
|
99 |
+
residual = None
|
100 |
+
|
101 |
+
if encoder_padding_mask is not None:
|
102 |
+
x = x.masked_fill(encoder_padding_mask.unsqueeze(1), 0)
|
103 |
+
|
104 |
+
x = F.dropout(x, p=self.dropout, training=self.training)
|
105 |
+
if conv.kernel_size[0] % 2 == 1:
|
106 |
+
# padding is implicit in the conv
|
107 |
+
x = conv(x)
|
108 |
+
else:
|
109 |
+
padding_l = (conv.kernel_size[0] - 1) // 2
|
110 |
+
padding_r = conv.kernel_size[0] // 2
|
111 |
+
x = F.pad(x, (0, 0, 0, 0, padding_l, padding_r))
|
112 |
+
x = conv(x)
|
113 |
+
x = F.glu(x, dim=1)
|
114 |
+
|
115 |
+
# apply residual connection
|
116 |
+
if residual is not None:
|
117 |
+
x = (x + residual) * math.sqrt(0.5)
|
118 |
+
residuals.append(x)
|
119 |
+
|
120 |
+
conved = self.inchannels2embed(x.permute(0, 2, 1))
|
121 |
+
|
122 |
+
if encoder_padding_mask is not None:
|
123 |
+
conved = conved.masked_fill(encoder_padding_mask.unsqueeze(-1), 0)
|
124 |
+
|
125 |
+
combined = (conved + embedded) * math.sqrt(0.5)
|
126 |
+
|
127 |
+
return conved, combined
|
128 |
+
class Attention(nn.Module):
|
129 |
+
"""Attention"""
|
130 |
+
def __init__(self, conv_channels, embed_dim):
|
131 |
+
super().__init__()
|
132 |
+
self.linear_in = Linear(conv_channels, embed_dim)
|
133 |
+
self.linear_out = Linear(embed_dim, conv_channels)
|
134 |
+
|
135 |
+
def forward(self, conved, embedded, encoder_out, encoder_padding_mask):
|
136 |
+
"""
|
137 |
+
Forward Attention Layer
|
138 |
+
Args:
|
139 |
+
conved (LongTensor): (batch, conv_channels, trg_len)
|
140 |
+
embedded (LongTensor): (batch, trg_len, embed_dim)
|
141 |
+
encoder_out (encoder_conved, encoder_combined): (batch, src_len, embed_dim)
|
142 |
+
encoder_padding_mask(LongTensor): (batch, src_len)
|
143 |
+
Returns:
|
144 |
+
attended_combined (LongTensor): (batch, conv_channels, trg_len)
|
145 |
+
attention (LongTensor): (batch, trg_len, src_len)
|
146 |
+
"""
|
147 |
+
encoder_conved, encoder_combined = encoder_out
|
148 |
+
|
149 |
+
conved_emb = self.linear_in(conved.permute(0, 2, 1)) # (batch, trg_len, embed_dim)
|
150 |
+
combined = (conved_emb + embedded) * math.sqrt(0.5) # (batch, trg_len, embed_dim)
|
151 |
+
|
152 |
+
energy = torch.matmul(combined, encoder_conved.permute(0, 2, 1)) # (batch, trg_len, src_len)
|
153 |
+
|
154 |
+
# don't attend over padding
|
155 |
+
energy = energy.float().masked_fill(encoder_padding_mask.unsqueeze(1), float('-inf'))
|
156 |
+
|
157 |
+
attention = F.softmax(energy, dim=2)
|
158 |
+
|
159 |
+
attended_encoding = torch.matmul(attention, encoder_combined) # (batch, trg_len, embed_dim)
|
160 |
+
attended_encoding = self.linear_out(attended_encoding) # (batch, trg_len, conv_channels)
|
161 |
+
|
162 |
+
# apply residual connection
|
163 |
+
attended_combined = (conved + attended_encoding.permute(0, 2, 1)) * math.sqrt(0.5)
|
164 |
+
|
165 |
+
return attended_combined, attention
|
166 |
+
class Decoder(nn.Module):
|
167 |
+
"""Decoder"""
|
168 |
+
def __init__(self, vocabulary, device, embed_dim=512, convolutions=((512, 3),) * 3,
|
169 |
+
dropout=0.5, max_positions=5000):
|
170 |
+
super().__init__()
|
171 |
+
|
172 |
+
self.vocabulary = vocabulary
|
173 |
+
self.dropout = dropout
|
174 |
+
self.device = device
|
175 |
+
self.max_positions = max_positions
|
176 |
+
|
177 |
+
convolutions = extend_conv_spec(convolutions)
|
178 |
+
in_channels = convolutions[0][0]
|
179 |
+
output_dim = len(vocabulary)
|
180 |
+
self.padding_idx = vocabulary.stoi[PAD_TOKEN]
|
181 |
+
|
182 |
+
self.embed_tokens = Embedding(output_dim, embed_dim, self.padding_idx)
|
183 |
+
self.embed_positions = PositionalEmbedding(max_positions, embed_dim, self.padding_idx)
|
184 |
+
|
185 |
+
self.embed2inchannels = Linear(embed_dim, in_channels)
|
186 |
+
self.projections = nn.ModuleList()
|
187 |
+
self.convolutions = nn.ModuleList()
|
188 |
+
self.attention = nn.ModuleList()
|
189 |
+
self.residuals = []
|
190 |
+
|
191 |
+
layer_in_channels = [in_channels]
|
192 |
+
for _, (out_channels, kernel_size, residual) in enumerate(convolutions):
|
193 |
+
if residual == 0:
|
194 |
+
residual_dim = out_channels
|
195 |
+
else:
|
196 |
+
residual_dim = layer_in_channels[-residual]
|
197 |
+
self.projections.append(Linear(residual_dim, out_channels)
|
198 |
+
if residual_dim != out_channels else None)
|
199 |
+
self.convolutions.append(
|
200 |
+
nn.Conv1d(in_channels=in_channels,
|
201 |
+
out_channels=out_channels * 2,
|
202 |
+
kernel_size=kernel_size)
|
203 |
+
)
|
204 |
+
self.attention.append(Attention(out_channels, embed_dim))
|
205 |
+
self.residuals.append(residual)
|
206 |
+
in_channels = out_channels
|
207 |
+
layer_in_channels.append(out_channels)
|
208 |
+
|
209 |
+
self.inchannels2embed = Linear(in_channels, embed_dim)
|
210 |
+
self.linear_out = Linear(embed_dim, output_dim)
|
211 |
+
|
212 |
+
def forward(self, trg_tokens, encoder_out, **kwargs):
|
213 |
+
"""
|
214 |
+
Forward pass for convolutional decoder
|
215 |
+
Args:
|
216 |
+
trg_tokens (LongTensor): (batch, trg_len)
|
217 |
+
encoder_out (encoder_conved, encoder_combined): (batch, src_len, embed_dim)
|
218 |
+
src_tokens (LongTensor): (batch, src_len)
|
219 |
+
Returns:
|
220 |
+
outputs (LongTensor): (batch, trg_len, output_dim)
|
221 |
+
avg_attn_scores (LongTensor): (batch, trg_len, src_len)
|
222 |
+
"""
|
223 |
+
src_tokens = kwargs.get('src_tokens', '')
|
224 |
+
encoder_padding_mask = src_tokens.eq(self.padding_idx)
|
225 |
+
|
226 |
+
# embed tokens and positions
|
227 |
+
embedded = self.embed_tokens(trg_tokens) + self.embed_positions(trg_tokens)
|
228 |
+
embedded = F.dropout(embedded, p=self.dropout, training=self.training) # (batch, trg_len, embed_dim)
|
229 |
+
|
230 |
+
conv_input = self.embed2inchannels(embedded) # (batch, trg_len, in_channels)
|
231 |
+
|
232 |
+
x = conv_input.permute(0, 2, 1) # (batch, in_channels, trg_len)
|
233 |
+
|
234 |
+
avg_attn_scores = None
|
235 |
+
num_attn_layers = len(self.attention)
|
236 |
+
residuals = [x]
|
237 |
+
for proj, conv, attention, res_layer in zip(self.projections, self.convolutions, self.attention,
|
238 |
+
self.residuals):
|
239 |
+
if res_layer > 0:
|
240 |
+
residual = residuals[-res_layer]
|
241 |
+
residual = residual if proj is None else proj(residual)
|
242 |
+
else:
|
243 |
+
residual = None
|
244 |
+
|
245 |
+
x = F.dropout(x, p=self.dropout, training=self.training)
|
246 |
+
# add padding
|
247 |
+
padding = torch.zeros(x.shape[0],
|
248 |
+
x.shape[1],
|
249 |
+
conv.kernel_size[0] - 1).fill_(self.padding_idx).to(self.device)
|
250 |
+
x = torch.cat((padding, x), dim=2)
|
251 |
+
x = conv(x)
|
252 |
+
x = F.glu(x, dim=1)
|
253 |
+
|
254 |
+
# attention
|
255 |
+
x, attn_scores = attention(x, embedded, encoder_out, encoder_padding_mask)
|
256 |
+
|
257 |
+
if not self.training:
|
258 |
+
attn_scores = attn_scores / num_attn_layers
|
259 |
+
if avg_attn_scores is None:
|
260 |
+
avg_attn_scores = attn_scores
|
261 |
+
else:
|
262 |
+
avg_attn_scores.add_(attn_scores)
|
263 |
+
|
264 |
+
# apply residual connection
|
265 |
+
if residual is not None:
|
266 |
+
x = (x + residual) * math.sqrt(0.5)
|
267 |
+
residuals.append(x)
|
268 |
+
|
269 |
+
conved = self.inchannels2embed(x.permute(0, 2, 1)) # (batch, trg_len, embed_dim)
|
270 |
+
conved = F.dropout(conved, p=self.dropout, training=self.training)
|
271 |
+
|
272 |
+
outputs = self.linear_out(conved)
|
273 |
+
|
274 |
+
return outputs # , avg_attn_scores
|
UIT-ViCoV19QA/models/layers.py
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch.nn as nn
|
2 |
+
import torch
|
3 |
+
|
4 |
+
def RNN(cell_name):
|
5 |
+
if cell_name.lower() == 'lstm':
|
6 |
+
return LSTM
|
7 |
+
elif cell_name.lower() == 'gru':
|
8 |
+
return GRU
|
9 |
+
else:
|
10 |
+
raise ValueError(f"Unsupported RNN Cell: {cell_name}")
|
11 |
+
|
12 |
+
def Embedding(num_embeddings, embedding_dim, padding_idx):
|
13 |
+
"""Embedding layer"""
|
14 |
+
m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx)
|
15 |
+
nn.init.uniform_(m.weight, -0.1, 0.1)
|
16 |
+
nn.init.constant_(m.weight[padding_idx], 0)
|
17 |
+
return m
|
18 |
+
|
19 |
+
def Linear(in_features, out_features, bias=True):
|
20 |
+
"""Linear layer"""
|
21 |
+
m = nn.Linear(in_features, out_features, bias=bias)
|
22 |
+
m.weight.data.uniform_(-0.1, 0.1)
|
23 |
+
if bias:
|
24 |
+
m.bias.data.uniform_(-0.1, 0.1)
|
25 |
+
return m
|
26 |
+
|
27 |
+
def LSTM(input_size, hidden_size, **kwargs):
|
28 |
+
"""LSTM layer"""
|
29 |
+
m = nn.LSTM(input_size, hidden_size, **kwargs)
|
30 |
+
for name, param in m.named_parameters():
|
31 |
+
if 'weight' in name or 'bias' in name:
|
32 |
+
param.data.uniform_(-0.1, 0.1)
|
33 |
+
return m
|
34 |
+
|
35 |
+
def GRU(input_size, hidden_size, **kwargs):
|
36 |
+
"""GRU layer"""
|
37 |
+
m = nn.GRU(input_size, hidden_size, **kwargs)
|
38 |
+
for name, param in m.named_parameters():
|
39 |
+
if 'weight' in name or 'bias' in name:
|
40 |
+
param.data.uniform_(-0.1, 0.1)
|
41 |
+
return m
|
42 |
+
|
43 |
+
def Conv1d(in_channels, out_channels, kernel_size, padding=0):
|
44 |
+
"""Conv1d"""
|
45 |
+
m = nn.Conv1d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, padding=padding)
|
46 |
+
nn.init.normal_(m.weight, 0, 0.1)
|
47 |
+
nn.init.constant_(m.bias, 0)
|
48 |
+
return m
|
49 |
+
|
50 |
+
def PositionalEmbedding(num_embeddings, embedding_dim, padding_idx):
|
51 |
+
"""PositionalEmbedding"""
|
52 |
+
m = LearnedPositionalEmbedding(num_embeddings, embedding_dim, padding_idx)
|
53 |
+
nn.init.normal_(m.weight, 0, 0.1)
|
54 |
+
nn.init.constant_(m.weight[padding_idx], 0)
|
55 |
+
return m
|
56 |
+
|
57 |
+
class LearnedPositionalEmbedding(nn.Embedding):
|
58 |
+
"""LearnedPositionalEmbedding"""
|
59 |
+
def __init__(self, num_embeddings, embedding_dim, padding_idx):
|
60 |
+
super().__init__(num_embeddings, embedding_dim, padding_idx)
|
61 |
+
|
62 |
+
def forward(self, input):
|
63 |
+
"""Input size [bsz x seqlen]"""
|
64 |
+
# Replace non-padding symbols with their position numbers.
|
65 |
+
# Position numbers begin at padding_idx+1. Padding symbols are ignored.
|
66 |
+
mask = input.ne(self.padding_idx).int()
|
67 |
+
positions = (torch.cumsum(mask, dim=1).type_as(mask) * mask).long() + self.padding_idx
|
68 |
+
return super().forward(positions)
|
UIT-ViCoV19QA/models/rnn1.py
ADDED
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Seq2seq based: Neural Machine Translation by Jointly Learning to Align and Translate
|
3 |
+
https://arxiv.org/abs/1409.0473
|
4 |
+
"""
|
5 |
+
import random
|
6 |
+
import torch
|
7 |
+
import torch.nn as nn
|
8 |
+
import torch.nn.functional as F
|
9 |
+
from utils.constants import PAD_TOKEN, EOS_TOKEN, SOS_TOKEN
|
10 |
+
from models.layers import RNN, Embedding, Linear, LSTM, GRU
|
11 |
+
|
12 |
+
class Encoder(nn.Module):
|
13 |
+
"""Encoder"""
|
14 |
+
def __init__(self, vocabulary, device, embed_dim=512, hidden_size=512,
|
15 |
+
num_layers=2, dropout=0.5, bidirectional=True, cell_name='gru'):
|
16 |
+
super().__init__()
|
17 |
+
input_dim = len(vocabulary)
|
18 |
+
self.vocabulary = vocabulary
|
19 |
+
self.pad_id = vocabulary.stoi[PAD_TOKEN]
|
20 |
+
self.embed_dim= embed_dim
|
21 |
+
self.hidden_size = hidden_size
|
22 |
+
self.num_layers = num_layers
|
23 |
+
|
24 |
+
self.dropout = dropout
|
25 |
+
self.bidirectional = bidirectional
|
26 |
+
self.cell_name = cell_name
|
27 |
+
self.device = device
|
28 |
+
|
29 |
+
self.embed_tokens = Embedding(input_dim, self.embed_dim, self.pad_id)
|
30 |
+
|
31 |
+
self.rnn_cell = RNN(cell_name)
|
32 |
+
self.rnn = self.rnn_cell(
|
33 |
+
input_size=self.embed_dim,
|
34 |
+
hidden_size=self.hidden_size,
|
35 |
+
num_layers=self.num_layers,
|
36 |
+
dropout=self.dropout if self.num_layers > 1 else 0.,
|
37 |
+
bidirectional=self.bidirectional
|
38 |
+
)
|
39 |
+
self.linear_out = nn.Linear(hidden_size * 2, hidden_size)
|
40 |
+
|
41 |
+
def forward(self, src_tokens, **kwargs):
|
42 |
+
"""
|
43 |
+
Forward Encoder
|
44 |
+
Args:
|
45 |
+
src_tokens (LongTensor): (batch, src_len)
|
46 |
+
src_lengths (LongTensor): (batch)
|
47 |
+
Returns:
|
48 |
+
x (LongTensor): (src_len, batch, hidden_size * num_directions)
|
49 |
+
hidden (LongTensor): (batch, enc_hid_dim)
|
50 |
+
"""
|
51 |
+
src_lengths = kwargs.get('src_lengths', '')
|
52 |
+
src_tokens = src_tokens.t()
|
53 |
+
|
54 |
+
x = self.embed_tokens(src_tokens)
|
55 |
+
x = F.dropout(x, p=self.dropout, training=self.training) # (src_len, batch, embed_dim)
|
56 |
+
|
57 |
+
packed_x = nn.utils.rnn.pack_padded_sequence(x, src_lengths)
|
58 |
+
|
59 |
+
packed_outputs, hidden = self.rnn(packed_x) # hidden: (n_layers * num_directions, batch, hidden_size)
|
60 |
+
|
61 |
+
x, _ = nn.utils.rnn.pad_packed_sequence(packed_outputs)
|
62 |
+
x = F.dropout(x, p=self.dropout, training=self.training)
|
63 |
+
|
64 |
+
# input hidden for decoder is the final encoder hidden state
|
65 |
+
# since rnn is bidirectional get last forward and backward hidden state
|
66 |
+
|
67 |
+
last_forward = hidden[-2, :, :]
|
68 |
+
last_backward = hidden[-1, :, :]
|
69 |
+
hidden = torch.cat((last_forward, last_backward), dim=1)
|
70 |
+
hidden = torch.tanh(self.linear_out(hidden)) # (batch, enc_hid_dim)
|
71 |
+
|
72 |
+
return x, hidden
|
73 |
+
|
74 |
+
class Attention(nn.Module):
|
75 |
+
"""Attention"""
|
76 |
+
def __init__(self, enc_hid_dim, dec_hid_dim):
|
77 |
+
super().__init__()
|
78 |
+
|
79 |
+
self.linear = nn.Linear((enc_hid_dim * 2) + dec_hid_dim, dec_hid_dim)
|
80 |
+
self.v = nn.Parameter(torch.rand(dec_hid_dim))
|
81 |
+
|
82 |
+
def forward(self, hidden, encoder_outputs, mask):
|
83 |
+
"""
|
84 |
+
Forward Attention Layer
|
85 |
+
Args:
|
86 |
+
hidden (LongTensor): (batch, dec_hid_dim)
|
87 |
+
encoder_outputs (LongTensor): (src_len, batch, enc_hid_dim * 2)
|
88 |
+
mask (LongTensor): (batch, src_len)
|
89 |
+
Returns:
|
90 |
+
attention (LongTensor): (batch, src_len)
|
91 |
+
"""
|
92 |
+
|
93 |
+
batch = encoder_outputs.shape[1]
|
94 |
+
src_len = encoder_outputs.shape[0]
|
95 |
+
|
96 |
+
hidden = hidden.unsqueeze(1).repeat(1, src_len, 1) # (batch, src_len, dec_hid_dim)
|
97 |
+
|
98 |
+
encoder_outputs = encoder_outputs.permute(1, 0, 2) # (batch, src_len, enc_hid_dim * 2)
|
99 |
+
|
100 |
+
energy = torch.tanh(self.linear(torch.cat((hidden, encoder_outputs), dim=2))) # (batch, src_len, dec_hid_dim)
|
101 |
+
energy = energy.permute(0, 2, 1) # (batch, dec_hid_dim, src_len)
|
102 |
+
|
103 |
+
v = self.v.repeat(batch, 1).unsqueeze(1) # (batch, 1, dec_hid_dim)
|
104 |
+
|
105 |
+
attention = torch.bmm(v, energy).squeeze(1)
|
106 |
+
|
107 |
+
attention = attention.masked_fill(mask == 0, float('-inf'))
|
108 |
+
|
109 |
+
return F.softmax(attention, dim=1)
|
110 |
+
|
111 |
+
class Decoder(nn.Module):
|
112 |
+
"""Decoder"""
|
113 |
+
def __init__(self, vocabulary, device, embed_dim=512, hidden_size=512,
|
114 |
+
num_layers=2, dropout=0.5, max_positions=500, cell_name='gru'):
|
115 |
+
super().__init__()
|
116 |
+
self.vocabulary = vocabulary
|
117 |
+
self.pad_id = vocabulary.stoi[PAD_TOKEN]
|
118 |
+
self.sos_idx = vocabulary.stoi[SOS_TOKEN]
|
119 |
+
self.eos_idx = vocabulary.stoi[EOS_TOKEN]
|
120 |
+
|
121 |
+
self.embed_dim = embed_dim
|
122 |
+
self.hidden_size = hidden_size
|
123 |
+
self.need_attn = True
|
124 |
+
self.output_dim = len(vocabulary)
|
125 |
+
|
126 |
+
self.dropout = dropout
|
127 |
+
self.max_positions = max_positions
|
128 |
+
self.device = device
|
129 |
+
self.cell_name = cell_name
|
130 |
+
|
131 |
+
# suppose encoder and decoder have same hidden size
|
132 |
+
self.attention = Attention(self.hidden_size, self.hidden_size)
|
133 |
+
self.embed_tokens = Embedding(self.output_dim, self.embed_dim, self.pad_id)
|
134 |
+
|
135 |
+
self.rnn_cell = RNN(cell_name)
|
136 |
+
self.rnn = self.rnn_cell(
|
137 |
+
input_size=(hidden_size * 2) + embed_dim,
|
138 |
+
hidden_size=hidden_size,
|
139 |
+
)
|
140 |
+
|
141 |
+
self.linear_out = Linear(
|
142 |
+
in_features=(hidden_size * 2) + hidden_size + embed_dim,
|
143 |
+
out_features=self.output_dim
|
144 |
+
)
|
145 |
+
|
146 |
+
def _decoder_step(self, input, hidden, encoder_outputs, mask):
|
147 |
+
input = input.unsqueeze(0) # (1, batch)
|
148 |
+
|
149 |
+
x = self.embed_tokens(input) # (1, batch, emb_dim)
|
150 |
+
x = F.dropout(x, p=self.dropout, training=self.training)
|
151 |
+
|
152 |
+
attn = self.attention(hidden, encoder_outputs, mask) # (batch, src_len)
|
153 |
+
attn = F.dropout(attn, p=self.dropout, training=self.training)
|
154 |
+
|
155 |
+
attn = attn.unsqueeze(1) # (batch, 1, src_len)
|
156 |
+
|
157 |
+
encoder_outputs = encoder_outputs.permute(1, 0, 2) # (batch, src_len, 2 * enc_hid_dim)
|
158 |
+
|
159 |
+
weighted = torch.bmm(attn, encoder_outputs) # (batch, 1, 2 * enc_hid_dim)
|
160 |
+
|
161 |
+
weighted = weighted.permute(1, 0, 2) # (1, batch, 2 * enc_hid_dim)
|
162 |
+
|
163 |
+
rnn_input = torch.cat((x, weighted), dim=2) # (1, batch, 2 * enc_hid_dim + embed_dim)
|
164 |
+
|
165 |
+
output, hidden = self.rnn(rnn_input, hidden.unsqueeze(0))
|
166 |
+
# output: (1, batch, dec_hid_dim)
|
167 |
+
# hidden: (1, batch, dec_hid_dim)
|
168 |
+
|
169 |
+
x = x.squeeze(0)
|
170 |
+
output = output.squeeze(0)
|
171 |
+
weighted = weighted.squeeze(0)
|
172 |
+
|
173 |
+
x = torch.cat((output, weighted, x), dim=1)
|
174 |
+
output = self.linear_out(x) # (batch, output_dim)
|
175 |
+
|
176 |
+
return output, hidden.squeeze(0), attn.squeeze(1)
|
177 |
+
|
178 |
+
def forward(self, trg_tokens, encoder_out, **kwargs):
|
179 |
+
"""
|
180 |
+
Forward Decoder
|
181 |
+
Args:
|
182 |
+
trg_tokens (LongTensor): (trg_len, batch)
|
183 |
+
Tuple (encoder_out):
|
184 |
+
encoder_out (LongTensor): (src_len, batch, 2 * hidden_size)
|
185 |
+
hidden (LongTensor): (batch, enc_hid_dim)
|
186 |
+
src_tokens (LongTensor): (src_len, batch)
|
187 |
+
Returns:
|
188 |
+
outputs (LongTensor): (max_len, batch, output_dim)
|
189 |
+
attentions (LongTensor): (max_len, batch, src_len)
|
190 |
+
"""
|
191 |
+
encoder_out, hidden = encoder_out
|
192 |
+
src_tokens = kwargs.get('src_tokens', '')
|
193 |
+
teacher_ratio = kwargs.get('teacher_forcing_ratio', '')
|
194 |
+
src_tokens = src_tokens.t()
|
195 |
+
batch = src_tokens.shape[1]
|
196 |
+
|
197 |
+
if trg_tokens is None:
|
198 |
+
teacher_ratio = 0.
|
199 |
+
inference = True
|
200 |
+
trg_tokens = torch.zeros((self.max_positions, batch)).long().\
|
201 |
+
fill_(self.sos_idx).\
|
202 |
+
to(self.device)
|
203 |
+
else:
|
204 |
+
trg_tokens = trg_tokens.t()
|
205 |
+
inference = False
|
206 |
+
|
207 |
+
max_len = trg_tokens.shape[0]
|
208 |
+
|
209 |
+
# initialize tensors to store the outputs and attentions
|
210 |
+
outputs = torch.zeros(max_len, batch, self.output_dim).to(self.device)
|
211 |
+
attentions = torch.zeros(max_len, batch, src_tokens.shape[0]).to(self.device)
|
212 |
+
|
213 |
+
# prepare decoder input(<sos> token)
|
214 |
+
input = trg_tokens[0, :]
|
215 |
+
|
216 |
+
mask = (src_tokens != self.pad_id).permute(1, 0) # (batch, src_len)
|
217 |
+
|
218 |
+
for i in range(1, max_len):
|
219 |
+
|
220 |
+
# forward through decoder using inout, encoder hidden, encoder outputs and mask
|
221 |
+
# get predictions, hidden state and attentions
|
222 |
+
output, hidden, attention = self._decoder_step(input, hidden, encoder_out, mask)
|
223 |
+
|
224 |
+
# save predictions for position i
|
225 |
+
outputs[i] = output
|
226 |
+
|
227 |
+
# save attention for position i
|
228 |
+
attentions[i] = attention
|
229 |
+
|
230 |
+
# if teacher forcing
|
231 |
+
# use actual next token as input for next position
|
232 |
+
# else
|
233 |
+
# use highest predicted token
|
234 |
+
input = trg_tokens[i] if random.random() < teacher_ratio else output.argmax(1)
|
235 |
+
|
236 |
+
# if inference is enabled and highest predicted token is <eos> then stop
|
237 |
+
# and return everything till position i
|
238 |
+
if inference and input.item() == self.eos_idx:
|
239 |
+
return outputs[:i] # , attentions[:i]
|
240 |
+
|
241 |
+
return outputs # , attentions
|
UIT-ViCoV19QA/models/rnn2.py
ADDED
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Seq2seq based: Effective Approaches to Attention-based Neural Machine Translation
|
3 |
+
https://arxiv.org/abs/1508.04025
|
4 |
+
"""
|
5 |
+
import random
|
6 |
+
import torch
|
7 |
+
import torch.nn as nn
|
8 |
+
import torch.nn.functional as F
|
9 |
+
from utils.constants import PAD_TOKEN, EOS_TOKEN, SOS_TOKEN
|
10 |
+
from models.layers import RNN, Embedding, Linear, LSTM, GRU
|
11 |
+
|
12 |
+
class Encoder(nn.Module):
|
13 |
+
"""Encoder"""
|
14 |
+
def __init__(self, vocabulary, device, cell_name, hidden_size=512, num_layers=2,
|
15 |
+
bidirectional=True, dropout=0.5):
|
16 |
+
super().__init__()
|
17 |
+
input_dim = len(vocabulary)
|
18 |
+
self.num_layers = num_layers
|
19 |
+
self.pad_id = vocabulary.stoi[PAD_TOKEN]
|
20 |
+
self.hidden_size = hidden_size
|
21 |
+
self.bidirectional = bidirectional
|
22 |
+
self.device = device
|
23 |
+
self.rnn_cell = RNN(cell_name)
|
24 |
+
|
25 |
+
self.embedding = Embedding(input_dim, self.hidden_size, self.pad_id)
|
26 |
+
self.dropout = dropout
|
27 |
+
|
28 |
+
self.rnn = self.rnn_cell(
|
29 |
+
input_size=self.hidden_size,
|
30 |
+
hidden_size=self.hidden_size,
|
31 |
+
num_layers=self.num_layers,
|
32 |
+
batch_first=True,
|
33 |
+
bidirectional=self.bidirectional,
|
34 |
+
dropout=self.dropout if self.num_layers > 1 else 0.
|
35 |
+
)
|
36 |
+
|
37 |
+
def forward(self, src_tokens, **kwargs):
|
38 |
+
"""
|
39 |
+
Forward Encoder
|
40 |
+
Args:
|
41 |
+
src_tokens (LongTensor): (batch, src_len)
|
42 |
+
src_lengths (LongTensor): (batch)
|
43 |
+
Returns:
|
44 |
+
x (LongTensor): (src_len, batch, hidden_size * num_directions)
|
45 |
+
hidden (LongTensor): (batch, enc_hid_dim)
|
46 |
+
"""
|
47 |
+
src_lengths = kwargs.get('src_lengths', '')
|
48 |
+
|
49 |
+
embedded = self.embedding(src_tokens)
|
50 |
+
embedded = F.dropout(embedded, p=self.dropout, training=self.training)
|
51 |
+
|
52 |
+
embedded = nn.utils.rnn.pack_padded_sequence(embedded, src_lengths, batch_first=True)
|
53 |
+
output, hidden = self.rnn(embedded)
|
54 |
+
|
55 |
+
output, _ = nn.utils.rnn.pad_packed_sequence(output, batch_first=True)
|
56 |
+
output = F.dropout(output, p=self.dropout, training=self.training)
|
57 |
+
|
58 |
+
if isinstance(hidden, tuple):
|
59 |
+
hidden = tuple([self._cat_directions(h) for h in hidden])
|
60 |
+
else:
|
61 |
+
hidden = self._cat_directions(hidden)
|
62 |
+
|
63 |
+
return output, hidden
|
64 |
+
|
65 |
+
def _cat_directions(self, h):
|
66 |
+
"""
|
67 |
+
If the encoder is bidirectional, do the following transformation.
|
68 |
+
(#directions * #layers, #batch, hidden_size) -> (#layers, #batch, #directions * hidden_size)
|
69 |
+
"""
|
70 |
+
if self.bidirectional:
|
71 |
+
h = torch.cat([h[0:h.size(0):2], h[1:h.size(0):2]], 2)
|
72 |
+
return h
|
73 |
+
|
74 |
+
class Attention(nn.Module):
|
75 |
+
"""Attention"""
|
76 |
+
def __init__(self, input_embed, source_embed, output_embed):
|
77 |
+
super().__init__()
|
78 |
+
self.linear_in = Linear(input_embed, source_embed)
|
79 |
+
self.linear_out = Linear(input_embed+source_embed, output_embed)
|
80 |
+
|
81 |
+
def forward(self, output, context, mask):
|
82 |
+
"""
|
83 |
+
Forward Attention
|
84 |
+
"""
|
85 |
+
# input: bsz x input_embed_dim
|
86 |
+
# source_hids: srclen x bsz x source_embed_dim
|
87 |
+
|
88 |
+
input = output.squeeze(1)
|
89 |
+
source_hids = context.permute(1, 0, 2)
|
90 |
+
|
91 |
+
x = self.linear_in(input)
|
92 |
+
|
93 |
+
# compute attention
|
94 |
+
attn_scores = (source_hids * x.unsqueeze(0)).sum(dim=2)
|
95 |
+
|
96 |
+
# don't attend over padding
|
97 |
+
attn_scores = attn_scores.float().masked_fill(mask == 0, float('-inf'))
|
98 |
+
|
99 |
+
attn_scores = F.softmax(attn_scores, dim=0) # srclen x bsz
|
100 |
+
|
101 |
+
# sum weighted sources
|
102 |
+
x = (attn_scores.unsqueeze(2) * source_hids).sum(dim=0)
|
103 |
+
|
104 |
+
x = torch.cat((x, input), dim=1)
|
105 |
+
x = self.linear_out(x)
|
106 |
+
x = torch.tanh(x)
|
107 |
+
|
108 |
+
return x, attn_scores
|
109 |
+
|
110 |
+
class Decoder(nn.Module):
|
111 |
+
"""Decoder"""
|
112 |
+
def __init__(self, vocabulary, device,cell_name, hidden_size=512, num_layers=2,
|
113 |
+
max_len=500, dropout=0.5):
|
114 |
+
super().__init__()
|
115 |
+
self.output_dim = len(vocabulary)
|
116 |
+
self.hidden_size = hidden_size
|
117 |
+
self.num_layers = num_layers
|
118 |
+
self.max_length = max_len
|
119 |
+
self.device = device
|
120 |
+
self.eos_id = vocabulary.stoi[EOS_TOKEN]
|
121 |
+
self.sos_id = vocabulary.stoi[SOS_TOKEN]
|
122 |
+
self.pad_id = vocabulary.stoi[PAD_TOKEN]
|
123 |
+
self.rnn_cell = RNN(cell_name)
|
124 |
+
|
125 |
+
self.encoder_proj = Linear(hidden_size*2, hidden_size)
|
126 |
+
|
127 |
+
self.embedding = Embedding(self.output_dim, self.hidden_size, self.pad_id)
|
128 |
+
self.dropout = dropout
|
129 |
+
|
130 |
+
self.rnn = self.rnn_cell(
|
131 |
+
input_size=hidden_size,
|
132 |
+
hidden_size=hidden_size,
|
133 |
+
num_layers=self.num_layers,
|
134 |
+
batch_first=True,
|
135 |
+
dropout=self.dropout if num_layers > 1 else 0.
|
136 |
+
)
|
137 |
+
|
138 |
+
self.attention = Attention(self.hidden_size, self.hidden_size*2, self.hidden_size)
|
139 |
+
self.linear_out = Linear(self.hidden_size, self.output_dim)
|
140 |
+
|
141 |
+
def _decoder_step(self, input_var, hidden, encoder_outputs, mask):
|
142 |
+
input_var = input_var.unsqueeze(1)
|
143 |
+
|
144 |
+
embedded = self.embedding(input_var)
|
145 |
+
embedded = F.dropout(embedded, p=self.dropout, training=self.training)
|
146 |
+
|
147 |
+
output, hidden = self.rnn(embedded, hidden)
|
148 |
+
output = F.dropout(output, p=self.dropout, training=self.training)
|
149 |
+
|
150 |
+
output, attn = self.attention(output, encoder_outputs, mask)
|
151 |
+
output = F.dropout(output, p=self.dropout, training=self.training)
|
152 |
+
|
153 |
+
output = self.linear_out(output)
|
154 |
+
# output = F.dropout(output, p=self.dropout, training=self.training)
|
155 |
+
output = F.log_softmax(output, dim=1)
|
156 |
+
|
157 |
+
return output, hidden, attn
|
158 |
+
|
159 |
+
def forward(self, trg_tokens, encoder_out, **kwargs):
|
160 |
+
"""
|
161 |
+
Forward Decoder
|
162 |
+
"""
|
163 |
+
encoder_out, hidden = encoder_out
|
164 |
+
src_tokens = kwargs.get('src_tokens', '')
|
165 |
+
teacher_forcing_ratio = kwargs.get('teacher_forcing_ratio', '')
|
166 |
+
batch_size, src_length = src_tokens.size()
|
167 |
+
|
168 |
+
if trg_tokens is None:
|
169 |
+
teacher_forcing_ratio = 0.
|
170 |
+
inference = True
|
171 |
+
trg_tokens = torch.zeros((batch_size, self.max_length)).long().\
|
172 |
+
fill_(self.sos_id).\
|
173 |
+
to(self.device)
|
174 |
+
else:
|
175 |
+
inference = False
|
176 |
+
|
177 |
+
max_length = trg_tokens.shape[1]
|
178 |
+
|
179 |
+
outputs = torch.zeros(max_length, batch_size, self.output_dim).to(self.device)
|
180 |
+
attentions = torch.zeros(max_length, batch_size, src_length).to(self.device)
|
181 |
+
|
182 |
+
mask = (src_tokens != self.pad_id).t()
|
183 |
+
|
184 |
+
# check whether encoder has lstm or gru hidden state and
|
185 |
+
# project their output to decoder hidden state
|
186 |
+
if isinstance(hidden, tuple):
|
187 |
+
hidden = [self.encoder_proj(h) for h in hidden] # new_line
|
188 |
+
else:
|
189 |
+
hidden = self.encoder_proj(hidden)
|
190 |
+
|
191 |
+
# use_teacher_forcing = True if random.random() < teacher_forcing_ratio else False
|
192 |
+
|
193 |
+
decoder_input = trg_tokens[:, 0]
|
194 |
+
|
195 |
+
# Here we miss the output for position 0
|
196 |
+
for i in range(1, max_length):
|
197 |
+
output, hidden, attention = self._decoder_step(decoder_input, hidden, encoder_out, mask)
|
198 |
+
outputs[i] = output
|
199 |
+
attentions[i] = attention.t()
|
200 |
+
use_teacher_forcing = True if random.random() < teacher_forcing_ratio else False
|
201 |
+
decoder_input = trg_tokens[:, i] if use_teacher_forcing else output.argmax(1)
|
202 |
+
|
203 |
+
if inference and decoder_input.item() == self.eos_id and i > 0:
|
204 |
+
return outputs[:i] # , attentions[:i]
|
205 |
+
|
206 |
+
return outputs # , attentions
|
UIT-ViCoV19QA/models/seq2seq.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Main sequence to sequence class which conects
|
3 |
+
encoder-decoder model
|
4 |
+
"""
|
5 |
+
import torch.nn as nn
|
6 |
+
|
7 |
+
class Seq2Seq(nn.Module):
|
8 |
+
"""
|
9 |
+
Seq2seq class
|
10 |
+
"""
|
11 |
+
def __init__(self, encoder, decoder, name):
|
12 |
+
super().__init__()
|
13 |
+
self.encoder = encoder
|
14 |
+
self.decoder = decoder
|
15 |
+
self.name = name
|
16 |
+
|
17 |
+
def forward(self, src_tokens, src_lengths, trg_tokens, teacher_forcing_ratio=0.5):
|
18 |
+
"""
|
19 |
+
Run the forward pass for an encoder-decoder model.
|
20 |
+
|
21 |
+
Args:
|
22 |
+
src_tokens (LongTensor): tokens in the source language of shape
|
23 |
+
`(src_len, batch)`
|
24 |
+
src_lengths (LongTensor): source sentence lengths of shape `(batch)`
|
25 |
+
trg_tokens (LongTensor): tokens in the target language of shape
|
26 |
+
`(tgt_len, batch)`, for teacher forcing
|
27 |
+
teacher_forcing_ratio (float): teacher forcing probability
|
28 |
+
|
29 |
+
Returns:
|
30 |
+
tuple:
|
31 |
+
- the decoder's output of shape `(batch, tgt_len, vocab)`
|
32 |
+
- attention scores of shape `(batch, trg_len, src_len)`
|
33 |
+
"""
|
34 |
+
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths)
|
35 |
+
|
36 |
+
decoder_out = self.decoder(trg_tokens, encoder_out,
|
37 |
+
src_tokens=src_tokens,
|
38 |
+
teacher_forcing_ratio=teacher_forcing_ratio)
|
39 |
+
return decoder_out
|
UIT-ViCoV19QA/models/transformer.py
ADDED
@@ -0,0 +1,271 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Seq2seq based: Attention Is All You Need
|
3 |
+
https://arxiv.org/abs/1706.03762
|
4 |
+
"""
|
5 |
+
import math
|
6 |
+
import torch
|
7 |
+
import torch.nn as nn
|
8 |
+
import torch.onnx.operators
|
9 |
+
import torch.nn.functional as F
|
10 |
+
from torch.autograd import Variable
|
11 |
+
from utils.constants import PAD_TOKEN
|
12 |
+
|
13 |
+
class Encoder(nn.Module):
|
14 |
+
"""Encoder"""
|
15 |
+
def __init__(self, vocabulary, device, embed_dim=512, layers=2,
|
16 |
+
heads=8, pf_dim=2048, dropout=0.5, max_positions=5000):
|
17 |
+
super().__init__()
|
18 |
+
input_dim = len(vocabulary)
|
19 |
+
self.padding_idx = vocabulary.stoi[PAD_TOKEN]
|
20 |
+
self.dropout = dropout
|
21 |
+
self.device = device
|
22 |
+
|
23 |
+
self.scale = math.sqrt(embed_dim)
|
24 |
+
self.embed_tokens = nn.Embedding(input_dim, embed_dim)
|
25 |
+
self.embed_positions = PositionalEmbedding(embed_dim, dropout, max_positions)
|
26 |
+
|
27 |
+
self.layers = nn.ModuleList([EncoderLayer(embed_dim, heads, pf_dim, dropout, device) for _ in range(layers)])
|
28 |
+
|
29 |
+
def forward(self, src_tokens, **kwargs):
|
30 |
+
"""
|
31 |
+
Forward pass for transformer encoder
|
32 |
+
Args:
|
33 |
+
src_tokens (LongTensor): (batch, src_len)
|
34 |
+
Returns:
|
35 |
+
x (LongTensor): (batch, src_len, embed_dim)
|
36 |
+
"""
|
37 |
+
src_mask = (src_tokens != self.padding_idx).unsqueeze(1).unsqueeze(2)
|
38 |
+
|
39 |
+
x = self.embed_tokens(src_tokens) * self.scale
|
40 |
+
x += self.embed_positions(src_tokens)
|
41 |
+
x = F.dropout(x, p=self.dropout, training=self.training)
|
42 |
+
|
43 |
+
for layer in self.layers:
|
44 |
+
x = layer(x, src_mask)
|
45 |
+
|
46 |
+
return x
|
47 |
+
|
48 |
+
class EncoderLayer(nn.Module):
|
49 |
+
"""EncoderLayer"""
|
50 |
+
def __init__(self, embed_dim, heads, pf_dim, dropout, device):
|
51 |
+
super().__init__()
|
52 |
+
|
53 |
+
self.layer_norm = nn.LayerNorm(embed_dim)
|
54 |
+
self.self_attn = MultiHeadedAttention(embed_dim, heads, dropout, device)
|
55 |
+
self.pos_ff = PositionwiseFeedforward(embed_dim, pf_dim, dropout)
|
56 |
+
self.dropout = nn.Dropout(dropout)
|
57 |
+
|
58 |
+
def forward(self, src_tokens, src_mask):
|
59 |
+
"""
|
60 |
+
Forward pass for transformer encoder layer
|
61 |
+
Args:
|
62 |
+
src_tokens (LongTensor): (batch, src_len, embed_dim)
|
63 |
+
src_mask (LongTensor): (batch, src_len)
|
64 |
+
Returns:
|
65 |
+
x (LongTensor): (batch, src_len, embed_dim)
|
66 |
+
"""
|
67 |
+
x = self.layer_norm(src_tokens + self.dropout(self.self_attn(src_tokens, src_tokens, src_tokens, src_mask)))
|
68 |
+
x = self.layer_norm(x + self.dropout(self.pos_ff(x)))
|
69 |
+
|
70 |
+
return x
|
71 |
+
|
72 |
+
class Decoder(nn.Module):
|
73 |
+
"""Decoder"""
|
74 |
+
def __init__(self, vocabulary, device, embed_dim=512, layers=2,
|
75 |
+
heads=8, pf_dim=2048, dropout=0.5, max_positions=5000):
|
76 |
+
super().__init__()
|
77 |
+
|
78 |
+
output_dim = len(vocabulary)
|
79 |
+
self.pad_id = vocabulary.stoi[PAD_TOKEN]
|
80 |
+
self.pf_dim = pf_dim
|
81 |
+
self.dropout = dropout
|
82 |
+
self.device = device
|
83 |
+
self.max_positions = max_positions
|
84 |
+
|
85 |
+
self.scale = math.sqrt(embed_dim)
|
86 |
+
self.embed_tokens = nn.Embedding(output_dim, embed_dim)
|
87 |
+
self.embed_positions = PositionalEmbedding(embed_dim, dropout, max_positions)
|
88 |
+
|
89 |
+
self.layers = nn.ModuleList([DecoderLayer(embed_dim, heads, pf_dim, dropout, device) for _ in range(layers)])
|
90 |
+
|
91 |
+
self.linear_out = nn.Linear(embed_dim, output_dim)
|
92 |
+
|
93 |
+
def make_masks(self, src_tokens, trg_tokens):
|
94 |
+
src_mask = (src_tokens != self.pad_id).unsqueeze(1).unsqueeze(2)
|
95 |
+
trg_pad_mask = (trg_tokens != self.pad_id).unsqueeze(1).unsqueeze(3).byte()
|
96 |
+
trg_len = trg_tokens.shape[1]
|
97 |
+
trg_sub_mask = torch.tril(torch.ones((trg_len, trg_len), device=self.device)).byte()
|
98 |
+
trg_mask = trg_pad_mask & trg_sub_mask
|
99 |
+
return src_mask, trg_mask
|
100 |
+
|
101 |
+
def forward(self, trg_tokens, encoder_out, **kwargs):
|
102 |
+
"""
|
103 |
+
Forward pass for transformer decoder
|
104 |
+
Args:
|
105 |
+
trg_tokens (LongTensor): (batch, trg_len)
|
106 |
+
encoder_out (LongTensor): (batch, src_len, embed_dim)
|
107 |
+
src_tokens (LongTensor): (batch, src_len)
|
108 |
+
Returns:
|
109 |
+
x (LongTensor): (batch, trg_len, output_dim)
|
110 |
+
"""
|
111 |
+
src_tokens = kwargs.get('src_tokens', '')
|
112 |
+
src_mask, trg_mask = self.make_masks(src_tokens, trg_tokens)
|
113 |
+
|
114 |
+
#print(trg_tokens.shape) #batch_size = 12
|
115 |
+
x = self.embed_tokens(trg_tokens) * self.scale #[12, 296, 512]
|
116 |
+
|
117 |
+
x += self.embed_positions(trg_tokens)#[1, 100, 512]
|
118 |
+
x = F.dropout(x, p=self.dropout, training=self.training)
|
119 |
+
|
120 |
+
for layer in self.layers:
|
121 |
+
x = layer(x, encoder_out, trg_mask, src_mask)
|
122 |
+
|
123 |
+
return self.linear_out(x)
|
124 |
+
|
125 |
+
class DecoderLayer(nn.Module):
|
126 |
+
"""DecoderLayer"""
|
127 |
+
def __init__(self, embed_dim, heads, pf_dim, dropout, device):
|
128 |
+
super().__init__()
|
129 |
+
self.layer_norm = nn.LayerNorm(embed_dim)
|
130 |
+
self.self_attn = MultiHeadedAttention(embed_dim, heads, dropout, device)
|
131 |
+
self.src_attn = MultiHeadedAttention(embed_dim, heads, dropout, device)
|
132 |
+
self.pos_ff = PositionwiseFeedforward(embed_dim, pf_dim, dropout)
|
133 |
+
self.dropout = nn.Dropout(dropout)
|
134 |
+
|
135 |
+
def forward(self, embed_trg, embed_src, trg_mask, src_mask):
|
136 |
+
"""
|
137 |
+
Forward pass for transformer decoder layer
|
138 |
+
Args:
|
139 |
+
embed_trg (LongTensor): (batch, trg_len, embed_dim)
|
140 |
+
embed_src (LongTensor): (batch, src_len, embed_dim)
|
141 |
+
trg_mask (LongTensor): (batch, trg_len)
|
142 |
+
src_mask (LongTensor): (batch, src_len)
|
143 |
+
Returns:
|
144 |
+
x (LongTensor): (batch, trg_len, embed_dim)
|
145 |
+
"""
|
146 |
+
x = self.layer_norm(embed_trg + self.dropout(self.self_attn(embed_trg, embed_trg, embed_trg, trg_mask)))
|
147 |
+
x = self.layer_norm(x + self.dropout(self.src_attn(x, embed_src, embed_src, src_mask)))
|
148 |
+
x = self.layer_norm(x + self.dropout(self.pos_ff(x)))
|
149 |
+
|
150 |
+
return x
|
151 |
+
|
152 |
+
class MultiHeadedAttention(nn.Module):
|
153 |
+
"""MultiHeadedAttention"""
|
154 |
+
def __init__(self, embed_dim, heads, dropout, device):
|
155 |
+
super().__init__()
|
156 |
+
assert embed_dim % heads == 0
|
157 |
+
self.attn_dim = embed_dim // heads
|
158 |
+
self.heads = heads
|
159 |
+
self.dropout = dropout
|
160 |
+
|
161 |
+
self.linear_q = nn.Linear(embed_dim, embed_dim)
|
162 |
+
self.linear_k = nn.Linear(embed_dim, embed_dim)
|
163 |
+
self.linear_v = nn.Linear(embed_dim, embed_dim)
|
164 |
+
|
165 |
+
self.scale = torch.sqrt(torch.FloatTensor([self.attn_dim])).to(device)
|
166 |
+
|
167 |
+
self.linear_out = nn.Linear(embed_dim, embed_dim)
|
168 |
+
|
169 |
+
def forward(self, query, key, value, mask=None):
|
170 |
+
"""
|
171 |
+
Forward pass for transformer decoder layer
|
172 |
+
Args:
|
173 |
+
query (LongTensor): (batch, sent_len, embed_dim)
|
174 |
+
key (LongTensor): (batch, sent_len, embed_dim)
|
175 |
+
value (LongTensor): (batch, sent_len, embed_dim)
|
176 |
+
mask (LongTensor): (batch, sent_len)
|
177 |
+
Returns:
|
178 |
+
x (LongTensor): (batch, sent_len, embed_dim)
|
179 |
+
"""
|
180 |
+
batch_size = query.shape[0]
|
181 |
+
|
182 |
+
Q = self.linear_q(query)
|
183 |
+
K = self.linear_k(key)
|
184 |
+
V = self.linear_v(value)
|
185 |
+
|
186 |
+
Q = Q.view(batch_size, -1, self.heads, self.attn_dim).permute(0, 2, 1, 3) # (batch, heads, sent_len, attn_dim)
|
187 |
+
K = K.view(batch_size, -1, self.heads, self.attn_dim).permute(0, 2, 1, 3) # (batch, heads, sent_len, attn_dim)
|
188 |
+
V = V.view(batch_size, -1, self.heads, self.attn_dim).permute(0, 2, 1, 3) # (batch, heads, sent_len, attn_dim)
|
189 |
+
|
190 |
+
energy = torch.matmul(Q, K.permute(0, 1, 3, 2)) / self.scale # (batch, heads, sent_len, sent_len)
|
191 |
+
|
192 |
+
if mask is not None:
|
193 |
+
energy = energy.masked_fill(mask == 0, -1e10)
|
194 |
+
|
195 |
+
attention = F.softmax(energy, dim=-1) # (batch, heads, sent_len, sent_len)
|
196 |
+
attention = F.dropout(attention, p=self.dropout, training=self.training)
|
197 |
+
|
198 |
+
x = torch.matmul(attention, V) # (batch, heads, sent_len, attn_dim)
|
199 |
+
x = x.permute(0, 2, 1, 3).contiguous() # (batch, sent_len, heads, attn_dim)
|
200 |
+
x = x.view(batch_size, -1, self.heads * (self.attn_dim)) # (batch, sent_len, embed_dim)
|
201 |
+
x = self.linear_out(x)
|
202 |
+
|
203 |
+
return x
|
204 |
+
|
205 |
+
class PositionwiseFeedforward(nn.Module):
|
206 |
+
"""PositionwiseFeedforward"""
|
207 |
+
def __init__(self, embed_dim, pf_dim, dropout):
|
208 |
+
super().__init__()
|
209 |
+
self.linear_1 = nn.Linear(embed_dim, pf_dim)
|
210 |
+
self.linear_2 = nn.Linear(pf_dim, embed_dim)
|
211 |
+
self.dropout = dropout
|
212 |
+
|
213 |
+
def forward(self, x):
|
214 |
+
"""
|
215 |
+
PositionwiseFeedforward
|
216 |
+
Args:
|
217 |
+
x (LongTensor): (batch, src_len, embed_dim)
|
218 |
+
Returns:
|
219 |
+
x (LongTensor): (batch, src_len, embed_dim)
|
220 |
+
"""
|
221 |
+
x = torch.relu(self.linear_1(x))
|
222 |
+
x = F.dropout(x, p=self.dropout, training=self.training)
|
223 |
+
|
224 |
+
return self.linear_2(x)
|
225 |
+
|
226 |
+
class PositionalEmbedding(nn.Module):
|
227 |
+
"Implement the PE function."
|
228 |
+
def __init__(self, d_model, dropout, max_len=500):
|
229 |
+
super().__init__()
|
230 |
+
pos_embed = torch.zeros(max_len, d_model)
|
231 |
+
position = torch.arange(0., max_len).unsqueeze(1)
|
232 |
+
div_term = torch.exp(torch.arange(0., d_model, 2) * -(math.log(10000.0) / d_model))
|
233 |
+
pos_embed[:, 0::2] = torch.sin(position * div_term)
|
234 |
+
pos_embed[:, 1::2] = torch.cos(position * div_term)
|
235 |
+
pos_embed = pos_embed.unsqueeze(0)
|
236 |
+
self.register_buffer('pos_embed', pos_embed)
|
237 |
+
|
238 |
+
def forward(self, x):
|
239 |
+
|
240 |
+
return Variable(self.pos_embed[:, :x.size(1)], requires_grad=False)
|
241 |
+
|
242 |
+
class NoamOpt:
|
243 |
+
"Optim wrapper that implements rate."
|
244 |
+
def __init__(self, optimizer, model_size=512, factor=1, warmup=2000):
|
245 |
+
self.optimizer = optimizer
|
246 |
+
self._step = 0
|
247 |
+
self.warmup = warmup
|
248 |
+
self.factor = factor
|
249 |
+
self.model_size = model_size
|
250 |
+
self._rate = 0
|
251 |
+
self.param_groups = optimizer.param_groups
|
252 |
+
|
253 |
+
def step(self):
|
254 |
+
"Update parameters and rate"
|
255 |
+
self._step += 1
|
256 |
+
rate = self.rate()
|
257 |
+
for p in self.optimizer.param_groups:
|
258 |
+
p['lr'] = rate
|
259 |
+
self._rate = rate
|
260 |
+
self.optimizer.step()
|
261 |
+
|
262 |
+
def rate(self, step = None):
|
263 |
+
"Implement `lrate` above"
|
264 |
+
if step is None:
|
265 |
+
step = self._step
|
266 |
+
return self.factor * \
|
267 |
+
(self.model_size ** (-0.5) *
|
268 |
+
min(step ** (-0.5), step * self.warmup ** (-1.5)))
|
269 |
+
|
270 |
+
def zero_grad(self):
|
271 |
+
self.optimizer.zero_grad()
|
app.py
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
3 |
+
import gradio as gr
|
4 |
+
import subprocess
|
5 |
+
import os
|
6 |
+
|
7 |
+
def run_shell_command(command):
|
8 |
+
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
|
9 |
+
output, error = process.communicate()
|
10 |
+
if error:
|
11 |
+
raise Exception(f"Error running command: {command}\n{error.decode('utf-8')}")
|
12 |
+
return output.decode('utf-8')
|
13 |
+
|
14 |
+
def load_model_and_tokenizer(model_path):
|
15 |
+
# Load the trained tokenizer
|
16 |
+
tokenizer = AutoTokenizer.from_pretrained(model_path)
|
17 |
+
|
18 |
+
# Load the trained model
|
19 |
+
model = AutoModelForSeq2SeqLM.from_pretrained(model_path)
|
20 |
+
|
21 |
+
# Move the model to the GPU if available
|
22 |
+
device = torch.device("cuda" if torch.cuda.is available() else "cpu")
|
23 |
+
model.to(device)
|
24 |
+
|
25 |
+
return tokenizer, model, device
|
26 |
+
|
27 |
+
def generate_text(tokenizer, model, device, prompt, max_length=100,
|
28 |
+
num_return_sequences=1, top_p=0.95, temperature=0.7):
|
29 |
+
# Tokenize the input prompt
|
30 |
+
input_ids = tokenizer.encode(prompt, return_tensors='pt').to(device)
|
31 |
+
|
32 |
+
# Generate text
|
33 |
+
output = model.generate(
|
34 |
+
input_ids,
|
35 |
+
max_length=max_length,
|
36 |
+
num_return_sequences=num_return_sequences,
|
37 |
+
no_repeat_ngram_size=2,
|
38 |
+
top_k=50,
|
39 |
+
top_p=top_p,
|
40 |
+
temperature=temperature,
|
41 |
+
do_sample=True
|
42 |
+
)
|
43 |
+
|
44 |
+
# Convert the generated text back to a string
|
45 |
+
generated_text = [tokenizer.decode(ids, skip_special_tokens=True) for ids in output]
|
46 |
+
|
47 |
+
return generated_text
|
48 |
+
|
49 |
+
def gradio_generate_text(prompt, max_length=100, num_return_sequences=1, top_p=0.95, temperature=0.7):
|
50 |
+
generated_text = generate_text(tokenizer, model, device, prompt, max_length, num_return_sequences, top_p, temperature)
|
51 |
+
return generated_text
|
52 |
+
|
53 |
+
# Ensure the models directory exists
|
54 |
+
# if not os.path.exists('models'):
|
55 |
+
# os.makedirs('models')
|
56 |
+
# if not os.path.exists('models/vi-medical-t5-finetune-qa'):
|
57 |
+
# # Run the Git LFS commands to clone the model
|
58 |
+
# run_shell_command('git lfs install')
|
59 |
+
# run_shell_command('cd models && git lfs clone https://huggingface.co/danhtran2mind/vi-medical-t5-finetune-qa && cd ..')
|
60 |
+
|
61 |
+
# Load the trained model and tokenizer
|
62 |
+
model_path = "models/vi-medical-t5-finetune-qa"
|
63 |
+
tokenizer, model, device = load_model_and_tokenizer(model_path)
|
64 |
+
|
65 |
+
# Create Gradio interface
|
66 |
+
iface = gr.Interface(
|
67 |
+
fn=gradio_generate_text,
|
68 |
+
inputs=[
|
69 |
+
gr.inputs.Textbox(lines=5, label="Input Prompt"),
|
70 |
+
gr.inputs.Slider(minimum=10, maximum=500, default=100, label="Max Length"),
|
71 |
+
gr.inputs.Slider(minimum=1, maximum=10, default=1, label="Number of Sequences"),
|
72 |
+
gr.inputs.Slider(minimum=0.1, maximum=1.0, default=0.95, label="Top-p Sampling"),
|
73 |
+
gr.inputs.Slider(minimum=0.1, maximum=1.0, default=0.7, label="Temperature")
|
74 |
+
],
|
75 |
+
outputs=gr.outputs.Textbox(label="Generated Text"),
|
76 |
+
title="Vietnamese Medical T5 Fine-Tuned Model",
|
77 |
+
description="Generate text using a fine-tuned Vietnamese medical T5 model."
|
78 |
+
)
|
79 |
+
|
80 |
+
# Launch the Gradio interface
|
81 |
+
iface.launch()
|
dataset/1_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:d254fafb6c9340b101bf478536af6e1dd7b1ffd516a820f2580e48df88794573
|
3 |
+
size 520161
|
dataset/1_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3660454cae6ff01e7c0046708abfe46dc67357bb239ec27bb4aa7d692c941149
|
3 |
+
size 3711672
|
dataset/1_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:18d4db7ec783e08f8cba280109b70b029c38aeecbdd72330eedc7cc52324687b
|
3 |
+
size 520352
|
dataset/2_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:c42f217da35a5318dacd46f85e003ac370471fc2b3e491e4ead730fcf77d0685
|
3 |
+
size 582656
|
dataset/2_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:85130ab449d23fe672e6a91b1791fdd5bae3b5b72bfc5f32620c5099bf82013f
|
3 |
+
size 4122052
|
dataset/2_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:109b7905010d967ade5299b0de22211606685557fd09d785179206654ec941b6
|
3 |
+
size 579852
|
dataset/3_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:188b82c5487b3bb6ff94bf654a1702f344c753c79e8bf27fcaf9df03f9bb6f55
|
3 |
+
size 600605
|
dataset/3_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:284958313282493c3b04c3eca2fe60c640eda64a81bd218b5a1ea0b1b07bb52a
|
3 |
+
size 4240422
|
dataset/3_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3cb2fd30ac52b1ff58eee680fa0135208841da39d873ed379841b88a27b822b4
|
3 |
+
size 595439
|
dataset/4_ans/UIT-ViCoV19QA_test.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:99860bae4ae5043e869c8047558d7db6d40e76d174aed522b7f37d7931c64fc9
|
3 |
+
size 610868
|
dataset/4_ans/UIT-ViCoV19QA_train.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:8e2e7f21cef6898d42eafc5ee094e9dac285e251af19f9f6b9c274d92f446881
|
3 |
+
size 4300607
|
dataset/4_ans/UIT-ViCoV19QA_val.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:dfe58d5c3e89a404c2db0620e3e9c893e8e0e29bfeaab05b6650f7ca6e82946a
|
3 |
+
size 603979
|
dataset/UIT-ViCoV19QA.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:65b147559695843829a0932fcaab9e6d1415d9821c3a0a3c1aa7ff8118a6ac6f
|
3 |
+
size 5515361
|
models/README.md
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:152dc41e703f31f4950210d6df2c69e384952acf1e99496b051cc2a86b010715
|
3 |
+
size 323
|
models/vi-medical-t5-finetune-qa/tokenizer_config.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:131a6e62a18a252551d92684ef82c7d7f8ef9f9f750ea4d666147d954bcc6de9
|
3 |
+
size 19282
|
notebooks/vi-medical-t5-finetune-qa.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|
requirements.txt
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
pandas==2.2.3
|
2 |
+
numpy==1.26.4
|
3 |
+
matplotlib==3.7.5
|
4 |
+
scikit-learn==1.2.2
|
5 |
+
gensim==4.3.3
|
6 |
+
underthesea==6.8.4
|
7 |
+
tensorflow==2.17.1
|
8 |
+
datasets==3.3.1
|
9 |
+
torch==2.5.1
|
10 |
+
transformers==4.47.0
|
11 |
+
gradio
|