Skip to content

Commit d2c7ed2

Browse files
committed
refresh rate,rm leaky relu, fix predictor
1 parent 3c9ef65 commit d2c7ed2

12 files changed

+68
-64
lines changed

Configuration.py

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ def __init__(self, p):
2828
self.cuda = True if torch.cuda.is_available() else False
2929
self.gpu = "cuda:0"
3030

31+
self.refresh_rate: int = 60 # interval of refresh in tqdm
32+
3133
def update_params(self, param: str, value: float):
3234
self.param[param] = value
3335

Evaluation/metrics.py

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import torch
22
from pandas import DataFrame
3-
from torch import Tensor, zeros, IntTensor, BoolTensor, LongTensor, masked_select
3+
from torch import Tensor, zeros, IntTensor, BoolTensor, LongTensor, masked_select, nn
44
from tqdm import tqdm
55
from transformers import BertTokenizerFast
66

@@ -11,15 +11,15 @@
1111

1212
def scores(confusion: Tensor, all_metrics=False):
1313
"""
14-
Given a Confusion matrix, returns an F1-score, if all_metrics is false, then returns only F1-score
14+
Given a Confusion matrix, returns an F1-score, if all_metrics is false, then returns only a mean of F1-score
1515
"""
1616
length = confusion.shape[0]
1717
iter_label = range(length)
1818

19-
accuracy: Tensor = torch.zeros(length)
20-
precision: Tensor = torch.zeros(length)
21-
recall: Tensor = torch.zeros(length)
22-
f1: Tensor = torch.zeros(length)
19+
accuracy: Tensor = zeros(length)
20+
precision: Tensor = zeros(length)
21+
recall: Tensor = zeros(length)
22+
f1: Tensor = zeros(length)
2323

2424
for i in iter_label:
2525
fn = torch.sum(confusion[i, :i]) + torch.sum(confusion[i, i + 1:]) # false negative
@@ -46,15 +46,15 @@ def scores(confusion: Tensor, all_metrics=False):
4646
return f1.mean()
4747

4848

