From 36720c72046133706957e6f7db5397b0de189258 Mon Sep 17 00:00:00 2001
From: PNRIA - Julien <julien.rabault@irit.fr>
Date: Tue, 17 May 2022 10:59:06 +0200
Subject: [PATCH] Add README.md

---
 .gitignore                                    |  10 +-
 Configuration/Configuration.py                |  17 ---
 Configuration/config.ini                      |  18 ---
 Datasets/index_to_pos1.pkl                    | Bin 0 -> 1632 bytes
 Datasets/index_to_super.pkl                   | Bin 0 -> 168867 bytes
 .../{m2_dataset_V2.csv => m2_dataset.csv}     |   0
 README.md                                     |  76 +++++++++++-
 SuperTagger/SuperTagger.py                    | 113 +++++++++++++-----
 SuperTagger/Utils/SentencesTokenizer.py       |  24 ----
 SuperTagger/Utils/utils.py                    |  11 +-
 bash_GPU.sh                                   |  13 --
 requirements.txt                              | Bin 99 -> 476 bytes
 train.py                                      |  12 +-
 13 files changed, 170 insertions(+), 124 deletions(-)
 delete mode 100644 Configuration/Configuration.py
 delete mode 100644 Configuration/config.ini
 create mode 100644 Datasets/index_to_pos1.pkl
 create mode 100644 Datasets/index_to_super.pkl
 rename Datasets/{m2_dataset_V2.csv => m2_dataset.csv} (100%)
 delete mode 100644 bash_GPU.sh

diff --git a/.gitignore b/.gitignore
index 371503a..f57c436 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,11 @@
 .idea
-tests
 venv
 *.pyc
 .DS_Store
-.env
-./bash_GPU.sh
-push pull texte
-logs
-Output
 .data
 TensorBoard
 models
-*.pkl
-good_models/model_check.pt
+good_models
 main.py
 *.pt
+Datasets/Utils
diff --git a/Configuration/Configuration.py b/Configuration/Configuration.py
deleted file mode 100644
index 3d94c9b..0000000
--- a/Configuration/Configuration.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import os
-from configparser import ConfigParser
-
-# Read configuration file
-path_current_directory = os.path.dirname(__file__)
-path_config_file = os.path.join(path_current_directory, 'config.ini')
-config = ConfigParser()
-config.read(path_config_file)
-
-# region Get section
-
-version = config["VERSION"]
-
-modelDecoderConfig = config["MODEL_DECODER"]
-modelTrainingConfig = config["MODEL_TRAINING"]
-
-# endregion Get section
diff --git a/Configuration/config.ini b/Configuration/config.ini
deleted file mode 100644
index 3fb0157..0000000
--- a/Configuration/config.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[VERSION]
-transformers = 4.16.2
-[MODEL_DECODER]
-dim_encoder = 768
-dim_decoder = 128
-num_rnn_layers=1
-dropout=0.1
-teacher_forcing=0.05
-[MODEL_TRAINING]
-batch_size=16
-epoch=10
-seed_val=42
-learning_rate=0.005
-use_checkpoint_SAVE=1
-output_path=Output
-use_checkpoint_LOAD=1
-input_path=models_save
-model_to_load=model_check.pt
\ No newline at end of file
diff --git a/Datasets/index_to_pos1.pkl b/Datasets/index_to_pos1.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..c212d7e65f99a80671dfe2dba3481bbd49c22c6e
GIT binary patch
literal 1632
zcmZo*of^u<00y;FG`tylMDt2>3o7-J^NUjTa!YecG82o65-X?luoWjK<|GzPnLMS3
z6|7`R4{J(EWkD)PgelZ`N@qv=l%OdZ-poCWHdFlk{JeR*S-d$)rX)G@I5IFWxG*p<
zcrh?AOlg}EG{u`SgE@n(hbhz)p)G?8q)7y(Nd#F_I0FNN2V64~R5OyD5Y3o2hQT#4
zLp2d$BS;gfjVw^jM(EDvfH{}LnSp@;gdzT8g=)a#M37=11_lOyxD(lk*AxWT#7?}X
zV7Mj@s3rpbL1^HFYQW<kPz1X&FffF`ZQ+7y!V~1knoxtB8>$(P6H#sBfod>Bk0TaX
z9I<%9oyH4QjK_38lnCX6YQPf!APoTw3=AL)Nd^2+O?aGyP%HpdjK>C$Vr^(%g4iGk
z)r2RAVVXcRDA^#=n-FoDK^j1Q10`5Q<O)MIo1h1`04%r#U^ar{$qgR#B2bM4{E6yR
zQK%*}blW6gwn@Nj134F@8DuLce?bCD3~B&@fC6a*8GxD=#i5$<#3QK8fY>AfRg5QK
zK#D<W(HAAPND{9R6di~Vm4a%-6QUp+K>-B95NApguL%?=5KS^rO?a{m$R>EXQK|<3
Di1V+O

literal 0
HcmV?d00001

diff --git a/Datasets/index_to_super.pkl b/Datasets/index_to_super.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..606848f7652155e0048c281320e36f46886661e5
GIT binary patch
literal 168867
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
z%0D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
b2?<b$LsSRCRO7J=q#9%oa`6JzU8)BFh8of$

