aacengiz commited on
Commit
ebb4f06
·
1 Parent(s): 66ad5b0

Add ner and pos (in progress)

Browse files
Files changed (2) hide show
  1. src/deepeval/ner.py +166 -0
  2. src/deepeval/pos.py +159 -0
src/deepeval/ner.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.deepeval.base_task import BaseTask
2
+ from collections import defaultdict
3
+ from src.deepeval.utils import accuracy, accuracy_standard_error
4
+ from typing import Any
5
+ import re
6
+
7
+ class NERTask(BaseTask):
8
+ def __init__(self, model_name):
9
+ super().__init__("metunlp/tr_ner", model_name=model_name)
10
+
11
+ def load_dataset_from_hf(self):
12
+ dataset = super().load_dataset_from_hf()
13
+ return dataset.select(range(min(1, len(dataset))))
14
+
15
+ def generate_response_oeqa_multi_token(self, msg,max_new_tokens: int = 128):
16
+ """
17
+ Handles multiple-choice questions where answers might have multiple tokens.
18
+ """
19
+ # Ensure tokenizer has proper special tokens set
20
+ if self.tokenizer.pad_token is None:
21
+ self.tokenizer.pad_token = self.tokenizer.eos_token
22
+
23
+ if self.model.config.pad_token_id is None:
24
+ self.model.config.pad_token_id = self.tokenizer.pad_token_id
25
+
26
+ chat = [
27
+ {"role": "user", "content": "You are a question-answering chatbot."},
28
+ {"role": "assistant", "content": "I am ready to answer your questions. Feel free to ask anything.\n"},
29
+ {"role": "user", "content": f"{msg}"},
30
+ ]
31
+ formatted_chat = self.tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)
32
+ print(formatted_chat)
33
+
34
+ inputs = self.tokenizer(formatted_chat, return_tensors="pt", padding=True, truncation=True)
35
+ input_ids = inputs.input_ids.to(self.model.device)
36
+ attention_mask = inputs.attention_mask.to(self.model.device)
37
+
38
+
39
+ # Generate response with proper token limits
40
+ output = self.model.generate(
41
+ input_ids,
42
+ do_sample=True,
43
+ attention_mask=attention_mask,
44
+ eos_token_id=self.tokenizer.eos_token_id,
45
+ pad_token_id=self.tokenizer.pad_token_id,
46
+ temperature=0.4,
47
+ max_new_tokens=max_new_tokens,
48
+ )
49
+
50
+ generated_ids = output[0] # The generated sequence including the prompt
51
+ generated_tokens = generated_ids[len(input_ids[0]):] # Exclude the input_ids part
52
+ generated_text = self.tokenizer.decode(generated_tokens, skip_special_tokens=True)
53
+
54
+ return generated_text
55
+
56
+
57
+ def evaluate(self) -> dict[str, Any]:
58
+ responses = []
59
+ difficulty_results = defaultdict(lambda: {'correct': 0, 'total': 0})
60
+ total_count = 0
61
+ true = 0
62
+
63
+ for row in self.dataset:
64
+ total_count += 1
65
+
66
+ # Get values from row
67
+ category = str(row["difficulty"])
68
+ answer = row["final_answer"]
69
+
70
+ # Prints for debugging
71
+ print(f"Answer: {answer}")
72
+ print("Type of answer:", type(answer))
73
+
74
+ # Construct the prompt/message
75
+ instruction = ("Aşağıdaki Named Entity Recognition (NER) için etiketlenmesi gereken cümleler vardır. "
76
+ "Cümlelerdeki varlıkları belirleyin ve şu kategorilere ayırın: CARDINAL, DATE, EVENT, FAC, GPE, LANGUAGE, LAW, LOC, MONEY, NORP, ORDINAL, ORG, PER, PERCENT, PERSON, PRODUCT, QUANTITY, TIME, TITLE, WORK_OF_ART. "
77
+ ""
78
+ "Varlıklar, anlamlı bilgiler içeren terimlerdir ve aşağıdaki şekilde tanımlanır: "
79
+ "CARDINAL: Nicelik veya sıralama belirtmeyen sayısal ifadeler."
80
+ "DATE: Belirli bir tarih veya zaman ifadeleri."
81
+ "EVENT: Adlandırılmış olaylar veya durumlar."
82
+ "FAC: Binalar veya önemli yerler gibi tesisler."
83
+ "GPE: Ülke, şehir veya eyalet gibi coğrafi-politik varlıklar."
84
+ "LANGUAGE: Adlandırılmış diller."
85
+ "LAW: Yasal belgeler, düzenlemeler veya kanunlar."
86
+ "LOC: Coğrafi veya fiziksel konumlar (GPE dışındaki)."
87
+ "MONEY: Parasal değerler."
88
+ "NORP: Milletler, dini veya siyasi gruplar."
89
+ "ORDINAL: Sıralama veya dereceler."
90
+ "ORG: Organizasyonlar veya kurumlar."
91
+ "PER: Kişisel unvanlar veya sıfatlar."
92
+ "PERSON: Bireylerin isimleri."
93
+ "PRODUCT: Üretilen nesneler veya araçlar."
94
+ "QUANTITY: Ölçülebilir miktarlar ve birimler."
95
+ "TIME: Günün belirli saatleri."
96
+ "TITLE: Kişi unvanları."
97
+ "WORK_OF_ART: Sanat eserleri, kitaplar, müzik vb. Adlar, tarih ifadeleri, konumlar gibi belirgin bilgiler varlıktır."
98
+ ""
99
+ "Fiiller, sıfatlar, zarflar, soyut kavramlar gibi ifadeler varlık değildir. Çıktıyı aşağıdaki JSON formatında döndürün. "
100
+ ""
101
+ "Örnekler: "
102
+ "Girdi: "
103
+ "sentence: \"Üç yıl aradan sonra gerçekleştirilen ve Karadeniz, Ege ve Akdeniz’de düzenlenecek olan tatbikata ilişkin Yunanistan'ın Kathimerini gazetesi 'Türk-Yunan: Çetin donanma dengesinin gücü' başlığını kullandı.\""
104
+ "Çıktı: "
105
+ "Üç yıl,DATE"
106
+ "Karadeniz,LOC"
107
+ "Ege,LOC"
108
+ "Akdeniz,LOC"
109
+ "Yunanistan,GPE"
110
+ "Kathimerini,ORG"
111
+ "Türk,NORP"
112
+ ""
113
+ "Girdi:"
114
+ "sentence: \"Evlendikten sonra oyunculuğu bırakan Makal, geçen yıl eşi ve oğluyla beraber İstanbul’dan Göcek’e taşınmıştı."
115
+ "Çıktı: "
116
+ "Makal,PERSON"
117
+ "İstanbul,GPE"
118
+ "Göcek,GPE"
119
+ ""
120
+ "Girdi:"
121
+ "sentence: \"Yeşil-kırmızılılardan 2016’da ayrılıp 3 sezonluk aradan sonra 2019’da geri dönen Sarıca, takımına 2021 yılında Şampiyonlar Ligi’nde, 2023’te de Süper Lig’de iki final oynattı."
122
+ "Çıktı:"
123
+ "2016’da,DATE"
124
+ "3,CARDINAL"
125
+ "2019’da,DATE"
126
+ "Sarıca,PERSON"
127
+ "2021,DATE"
128
+ "Şampiyonlar Ligi’nde,EVENT"
129
+ "2023’te,DATE"
130
+ "Süper Lig’de,EVENT"
131
+ "iki,CARDINAL"
132
+ ""
133
+ "Verilen cümlelerdeki her varlığı csv formatında yukarıdaki örneklere benzer şekilde belirleyin. Çıktıdaki her satırı aşağıdaki gibi oluşturun: "
134
+ "<Varlık metni>,<Varlık etiketi>"),
135
+ prompt = f"{instruction}\n\nSoru:\n{row["question"]}\n"
136
+ message = prompt
137
+
138
+ # Get/format answer of the model
139
+ model_answer = self.generate_response_oeqa_multi_token(message)
140
+ responses.append(model_answer)
141
+ model_answer_cleaned = model_answer
142
+
143
+ # Print answers
144
+ print(f"Correct Answer: {answer}")
145
+ print(f"Model Answer: {model_answer}")
146
+ print(f"Model Answer Cleaned: {model_answer_cleaned}")
147
+ print(f"Result: {answer == model_answer_cleaned}")
148
+
149
+ # Check if correct based on metric
150
+ if answer == model_answer_cleaned:
151
+ true += 1
152
+ difficulty_results[category]['correct'] += 1
153
+
154
+ difficulty_results[category]['total'] += 1
155
+
156
+ # Print results categorized by difficulty
157
+ for category, stats in difficulty_results.items():
158
+ calculatedAccuracy = stats['correct'] / stats['total'] if stats['total'] > 0 else 0
159
+ print(f"{category.capitalize()} Accuracy: {calculatedAccuracy:.2%} ({stats['correct']}/{stats['total']})")
160
+
161
+ print("Results:", responses)
162
+ print("Overall Accuracy:", true / total_count)
163
+ acc = accuracy(true, total_count)
164
+ acc_stderr = accuracy_standard_error(acc, total_count)
165
+ return {"acc": acc, "acc_stderr": acc_stderr}
166
+
src/deepeval/pos.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.deepeval.base_task import BaseTask
2
+ from collections import defaultdict
3
+ from src.deepeval.utils import accuracy, accuracy_standard_error
4
+ from typing import Any
5
+ import re
6
+
7
+ class POSTask(BaseTask):
8
+ def __init__(self, model_name):
9
+ super().__init__("metunlp/tr_pos", model_name=model_name)
10
+
11
+ def load_dataset_from_hf(self):
12
+ dataset = super().load_dataset_from_hf()
13
+ return dataset.select(range(min(1, len(dataset))))
14
+
15
+ def generate_response_oeqa_multi_token(self, msg,max_new_tokens: int = 128):
16
+ """
17
+ Handles multiple-choice questions where answers might have multiple tokens.
18
+ """
19
+ # Ensure tokenizer has proper special tokens set
20
+ if self.tokenizer.pad_token is None:
21
+ self.tokenizer.pad_token = self.tokenizer.eos_token
22
+
23
+ if self.model.config.pad_token_id is None:
24
+ self.model.config.pad_token_id = self.tokenizer.pad_token_id
25
+
26
+ chat = [
27
+ {"role": "user", "content": "You are a question-answering chatbot."},
28
+ {"role": "assistant", "content": "I am ready to answer your questions. Feel free to ask anything.\n"},
29
+ {"role": "user", "content": f"{msg}"},
30
+ ]
31
+ formatted_chat = self.tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)
32
+ print(formatted_chat)
33
+
34
+ inputs = self.tokenizer(formatted_chat, return_tensors="pt", padding=True, truncation=True)
35
+ input_ids = inputs.input_ids.to(self.model.device)
36
+ attention_mask = inputs.attention_mask.to(self.model.device)
37
+ prompt = ("Aşağıdaki Named Entity Recognition (NER) için etiketlenmesi gereken cümleler vardır. "
38
+ "Cümlelerdeki varlıkları belirleyin ve şu kategorilere ayırın: CARDINAL, DATE, EVENT, FAC, GPE, LANGUAGE, LAW, LOC, MONEY, NORP, ORDINAL, ORG, PER, PERCENT, PERSON, PRODUCT, QUANTITY, TIME, TITLE, WORK_OF_ART. "
39
+ ""
40
+ "Varlıklar, anlamlı bilgiler içeren terimlerdir ve aşağıdaki şekilde tanımlanır: "
41
+ "CARDINAL: Nicelik veya sıralama belirtmeyen sayısal ifadeler."
42
+ "DATE: Belirli bir tarih veya zaman ifadeleri."
43
+ "EVENT: Adlandırılmış olaylar veya durumlar."
44
+ "FAC: Binalar veya önemli yerler gibi tesisler."
45
+ "GPE: Ülke, şehir veya eyalet gibi coğrafi-politik varlıklar."
46
+ "LANGUAGE: Adlandırılmış diller."
47
+ "LAW: Yasal belgeler, düzenlemeler veya kanunlar."
48
+ "LOC: Coğrafi veya fiziksel konumlar (GPE dışındaki)."
49
+ "MONEY: Parasal değerler."
50
+ "NORP: Milletler, dini veya siyasi gruplar."
51
+ "ORDINAL: Sıralama veya dereceler."
52
+ "ORG: Organizasyonlar veya kurumlar."
53
+ "PER: Kişisel unvanlar veya sıfatlar."
54
+ "PERSON: Bireylerin isimleri."
55
+ "PRODUCT: Üretilen nesneler veya araçlar."
56
+ "QUANTITY: Ölçülebilir miktarlar ve birimler."
57
+ "TIME: Günün belirli saatleri."
58
+ "TITLE: Kişi unvanları."
59
+ "WORK_OF_ART: Sanat eserleri, kitaplar, müzik vb. Adlar, tarih ifadeleri, konumlar gibi belirgin bilgiler varlıktır."
60
+ ""
61
+ "Fiiller, sıfatlar, zarflar, soyut kavramlar gibi ifadeler varlık değildir. Çıktıyı aşağıdaki JSON formatında döndürün. "
62
+ ""
63
+ "Örnekler: "
64
+ "Girdi: "
65
+ "\"sentence\": \"Üç yıl aradan sonra gerçekleştirilen ve Karadeniz, Ege ve Akdeniz’de düzenlenecek olan tatbikata ilişkin Yunanistan'ın Kathimerini gazetesi 'Türk-Yunan: Çetin donanma dengesinin gücü' başlığını kullandı.\""
66
+ "Çıktı: "
67
+ "Üç yıl: DATE\" }, { \"text\": \"Karadeniz\", \"label\": \"LOC\" }, { \"text\": \"Ege\", \"label\": \"LOC\" }, { \"text\": \"Akdeniz\", \"label\": \"LOC\" }, { \"text\": \"Yunanistan\", \"label\": \"GPE\" }, { \"text\": \"Kathimerini\", \"label\": \"ORG\" }, { \"text\": \"Türk\", \"label\": \"NORP\" }]} Girdi: {\"sentence\": \"Evlendikten sonra oyunculuğu bırakan Makal, geçen yıl eşi ve oğluyla beraber İstanbul’dan Göcek’e taşınmıştı.\"} Çıktı: {\"entities\": [{ \"text\": \"Makal\", \"label\": \"PERSON\" }, { \"text\": \"İstanbul\", \"label\": \"GPE\" }, { \"text\": \"Göcek\", \"label\": \"GPE\" }]} Girdi: {\"sentence\": \"Yeşil-kırmızılılardan 2016’da ayrılıp 3 sezonluk aradan sonra 2019’da geri dönen Sarıca, takımına 2021 yılında Şampiyonlar Ligi’nde, 2023’te de Süper Lig’de iki final oynattı.\"} Çıktı: {\"entities\": [{ \"text\": \"2016’da\", \"label\": \"DATE\" }, { \"text\": \"3\", \"label\": \"CARDINAL\" }, { \"text\": \"2019’da\", \"label\": \"DATE\" }, { \"text\": \"Sarıca\", \"label\": \"PERSON\" }, { \"text\": \"2021\", \"label\": \"DATE\" }, { \"text\": \"Şampiyonlar Ligi’nde\", \"label\": \"EVENT\" }, { \"text\": \"2023’te\", \"label\": \"DATE\" }, { \"text\": \"Süper Lig’de\", \"label\": \"EVENT\" }, { \"text\": \"iki\", \"label\": \"CARDINAL\" }]}. Verilen cümlelerdeki varlıkları JSON formatında yukarıdaki örneklere benzer şekilde belirleyin. Çıktıyı aşağıdaki gibi oluşturun: Girdi Formatı: {\"sentence\": \"<CÜMLE>\"} Çıktı Formatı: {\"entities\": [{ \"text\": \"<Varlık metni>\", \"label\": \"<Varlık etiketi>\" }]}"),
68
+
69
+ # Generate response with proper token limits
70
+ output = self.model.generate(
71
+ input_ids,
72
+ do_sample=True,
73
+ attention_mask=attention_mask,
74
+ eos_token_id=self.tokenizer.eos_token_id,
75
+ pad_token_id=self.tokenizer.pad_token_id,
76
+ temperature=0.4,
77
+ max_new_tokens=max_new_tokens,
78
+ )
79
+
80
+ generated_ids = output[0] # The generated sequence including the prompt
81
+ generated_tokens = generated_ids[len(input_ids[0]):] # Exclude the input_ids part
82
+ generated_text = self.tokenizer.decode(generated_tokens, skip_special_tokens=True)
83
+
84
+ return generated_text
85
+
86
+
87
+ def evaluate(self) -> dict[str, Any]:
88
+ responses = []
89
+ difficulty_results = defaultdict(lambda: {'correct': 0, 'total': 0})
90
+ total_count = 0
91
+ true = 0
92
+
93
+ for row in self.dataset:
94
+ total_count += 1
95
+
96
+ # Get values from row
97
+ category = str(row["difficulty"])
98
+ answer = row["final_answer"]
99
+
100
+ # Prints for debugging
101
+ print(f"Answer: {answer}")
102
+ print("Type of answer:", type(answer))
103
+
104
+ # Construct the prompt/message
105
+ instruction = f"""Aşağıdaki matematik problemini verilen nihai cevap formatına uygun olacak şekilde çözün. Tüm adımları gösterdikten sonra, nihai cevabınızı sadece bir kez ve aşağıdaki kurallara uygun şekilde kutu (\\boxed{{}}) içinde verin.
106
+
107
+ Nihai Cevap için Uyulması Gereken Format Kuralları:
108
+
109
+ 1. Kesirler her zaman en sade hallerinde verilmeli.
110
+ - Matris içi kesirler: x/y biçiminde.
111
+ - Diğer tüm kesirler: \\frac{{x}}{{y}} biçiminde.
112
+ 2. Çarpma işareti (*) kullanılmamalı. Örnek: 2x yazın, 2**x* değil.
113
+ 3. Birden çok değişken varsa alfabetik sıraya uyulmalı ve (x, y, z...), polinomları azalan derece sırasına göre yazılmalı.
114
+ 4. Her zaman aynı gösterim biçimi kullanılmalı. Ondalık yerine kesir kullanılmalı (ör. 0.5 yerine \\frac{{1}}{{2}} ).
115
+ 5. Faktörize polinomlar daima aynı faktör sırası ile verilsin; her sorguda aynı cevabı verecek şekilde tutarlılığı koruyun.
116
+ 6. Nihai cevabı kutu dışında tekrar etmeyin, biçimi değiştirmeyin. Aynı soru tekrarlandığında aynı formatı ve cevabı verin.
117
+ 7. Nihai cevap, tek seferde \\boxed{{...}} içinde verilmeli. Örnek: Cevap x ise, "\\boxed{{x}}".
118
+
119
+
120
+ Görev: Problemi çözün, son adımda yukarıdaki kurallara tam uyan tek bir kutu içinde nihai cevabı verin.
121
+
122
+
123
+ Çözüm:
124
+
125
+
126
+ Nihai cevap:
127
+ """
128
+ prompt = f"{instruction}\n\nSoru:\n{row["question"]}\n"
129
+ message = prompt
130
+
131
+ # Get/format answer of the model
132
+ model_answer = self.generate_response_oeqa_multi_token(message)
133
+ responses.append(model_answer)
134
+ model_answer_cleaned = re.search(r"\\boxed{([^}]*)}", model_answer)
135
+
136
+ # Print answers
137
+ print(f"Correct Answer: {answer}")
138
+ print(f"Model Answer: {model_answer}")
139
+ print(f"Model Answer Cleaned: {model_answer_cleaned}")
140
+ print(f"Result: {answer == model_answer_cleaned}")
141
+
142
+ # Check if correct based on metric
143
+ if answer == model_answer_cleaned:
144
+ true += 1
145
+ difficulty_results[category]['correct'] += 1
146
+
147
+ difficulty_results[category]['total'] += 1
148
+
149
+ # Print results categorized by difficulty
150
+ for category, stats in difficulty_results.items():
151
+ calculatedAccuracy = stats['correct'] / stats['total'] if stats['total'] > 0 else 0
152
+ print(f"{category.capitalize()} Accuracy: {calculatedAccuracy:.2%} ({stats['correct']}/{stats['total']})")
153
+
154
+ print("Results:", responses)
155
+ print("Overall Accuracy:", true / total_count)
156
+ acc = accuracy(true, total_count)
157
+ acc_stderr = accuracy_standard_error(acc, total_count)
158
+ return {"acc": acc, "acc_stderr": acc_stderr}
159
+