49-
def eval_model(model, dataset: DataFrame, conf: Configuration,
49+
def eval_model(model: nn.Module, dataset: DataFrame, conf: Configuration,
5050
handler: EntityHandler, result="conlleval"):
5151
model.eval()
5252
true_label, pred_label = [], [] # using for conlleval
5353
max_labels = len(handler.set_entities)
5454
confusion = zeros(size=(max_labels, max_labels)) # Confusion matrix
5555
tokenizer = BertTokenizerFast.from_pretrained(conf.bert)
5656

57-
for row in tqdm(dataset.itertuples(), total=dataset.shape[0]):
57+
for row in tqdm(dataset.itertuples(), total=dataset.shape[0], desc="Evaluating", mininterval=conf.refresh_rate):
5858

5959
# tokens = ["Hi","How","are","you"], labels = ["O","I-TREAT" ...]
6060
tokens, labels = row[1].split(), row[2].split()
@@ -77,10 +77,11 @@ def eval_model(model, dataset: DataFrame, conf: Configuration,
7777
labels_ids = labels_ids.to(conf.gpu)
7878

7979
# Perform the prediction
80-
logits = model(input_ids, att_mask, None)
80+
path, _ = model(input_ids, att_mask, None)[0][0] # path is a list of int
81+
path = LongTensor(path)
8182

82-
path, _ = logits[0][0]
83-
path = torch.LongTensor(path).to("cuda:0")
83+
if conf.cuda:
84+
path = path.to(conf.gpu)
8485

8586
logits = masked_select(path, tag_mask)
8687
labels = masked_select(labels_ids, tag_mask)

Parsing/CustomDataset.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ def __init__(self, dataset: DataFrame, conf: Configuration, e_handler: EntityHan
1616

1717
tokenizer = BertTokenizerFast.from_pretrained(conf.bert)
1818

19-
for row in tqdm(dataset.itertuples(), total=dataset.shape[0], mininterval=60):
19+
for row in tqdm(dataset.itertuples(), total=dataset.shape[0], desc="Building dataset",
20+
mininterval=conf.refresh_rate):
2021

2122
# tokens = ["Hi","How","are","you"]
2223
tokens, labels = row[1].split(), row[2].split()

Parsing/parser_utils.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ def buildDataset(path_file: str, verbose=True) -> EntityHandler:
159159
return EntityHandler(DataFrame(t).drop_duplicates(), set_entities)
160160

161161

162-
def ensembleParser(path_file_a, path_file_b, verbose=True):
162+
def ensembleParser(path_file_a, path_file_b, verbose=True) -> tuple[tuple[EntityHandler, EntityHandler], DataFrame]:
163163
"""
164164
ensembleParser is used to group in one single dataframe the both to dataset A and B.
165165
@@ -225,10 +225,10 @@ def parse_args():
225225
p.add_argument('--bert', type=str,
226226
help='Bert model provided by Huggingface', default="dbmdz/bert-base-italian-xxl-cased")
227227

228-
p.add_argument('--save_model', type=int,
228+
p.add_argument('--save', type=int,
229229
help='set 1 if you want save the model otherwise set 0', default=1)
230230

231-
p.add_argument('--type_eval', type=str,
231+
p.add_argument('--eval', type=str,
232232
help='define the type of evaluation: conlleval or df', default="conlleval")
233233

234234
p.add_argument('--lr', type=float, help='Learning rate', default=0.001)
@@ -241,6 +241,6 @@ def parse_args():
241241

242242
p.add_argument('--max_epoch', type=int, help='Max number of epochs', default=20)
243243

244-
p.add_argument('--early_stopping', type=float, help='Patience in early stopping', default=3)
244+
p.add_argument('--patience', type=float, help='Patience in early stopping', default=3)
245245

246246
return p.parse_known_args()

Prediction/Predictor.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Tuple
22

3-
from torch import IntTensor, BoolTensor, masked_select
3+
from torch import IntTensor, BoolTensor, masked_select, LongTensor, nn
44
from transformers import BertTokenizerFast
55

66
import Configuration
@@ -58,7 +58,7 @@ def unify_labels(labelsA: list, labelsB: list) -> list:
5858
unified.append(a + "/" + b)
5959
return unified
6060

61-
def add_model(self, group: str, model, dictionary: dict):
61+
def add_model(self, group: str, model: nn.Module, dictionary: dict):
6262
model.eval()
6363
self.models[group] = (model, dictionary)
6464

@@ -77,9 +77,13 @@ def predict(self, string: str) -> Tuple[list, list]:
7777

7878
results = []
7979
for (model, dictionary) in self.models.values():
80-
logits = model(input_ids, att_mask, None)
81-
logits = logits[0].squeeze(0).argmax(1)
82-
logits = masked_select(logits, tag_mask).tolist()
80+
path, _ = model(input_ids, att_mask, None)[0][0]
81+
path = LongTensor(path)
82+
83+
if self.conf.cuda:
84+
path = path.to(self.conf.gpu)
85+
86+
logits = masked_select(path, tag_mask).tolist()
8387

8488
results.append(
8589
[lbl[2:] if lbl != "O" else "O" for lbl in self.map_id2lab(dictionary, logits)])

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
As final project for Human Language Technologies (HLT) I developed a project that extracts knowledge from Italian medical records written by physician and provides a simple web interface to make prediction on sentences. I also compared the quality of project’s result with the result of MultiCoNER competition. Both models uses BERT + CRF .
99

10-
#### *Report outdated further improvment have been applyed*
10+
#### *Report outdated further improvement have been applied*
1111

1212
report : [NER_for_Medical_Records.pdf](https://github.com/jacons/NERMedicalRecords/files/10427990/NER_for_Medical_Records.pdf)
1313

@@ -33,10 +33,10 @@ p.add_argument('--path_model', type=str,
3333
p.add_argument('--bert', type=str,
3434
help='Bert model provided by Huggingface', default="dbmdz/bert-base-italian-xxl-cased")
3535
36-
p.add_argument('--save_model', type=int,
36+
p.add_argument('--save', type=int,
3737
help='set 1 if you want save the model otherwise set 0', default=1)
3838
39-
p.add_argument('--type_eval', type=str,
39+
p.add_argument('--eval', type=str,
4040
help='define the type of evaluation: conlleval or df', default="conlleval")
4141
4242
p.add_argument('--lr', type=float, help='Learning rate', default=0.004)
@@ -49,7 +49,7 @@ p.add_argument('--batch_size', type=int, help='Batch size', default=16)
4949
5050
p.add_argument('--max_epoch', type=int, help='Max number of epochs', default=15)
5151
52-
p.add_argument('--early_stopping', type=float, help='Patience in early stopping', default=3)
52+
p.add_argument('--patience', type=float, help='Patience in early stopping', default=3)
5353
```
5454

5555
#### Running

Training/NERCRFClassifier.py

+5-8
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77
from torch.nn import Module
88
from transformers import BertPreTrainedModel, BertModel
99

10-
from Parsing.parser_utils import EntityHandler
11-
1210

1311
class NERBertCRFClassification(BertPreTrainedModel): # noqa
1412

1513
_keys_to_ignore_on_load_unexpected = [r"pooler"]
1614

17-
def __init__(self, config, handler: EntityHandler):
15+
def __init__(self, config, id2label: dict):
1816
super().__init__(config)
1917
self.num_labels = config.num_labels
2018

@@ -24,15 +22,14 @@ def __init__(self, config, handler: EntityHandler):
2422
self.bert = BertModel(config, add_pooling_layer=False)
2523

2624
self.linear_layer = nn.Sequential(
27-
nn.LeakyReLU(),
2825
nn.Dropout(classifier_dropout),
2926
nn.Linear(config.hidden_size, config.num_labels),
3027
nn.LogSoftmax(-1),
3128
)
3229

3330
self.crf_layer = ConditionalRandomField(num_tags=config.num_labels,
3431
constraints=allowed_transitions(constraint_type="BIO",
35-
labels=handler.id2label))
32+
labels=id2label))
3633

3734
# Initialize weights and apply final processing
3835
self.post_init()
@@ -80,16 +77,16 @@ def forward(
8077

8178

8279
class NERCRFClassifier(Module):
83-
def __init__(self, bert: str, handler: EntityHandler):
80+
def __init__(self, bert: str, id2label: dict):
8481
"""
8582
Bert model
8683
:param bert: Name of bert used
8784
:param frozen: True to freeze the deep parameters
8885
"""
8986
super(NERCRFClassifier, self).__init__()
9087

91-
num_labels = len(handler.set_entities)
92-
self.bert = NERBertCRFClassification.from_pretrained(bert, num_labels=num_labels, handler=handler)
88+
num_labels = len(id2label)
89+
self.bert = NERBertCRFClassification.from_pretrained(bert, num_labels=num_labels, id2label=id2label)
9390

9491
return
9592

Training/Trainer.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import torch
22
from pandas import DataFrame
3-
from torch import no_grad, zeros, masked_select
3+
from torch import no_grad, zeros, masked_select, nn
44
from torch.nn.utils import clip_grad_norm_
55
from torch.optim.lr_scheduler import ReduceLROnPlateau
66
from torch.optim.sgd import SGD
@@ -14,7 +14,7 @@
1414
from Training.trainer_utils import padding_batch, EarlyStopping, ModelVersion
1515

1616

17-
def train(model, e_handler: EntityHandler, df_train: DataFrame, df_val: DataFrame, conf: Configuration):
17+
def train(model: nn.Module, e_handler: EntityHandler, df_train: DataFrame, df_val: DataFrame, conf: Configuration):
1818
# --------- DATASETS ---------
1919
print("--INFO--\tCreating Dataloader for Training set")
2020
tr = DataLoader(NerDataset(df_train, conf, e_handler), collate_fn=padding_batch,
@@ -41,7 +41,7 @@ def train(model, e_handler: EntityHandler, df_train: DataFrame, df_val: DataFram
4141
model_version = ModelVersion(folder=conf.folder, name=conf.model_name) if conf.save_model else None
4242

4343
# --------- Scheduling the learning rate to improve the convergence ---------
44-
scheduler = ReduceLROnPlateau(optimizer, 'min', patience=2)
44+
scheduler = ReduceLROnPlateau(optimizer, 'min', patience=3)
4545

4646
print("\n--INFO--\tThe Training is started")
4747
model.train()
@@ -52,7 +52,7 @@ def train(model, e_handler: EntityHandler, df_train: DataFrame, df_val: DataFram
5252
# ========== Training Phase ==========
5353

5454
# There inputs are created in "NerDataset" class
55-
for inputs_ids, att_mask, _, labels in tqdm(tr, mininterval=60):
55+
for inputs_ids, att_mask, _, labels in tqdm(tr, desc="Training", mininterval=conf.refresh_rate):
5656
optimizer.zero_grad(set_to_none=True)
5757

5858
loss, _ = model(inputs_ids, att_mask, labels)
@@ -65,13 +65,16 @@ def train(model, e_handler: EntityHandler, df_train: DataFrame, df_val: DataFram
6565
# ========== Validation Phase ==========
6666
confusion = zeros(size=(max_labels, max_labels))
6767
with no_grad(): # Validation phase
68-
for inputs_ids, att_mask, tag_maks, labels in tqdm(vl, mininterval=60):
68+
for inputs_ids, att_mask, tag_maks, labels in tqdm(vl, desc="Evaluation", mininterval=conf.refresh_rate):
6969

7070
loss, logits = model(inputs_ids, att_mask, labels)
7171
loss_val += loss.item()
7272

7373
path, _ = logits[0]
74-
path = torch.LongTensor(path).to("cuda:0")
74+
path = torch.LongTensor(path)
75+
76+
if conf.cuda:
77+
path = path.to(conf.gpu)
7578

7679
logits = masked_select(path, tag_maks)
7780
labels = masked_select(labels, tag_maks)

eval_models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
(handler_a, handler_b), unified_dt = ensembleParser(paths[0], paths[1])
2222
_, _, df_test = holdout(unified_dt)
2323

24-
modelA = NERCRFClassifier(conf.bert, handler_a)
24+
modelA = NERCRFClassifier(conf.bert, handler_a.id2label)
2525
modelA.load_state_dict(torch.load(models[0]))
2626

27-
modelB = NERCRFClassifier(conf.bert, handler_b)
27+
modelB = NERCRFClassifier(conf.bert, handler_b.id2label)
2828
modelB.load_state_dict(torch.load(models[1]))
2929

3030
if conf.cuda:

prediction.py

+8-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from Configuration import Configuration
44
from Parsing.parser_utils import parse_args
55
from Prediction.Predictor import Predictor
6-
from Training.NERClassifier import NERClassifier
6+
from Training.NERCRFClassifier import NERCRFClassifier
77

88
if __name__ == '__main__':
99

@@ -17,10 +17,15 @@
1717

1818
models = args.models
1919

20-
modelA = NERClassifier(conf.bert, 9, frozen=False)
20+
id2lab_group_a = {0: 'B-ACTI', 1: 'B-DISO', 2: 'B-DRUG', 3: 'B-SIGN', 4: 'I-ACTI', 5: 'I-DISO', 6: 'I-DRUG',
21+
7: 'I-SIGN', 8: 'O'}
22+
23+
id2lab_group_b = {0: 'B-BODY', 1: 'B-TREA', 2: 'I-BODY', 3: 'I-TREA', 4: 'O'}
24+
25+
modelA = NERCRFClassifier(conf.bert, id2lab_group_a)
2126
modelA.load_state_dict(torch.load(models[0]))
2227

23-
modelB = NERClassifier(conf.bert, 5, frozen=False)
28+
modelB = NERCRFClassifier(conf.bert, id2lab_group_b)
2429
modelB.load_state_dict(torch.load(models[1]))
2530

2631
if conf.cuda:
@@ -29,14 +34,5 @@
2934

3035
predictor = Predictor(conf)
3136

32-
id2lab_group_a = {0: 'B-ACTI', 1: 'B-DISO', 2: 'B-DRUG', 3: 'B-SIGN', 4: 'I-ACTI', 5: 'I-DISO', 6: 'I-DRUG',
33-
7: 'I-SIGN', 8: 'O'}
34-
35-
id2lab_group_b = {0: 'B-BODY', 1: 'B-TREA', 2: 'I-BODY', 3: 'I-TREA', 4: 'O'}
36-
3737
predictor.add_model("a", modelA, id2lab_group_a)
3838
predictor.add_model("b", modelB, id2lab_group_b)
39-
40-
print(predictor.predict("Hello!!"))
41-
42-
# C:\ProgramData\Anaconda3\envs\deeplearning\python.exe train_model.py --models K:/NoSyncCache/Models/A/modelE1.pt K:/NoSyncCache/Models/B/modelH2.pt

server.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from Configuration import Configuration
55
from Parsing.parser_utils import parse_args
66
from Prediction.Predictor import Predictor
7-
from Training.NERClassifier import NERClassifier
7+
from Training.NERCRFClassifier import NERCRFClassifier
88

99
app = Flask(__name__)
1010

@@ -15,10 +15,15 @@
1515

1616
models = ["saved_models/model.a.pt", "saved_models/model.b.pt"]
1717

18-
modelA = NERClassifier(conf.bert, 9, frozen=False)
18+
id2lab_group_a = {0: 'B-ACTI', 1: 'B-DISO', 2: 'B-DRUG', 3: 'B-SIGN', 4: 'I-ACTI', 5: 'I-DISO', 6: 'I-DRUG',
19+
7: 'I-SIGN', 8: 'O'}
20+
21+
id2lab_group_b = {0: 'B-BODY', 1: 'B-TREA', 2: 'I-BODY', 3: 'I-TREA', 4: 'O'}
22+
23+
modelA = NERCRFClassifier(conf.bert, id2lab_group_a)
1924
modelA.load_state_dict(torch.load(models[0], map_location=torch.device('cpu')))
2025

21-
modelB = NERClassifier(conf.bert, 5, frozen=False)
26+
modelB = NERCRFClassifier(conf.bert, id2lab_group_b)
2227
modelB.load_state_dict(torch.load(models[1], map_location=torch.device('cpu')))
2328

2429
if conf.cuda:
@@ -27,11 +32,6 @@
2732

2833
predictor = Predictor(conf)
2934

30-
id2lab_group_a = {0: 'B-ACTI', 1: 'B-DISO', 2: 'B-DRUG', 3: 'B-SIGN', 4: 'I-ACTI', 5: 'I-DISO', 6: 'I-DRUG',
31-
7: 'I-SIGN', 8: 'O'}
32-
33-
id2lab_group_b = {0: 'B-BODY', 1: 'B-TREA', 2: 'I-BODY', 3: 'I-TREA', 4: 'O'}
34-
3535
predictor.add_model("a", modelA, id2lab_group_a)
3636
predictor.add_model("b", modelB, id2lab_group_b)
3737

@@ -52,4 +52,4 @@ def create():
5252
elif "clear" in request.form:
5353
list_of_result.clear()
5454

55-
return render_template('main.html', list_of_result=list_of_result)
55+
return render_template('main.html', list_of_result=list_of_result)

train_model.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
raise Exception("Define a model name!")
1818

1919
handler = buildDataset(args.datasets[0], verbose=True)
20-
df_train, df_val, df_test = holdout(handler.dt)
20+
df_train, df_val, _ = holdout(handler.dt)
2121

22-
model = NERCRFClassifier(conf.bert, handler)
22+
model = NERCRFClassifier(conf.bert, handler.id2label)
2323

2424
if conf.cuda:
2525
model = model.to(conf.gpu)

0 commit comments

Comments
 (0)