literal 0
HcmV?d00001

diff --git a/Datasets/m2_dataset_V2.csv b/Datasets/m2_dataset.csv
similarity index 100%
rename from Datasets/m2_dataset_V2.csv
rename to Datasets/m2_dataset.csv
diff --git a/README.md b/README.md
index 5994f14..5ece8c3 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,87 @@
 # DeepGrail
 
+This repository contains a Python implementation of BertForTokenClassification using TLGbank data to develop
+part-of-speech taggers and supertaggers.
+
+This code was designed to work with the [DeepGrail Linker](https://gitlab.irit.fr/pnria/global-helper/deepgrail-linker)
+to provide a wide coverage syntactic and semantic parser for French. But the Tagger is independent, you can use it for your own tags.
+
 ## Usage
 
+### Structure
+
+```
+.
+├── Datasets                    # TLGbank data
+├── SuperTagger                 # Implementation of BertForTokenClassification
+│   ├── SuperTagger.py          # Main class
+│   └── Tagging_bert_model.py   # Bert model
+├── predict.py                  # Example of prediction
+└── train.py                    # Example of train
+```
+
 ### Installation
+
 Python 3.9.10 **(Warning don't use Python 3.10**+**)**
 
 Clone the project locally. In a clean python venv do `pip install -r requirements.txt`
 
+Download already trained models or prepare data for **your** train.
+
 ## How To use
 
-TODO ...
+**predict.py** and **train.py** show simple examples of how to use the model, feel free to look at them before using the
+SupperTagger
+
+### Utils
+
+For load **m2_dataset.csv**, you can use `SuperTagger.Utils.utils.read_csv_pgbar(...)`. This function return a pandas
+dataframe.
+
+### Prediction
+
+For predict on your data you need to load a model (save with this code).
+
+```
+df = read_csv_pgbar(file_path,20)
+texts = df['X'].tolist()
+
+tagger = SuperTagger()
+
+tagger.load_weights("your/model/path")
+
+pred_without_argmax, pred_convert, bert_hidden_state = tagger.predict(texts[7])
+
+print(pred_convert)
+#['let', 'dr(0,s,s)', 'let', 'dr(0,dr(0,s,s),np)', 'dr(0,np,n)', 'dr(0,n,n)', 'let', 'n', 'let', 'dl(0,n,n)', 'dr(0,dl(0,dl(0,n,n),dl(0,n,n)),dl(0,n,n))', 'dl(0,n,n)', 'let', 'dr(0,np,np)', 'np', 'dr(0,dl(0,np,np),np)', 'np', 'dr(0,dl(0,np,np),np)', 'np', 'dr(0,dl(0,np,s),dl(0,np,s))', 'dr(0,dl(0,np,s),np)', 'dl(1,s,s)', 'np', 'dr(0,dl(0,np,np),n)', 'n', 'dl(0,s,txt)']
+```
+
+### Training
+
+```
+df = read_csv_pgbar(file_path,1000)
+texts = df['X'].tolist()
+tags = df['Z'].tolist()
+
+#Dict for convert ID to token (The dict is save with the model for prediction)
+index_to_super = load_obj('Datasets/index_to_super') 
+
+tagger = SuperTagger()
+
+bert_name = 'camembert-base'
+
+tagger.create_new_model(len(index_to_super), bert_name, index_to_super)
+# You can load your model for re-train this
+# tagger.load_weights("your/model/path")
+
+tagger.train(texts,tags, checkpoint=True)
+
+pred_without_argmax, pred_convert, bert_hidden_state = tagger.predict(texts[7])
+```
+
+In train, if you use `checkpoint=True`, the model is automatically saved in a folder: Training_XX-XX_XX-XX. It saves after each epoch.
+Use `tensorboard=True` for log in same folder. (`tensorboard --logdir=logs` for see logs)
 
-tensorboard --logdir=logs
+## Authors
 
+[Rabault Julien](https://www.linkedin.com/in/julienrabault), de Pourtales Caroline
\ No newline at end of file
diff --git a/SuperTagger/SuperTagger.py b/SuperTagger/SuperTagger.py
index 70c1592..95b3d59 100644
--- a/SuperTagger/SuperTagger.py
+++ b/SuperTagger/SuperTagger.py
@@ -1,26 +1,45 @@
+import datetime
 import os
 import sys
-
 import time
-import datetime
-from tkinter import Variable
 
 import torch
 import transformers
-from torch import nn
+from torch import nn, Tensor
 from torch.optim import Adam
+from torch.utils.data import Dataset, TensorDataset, random_split, DataLoader
 from torch.utils.tensorboard import SummaryWriter
 from tqdm import tqdm
 from transformers import AutoTokenizer
-
-from torch.utils.data import Dataset, TensorDataset, random_split
+from transformers import logging
 
 from SuperTagger.Utils.SentencesTokenizer import SentencesTokenizer
 from SuperTagger.Utils.SymbolTokenizer import SymbolTokenizer
 from SuperTagger.Utils.Tagging_bert_model import Tagging_bert_model
 
+logging.set_verbosity(logging.ERROR)
+
+
+def output_create_dir():
+    """
+
+    @return:
+    """
+    from datetime import datetime
+    outpout_path = 'TensorBoard'
+    training_dir = os.path.join(outpout_path, 'Tranning_' + datetime.today().strftime('%d-%m_%H-%M'))
+    logs_dir = os.path.join(training_dir, 'logs')
+    writer = SummaryWriter(log_dir=logs_dir)
+    return training_dir, writer
+
 
-def categorical_accuracy(preds, truth):
+def categorical_accuracy(preds: list[list[int]], truth: list[list[int]]) -> float:
+    """
+
+    @param preds:
+    @param truth:
+    @return:
+    """
     good_label = 0
     nb_label = 0
     for i in range(len(truth)):
@@ -48,7 +67,9 @@ def format_time(elapsed):
 class SuperTagger:
 
     def __init__(self):
+        """
 
+        """
         self.index_to_tags = None
         self.num_label = None
         self.bert_name = None
@@ -65,7 +86,11 @@ class SuperTagger:
         self.trainable = False
         self.model_load = False
 
-    def load_weights(self, model_file):
+    def load_weights(self, model_file: str):
+        """
+        yo mec
+        @param model_file:
+        """
         self.trainable = False
 
         print("#" * 15)
@@ -95,8 +120,13 @@ class SuperTagger:
         self.model_load = True
         self.trainable = True
 
-    def create_new_model(self, num_label, bert_name, index_to_tags: dict):
+    def create_new_model(self, num_label: int, bert_name: str, index_to_tags: dict):
+        """
 
+        @param num_label:
+        @param bert_name:
+        @param index_to_tags:
+        """
         assert len(
             index_to_tags) == num_label, f" len(index_to_tags) : {len(index_to_tags)} must be equels with num_label: {num_label}"
 
@@ -114,9 +144,15 @@ class SuperTagger:
         self.trainable = True
         self.model_load = True
 
-    def predict(self, sentences):
+    def predict(self, sentences: list[str]) -> (list[list[list[float]]], list[list[str]], Tensor):
+        """
 
+        @param sentences:
+        @return:
+        """
         assert self.trainable or self.model is None, "Please use the create_new_model(...) or load_weights(...) function before the predict, the model is not integrated"
+        sentences = [sentences] if type(sentences) == str else sentences
+
         self.model.eval()
         with torch.no_grad():
             sents_tokenized_t, sents_mask_t = self.sent_tokenizer.fit_transform_tensors(sentences)
@@ -127,13 +163,23 @@ class SuperTagger:
 
             return preds, self.tags_tokenizer.convert_ids_to_tags(preds.detach()), hidden
 
-    def train(self, sentences, tags, validation_rate=0.1, epochs=20, batch_size=32, tensorboard=False,
+    def train(self, sentences: list[str], tags: list[list[str]], validation_rate=0.1, epochs=20, batch_size=32,
+              tensorboard=False,
               checkpoint=False):
-
+        """
+
+        @param sentences:
+        @param tags:
+        @param validation_rate:
+        @param epochs:
+        @param batch_size:
+        @param tensorboard:
+        @param checkpoint:
+        """
         assert self.trainable or self.model is None, "Please use the create_new_model(...) or load_weights(...) function before the train, the model is not integrated"
 
         if checkpoint or tensorboard:
-            checkpoint_dir, writer = self.__output_create()
+            checkpoint_dir, writer = output_create_dir()
 
         training_dataloader, validation_dataloader = self.__preprocess_data(batch_size, sentences, tags,
                                                                             1 - validation_rate)
@@ -171,8 +217,16 @@ class SuperTagger:
             if checkpoint:
                 self.__checkpoint_save(path=os.path.join(checkpoint_dir, 'model_check.pt'))
 
-    def __preprocess_data(self, batch_size, sentences, tags, validation_rate):
+    def __preprocess_data(self, batch_size: int, sentences: list[str], tags: list[list[str]],
+                          validation_rate: float) -> (DataLoader, DataLoader):
+        """
 
+        @param batch_size:
+        @param sentences:
+        @param tags:
+        @param validation_rate:
+        @return:
+        """
         validation_dataloader = None
 
         sents_tokenized_t, sents_mask_t = self.sent_tokenizer.fit_transform_tensors(sentences)
@@ -191,15 +245,12 @@ class SuperTagger:
         training_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
         return training_dataloader, validation_dataloader
 
-    def __output_create(self):
-        from datetime import datetime
-        outpout_path = 'TensorBoard'
-        training_dir = os.path.join(outpout_path, 'Tranning_' + datetime.today().strftime('%d-%m_%H-%M'))
-        logs_dir = os.path.join(training_dir, 'logs')
-        writer = SummaryWriter(log_dir=logs_dir)
-        return training_dir, writer
+    def __train_epoch(self, training_dataloader: DataLoader) -> (float, float, str):
+        """
 
-    def __train_epoch(self, training_dataloader):
+        @param training_dataloader:
+        @return:
+        """
         self.model.train()
         epoch_loss = 0
         epoch_acc = 0
@@ -217,8 +268,6 @@ class SuperTagger:
 
                 predictions = torch.argmax(logit, dim=2).detach().cpu().numpy()
                 label_ids = targets.cpu().numpy()
-                # torch.nn.functional.one_hot(targets).long()
-                # torch.argmax(logit)
 
                 acc = categorical_accuracy(predictions, label_ids)
 
@@ -238,11 +287,17 @@ class SuperTagger:
 
         return epoch_acc, epoch_loss, training_time
 
-    def foward(self,b_sents_tokenized, b_sents_mask):
+    def foward(self, b_sents_tokenized: Tensor, b_sents_mask: Tensor) -> (Tensor, Tensor):
+        """
+
+        @param b_sents_tokenized:
+        @param b_sents_mask:
+        @return:
+        """
         _, logit, hidden = self.model((b_sents_tokenized, b_sents_mask))
         return logit, hidden
 
-    def __eval_epoch(self, validation_dataloader):
+    def __eval_epoch(self, validation_dataloader: DataLoader) -> (float, float, int):
         self.model.eval()
         eval_loss = 0
         eval_accuracy = 0
@@ -270,6 +325,10 @@ class SuperTagger:
         return eval_accuracy, eval_loss, nb_eval_steps
 
     def __checkpoint_save(self, path='/model_check.pt'):
+        """
+
+        @param path:
+        """
         self.model.cpu()
         # print('save model parameters to [%s]' % path, file=sys.stderr)
 
@@ -279,5 +338,3 @@ class SuperTagger:
             'optimizer': self.optimizer,
         }, path)
         self.model.to(self.device)
-
-
diff --git a/SuperTagger/Utils/SentencesTokenizer.py b/SuperTagger/Utils/SentencesTokenizer.py
index f1fbea5..ee72006 100644
--- a/SuperTagger/Utils/SentencesTokenizer.py
+++ b/SuperTagger/Utils/SentencesTokenizer.py
@@ -1,6 +1,3 @@
-import numpy as np
-import torch
-
 
 class SentencesTokenizer():
 
@@ -12,28 +9,7 @@ class SentencesTokenizer():
         return self.tokenizer(sents, padding=True)
 
     def fit_transform_tensors(self, sents):
-        # , return_tensors = 'pt'
         temp = self.tokenizer(sents, padding=True, return_tensors = 'pt')
-        #
-        # len_sent_max = len(temp['attention_mask'][0])
-        #
-        # input_ids = np.ones((len(sents),len_sent_max))
-        # attention_mask = np.zeros((len(sents),len_sent_max))
-        #
-        # for i in range(len(temp['offset_mapping'])):
-        #     h = 1
-        #     input_ids[i][0] = self.tokenizer.cls_token_id
-        #     attention_mask[i][0] = 1
-        #     for j in range (1,len_sent_max-1):
-        #         if temp['offset_mapping'][i][j][1] != temp['offset_mapping'][i][j+1][0]:
-        #             input_ids[i][h] = temp['input_ids'][i][j]
-        #             attention_mask[i][h] = 1
-        #             h += 1
-        #     input_ids[i][h] = self.tokenizer.eos_token_id
-        #     attention_mask[i][h] = 1
-        #
-        # input_ids = torch.tensor(input_ids).long()
-        # attention_mask = torch.tensor(attention_mask)
 
         return temp["input_ids"], temp["attention_mask"]
 
diff --git a/SuperTagger/Utils/utils.py b/SuperTagger/Utils/utils.py
index 03aadfe..4c22a68 100644
--- a/SuperTagger/Utils/utils.py
+++ b/SuperTagger/Utils/utils.py
@@ -1,7 +1,4 @@
-import datetime
-
 import pandas as pd
-import torch
 from tqdm import tqdm
 
 
@@ -16,7 +13,8 @@ def read_csv_pgbar(csv_path, nrows=float('inf'), chunksize=100):
         rows = nrows
 
     with tqdm(total=rows, desc='Rows read: ') as bar:
-        for chunk in pd.read_csv(csv_path, converters={'Y1': pd.eval,'Y2': pd.eval,'Z': pd.eval}, chunksize=chunksize, nrows=rows):
+        for chunk in pd.read_csv(csv_path, converters={'Y1': pd.eval, 'Y2': pd.eval, 'Z': pd.eval}, chunksize=chunksize,
+                                 nrows=rows):
             chunk_list.append(chunk)
             bar.update(len(chunk))
 
@@ -24,5 +22,10 @@ def read_csv_pgbar(csv_path, nrows=float('inf'), chunksize=100):
     print("#" * 20)
     return df
 
+def load_obj(name):
+    with open(name + '.pkl', 'rb') as f:
+        import pickle
+        return pickle.load(f)
+
 
 
diff --git a/bash_GPU.sh b/bash_GPU.sh
deleted file mode 100644
index 665f769..0000000
--- a/bash_GPU.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-#SBATCH --job-name=N-tensorboard
-#SBATCH --partition=RTX6000Node
-#SBATCH --gres=gpu:1
-#SBATCH --mem=32000
-#SBATCH --gres-flags=enforce-binding
-#SBATCH --error="error_rtx1.err"
-#SBATCH --output="out_rtx1.out"
-
-module purge
-module load singularity/3.0.3
-
-srun singularity exec /logiciels/containerCollections/CUDA11/pytorch-NGC-21-03-py3.sif python "train.py"
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index c611e9b46c45eac6d06ab14c47a951c0c641796c..41ce3b5b133a0d8ce94376ac0e32283b3c9f2417 100644
GIT binary patch
literal 476
zcmezWFN2|!A)O(eA(J7GA)O(OA(0`OA(cUw0VJNpV9Q|3V8EcqV8WosV8Fo3z{TLp
zkjPNPkj;?7kk3%gkOx*_%%H~r!e(F<c?_itxeNsim0&qT20aEN1|zTvkp2R&4cQEd
za63VE7%_m<8H4qMROB(FFeEY*!%YC$Zv>VtW=LkpWXNX7WGG?KWyoPj1-l304nwdj
zLH2=cf~Z7xhXq(3BA3dL$56rmB0>HwV8~=h1^XQ28jz1cW?3>od<0Qf%#hDe#E`_0
z54JG{>^6|U5T=$e<TGT0&CFz|Vn}5ug8Ber9!RYr*bg9eMGVOd8DKL&HW`Bb4+-HC
phC+rEhFq{5$lqp2p<lvK#E{64$570W26jy@k}V*$h71VT005AzMrZ&4

literal 99
zcmc~R%`K?3wKdc;GSV~RDk)0LD^ANV%1tdQwzW0UGc*GU<`*SrfRq>-=oxWkl%}U=
w=B1}4Ca3CVlqT8Q8t9qm8E_RO=A|SSgH)O58FCe;=9Q%8C8ri-rY5HX00hDx7ytkO

diff --git a/train.py b/train.py
index d5e66aa..ddcda4c 100644
--- a/train.py
+++ b/train.py
@@ -1,14 +1,7 @@
 from SuperTagger.SuperTagger import SuperTagger
-from SuperTagger.Utils.utils import read_csv_pgbar
+from SuperTagger.Utils.utils import read_csv_pgbar, load_obj
 
-
-def load_obj(name):
-    with open(name + '.pkl', 'rb') as f:
-        import pickle
-        return pickle.load(f)
-
-
-file_path = 'Datasets/m2_dataset_V2.csv'
+file_path = 'Datasets/m2_dataset.csv'
 
 
 df = read_csv_pgbar(file_path,1000)
@@ -25,7 +18,6 @@ tags = tags[4:]
 
 
 index_to_super = load_obj('Datasets/index_to_pos1')
-super_to_index = {v: int(k) for k, v in index_to_super.items()}
 
 tagger = SuperTagger()
 
-- 
GitLab