-
Notifications
You must be signed in to change notification settings - Fork 28
/
utils.py
138 lines (120 loc) · 4.41 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import csv
import json
import numpy as np
import pdb
from tqdm import tqdm
def check_k(queries):
return len(queries[0]['mentions'][0]['candidates'])
def evaluate_topk_acc(data):
"""
evaluate acc@1~acc@k
"""
queries = data['queries']
k = check_k(queries)
for i in range(0, k):
hit = 0
for query in queries:
mentions = query['mentions']
mention_hit = 0
for mention in mentions:
candidates = mention['candidates'][:i+1] # to get acc@(i+1)
mention_hit += np.any([candidate['label'] for candidate in candidates])
# When all mentions in a query are predicted correctly,
# we consider it as a hit
if mention_hit == len(mentions):
hit +=1
data['acc{}'.format(i+1)] = hit/len(queries)
return data
def check_label(predicted_cui, golden_cui):
"""
Some composite annotation didn't consider orders
So, set label '1' if any cui is matched within composite cui (or single cui)
Otherwise, set label '0'
"""
return int(len(set(predicted_cui.split("|")).intersection(set(golden_cui.split("|"))))>0)
def predict_topk(biosyn, eval_dictionary, eval_queries, topk, score_mode='hybrid'):
"""
Parameters
----------
score_mode : str
hybrid, dense, sparse
"""
encoder = biosyn.get_dense_encoder()
tokenizer = biosyn.get_dense_tokenizer()
sparse_encoder = biosyn.get_sparse_encoder()
sparse_weight = biosyn.get_sparse_weight().item() # must be scalar value
# embed dictionary
dict_sparse_embeds = biosyn.embed_sparse(names=eval_dictionary[:,0], show_progress=True)
dict_dense_embeds = biosyn.embed_dense(names=eval_dictionary[:,0], show_progress=True)
queries = []
for eval_query in tqdm(eval_queries, total=len(eval_queries)):
mentions = eval_query[0].replace("+","|").split("|")
golden_cui = eval_query[1].replace("+","|")
dict_mentions = []
for mention in mentions:
mention_sparse_embeds = biosyn.embed_sparse(names=np.array([mention]))
mention_dense_embeds = biosyn.embed_dense(names=np.array([mention]))
# get score matrix
sparse_score_matrix = biosyn.get_score_matrix(
query_embeds=mention_sparse_embeds,
dict_embeds=dict_sparse_embeds
)
dense_score_matrix = biosyn.get_score_matrix(
query_embeds=mention_dense_embeds,
dict_embeds=dict_dense_embeds
)
if score_mode == 'hybrid':
score_matrix = sparse_weight * sparse_score_matrix + dense_score_matrix
elif score_mode == 'dense':
score_matrix = dense_score_matrix
elif score_mode == 'sparse':
score_matrix = sparse_score_matrix
else:
raise NotImplementedError()
candidate_idxs = biosyn.retrieve_candidate(
score_matrix = score_matrix,
topk = topk
)
np_candidates = eval_dictionary[candidate_idxs].squeeze()
dict_candidates = []
for np_candidate in np_candidates:
dict_candidates.append({
'name':np_candidate[0],
'cui':np_candidate[1],
'label':check_label(np_candidate[1],golden_cui)
})
dict_mentions.append({
'mention':mention,
'golden_cui':golden_cui, # golden_cui can be composite cui
'candidates':dict_candidates
})
queries.append({
'mentions':dict_mentions
})
result = {
'queries':queries
}
return result
def evaluate(biosyn, eval_dictionary, eval_queries, topk, score_mode='hybrid'):
"""
predict topk and evaluate accuracy
Parameters
----------
biosyn : BioSyn
trained biosyn model
eval_dictionary : str
dictionary to evaluate
eval_queries : str
queries to evaluate
topk : int
the number of topk predictions
score_mode : str
hybrid, dense, sparse
Returns
-------
result : dict
accuracy and candidates
"""
result = predict_topk(biosyn,eval_dictionary,eval_queries, topk, score_mode)
result = evaluate_topk_acc(result)
return result