DocUA commited on
Commit
9dcb638
·
1 Parent(s): aaec566

статистика по сигнатурам (не до кінця робочий)

Browse files
Files changed (3) hide show
  1. app.py +84 -41
  2. model_info.json +19 -0
  3. sdc_classifier.py +24 -13
app.py CHANGED
@@ -14,27 +14,56 @@ def initialize_environment():
14
  DEFAULT_SIGNATURES_FILE = "signatures.npz"
15
  CACHE_FILE = "embeddings_cache.db"
16
 
 
 
 
 
 
 
 
17
  # Перевіряємо наявність необхідних файлів
18
  if not os.path.exists(DEFAULT_CLASSES_FILE):
19
- print(f"ПОМИЛКА: Файл {DEFAULT_CLASSES_FILE} не знайдено!")
20
- return False
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- if not os.path.exists(DEFAULT_SIGNATURES_FILE):
23
- print("Signatures не знайдено. Створюємо нові...")
24
- try:
25
- classifier = SDCClassifier()
26
- classifier.load_classes(DEFAULT_CLASSES_FILE)
27
  result = classifier.initialize_signatures(
28
  force_rebuild=True,
29
  signatures_file=DEFAULT_SIGNATURES_FILE
30
  )
31
- print(f"Результат ініціалізації: {result}")
32
- return True
33
- except Exception as e:
34
- print(f"ПОМИЛКА при ініціалізації: {str(e)}")
35
- return False
36
 
37
- return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  def create_classifier(model_type, openai_model=None, local_model=None, device=None):
40
  """
@@ -61,40 +90,37 @@ def main():
61
  CACHE_FILE = "embeddings_cache.db"
62
 
63
  # Перевіряємо та ініціалізуємо середовище
64
- if not initialize_environment():
 
 
 
 
65
  print("Не вдалося ініціалізувати середовище")
66
  return
67
-
68
- # Ініціалізуємо класифікатор
69
- classifier = SDCClassifier()
70
-
71
- print("Завантаження початкових класів...")
72
- # Перевірка наявності кешу
73
- if not os.path.exists(CACHE_FILE):
74
- print("Кеш ембедінгів не знайдено. Створюємо новий...")
75
-
76
- # Завантажуємо класи і створюємо нові signatures
77
- try:
78
- classifier.load_initial_state(DEFAULT_CLASSES_FILE, DEFAULT_SIGNATURES_FILE)
79
- result = classifier.initialize_signatures(
80
- force_rebuild=True,
81
- signatures_file=DEFAULT_SIGNATURES_FILE
82
- )
83
- print(f"Результат ініціалізації: {result}")
84
- except Exception as e:
85
- print(f"ПОМИЛКА при ініціалізації: {str(e)}")
86
- return
87
- else:
88
- # Якщо кеш існує, просто завантажуємо початковий стан
89
- try:
90
- classifier.load_initial_state(DEFAULT_CLASSES_FILE, DEFAULT_SIGNATURES_FILE)
91
- except Exception as e:
92
- print(f"ПОМИЛКА при завантаженні початкового стану: {str(e)}")
93
- return
94
 
95
  with gr.Blocks() as demo:
96
  gr.Markdown("# SDC Classifier")
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  with gr.Tabs():
99
  # Вкладка 1: Single Text Testing
100
  with gr.TabItem("Тестування одного тексту"):
@@ -244,6 +270,23 @@ def main():
244
  signatures_file=DEFAULT_SIGNATURES_FILE if not force_rebuild else None
245
  )
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  return result, classifier.get_cache_stats()
248
  except Exception as e:
249
  return f"Помилка: {str(e)}", classifier.get_cache_stats()
 
14
  DEFAULT_SIGNATURES_FILE = "signatures.npz"
15
  CACHE_FILE = "embeddings_cache.db"
16
 
17
+ initial_info = {
18
+ "status": "initializing",
19
+ "model_info": {},
20
+ "classes_info": {},
21
+ "errors": []
22
+ }
23
+
24
  # Перевіряємо наявність необхідних файлів
25
  if not os.path.exists(DEFAULT_CLASSES_FILE):
26
+ initial_info["errors"].append(f"ПОМИЛКА: Файл {DEFAULT_CLASSES_FILE} не знайдено!")
27
+ initial_info["status"] = "error"
28
+ return initial_info
29
+
30
+ # Створюємо класифікатор та завантажуємо класи
31
+ try:
32
+ classifier = SDCClassifier()
33
+ classes = classifier.load_classes(DEFAULT_CLASSES_FILE)
34
+
35
+ # Збираємо інформацію про класи
36
+ initial_info["classes_info"] = {
37
+ "total_classes": len(classes),
38
+ "classes_list": list(classes.keys()),
39
+ "hints_per_class": {cls: len(hints) for cls, hints in classes.items()}
40
+ }
41
 
42
+ # Якщо signatures не існують, створюємо нові
43
+ if not os.path.exists(DEFAULT_SIGNATURES_FILE):
44
+ initial_info["status"] = "creating_signatures"
 
 
45
  result = classifier.initialize_signatures(
46
  force_rebuild=True,
47
  signatures_file=DEFAULT_SIGNATURES_FILE
48
  )
 
 
 
 
 
49
 
50
+ if isinstance(result, str) and "error" in result.lower():
51
+ initial_info["errors"].append(result)
52
+ initial_info["status"] = "error"
53
+ return initial_info
54
+
55
+ # Завантажуємо інформацію про модель
56
+ classifier.save_model_info("model_info.json")
57
+ with open("model_info.json", "r") as f:
58
+ initial_info["model_info"] = json.load(f)
59
+
60
+ initial_info["status"] = "success"
61
+ return initial_info, classifier
62
+
63
+ except Exception as e:
64
+ initial_info["errors"].append(f"ПОМИЛКА при ініціалізації: {str(e)}")
65
+ initial_info["status"] = "error"
66
+ return initial_info, None
67
 
68
  def create_classifier(model_type, openai_model=None, local_model=None, device=None):
69
  """
 
90
  CACHE_FILE = "embeddings_cache.db"
91
 
92
  # Перевіряємо та ініціалізуємо середовище
93
+ init_result = initialize_environment()
94
+ if isinstance(init_result, tuple):
95
+ initial_info, classifier = init_result
96
+ else:
97
+ initial_info = init_result
98
  print("Не вдалося ініціалізувати середовище")
99
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  with gr.Blocks() as demo:
102
  gr.Markdown("# SDC Classifier")
103
 
104
+ # Додаємо інформаційний блок про модель та класи
105
+ with gr.Accordion("Інформація про систему", open=True):
106
+ system_info = gr.JSON(
107
+ value=initial_info,
108
+ label="Статус системи"
109
+ )
110
+
111
+ if initial_info["status"] == "success":
112
+ gr.Markdown(f"""
113
+ ### Поточна конфігурація:
114
+ - Модель: {initial_info['model_info'].get('using_local', 'OpenAI')}
115
+ - Кількість класів: {initial_info['classes_info']['total_classes']}
116
+ - Класи: {', '.join(initial_info['classes_info']['classes_list'])}
117
+ """)
118
+ else:
119
+ gr.Markdown(f"""
120
+ ### Помилки ініціалізації:
121
+ {chr(10).join('- ' + err for err in initial_info['errors'])}
122
+ """)
123
+
124
  with gr.Tabs():
125
  # Вкладка 1: Single Text Testing
126
  with gr.TabItem("Тестування одного тексту"):
 
270
  signatures_file=DEFAULT_SIGNATURES_FILE if not force_rebuild else None
271
  )
272
 
273
+ # Оновлюємо інформацію про систему
274
+ classifier.save_model_info("model_info.json")
275
+ with open("model_info.json", "r") as f:
276
+ model_info = json.load(f)
277
+
278
+ system_info.update(value={
279
+ "status": "success",
280
+ "model_info": model_info,
281
+ "classes_info": {
282
+ "total_classes": len(classifier.classes_json),
283
+ "classes_list": list(classifier.classes_json.keys()),
284
+ "hints_per_class": {cls: len(hints)
285
+ for cls, hints in classifier.classes_json.items()}
286
+ },
287
+ "errors": []
288
+ })
289
+
290
  return result, classifier.get_cache_stats()
291
  except Exception as e:
292
  return f"Помилка: {str(e)}", classifier.get_cache_stats()
model_info.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "using_local": true,
3
+ "classes_count": 15,
4
+ "signatures_count": 15,
5
+ "cache_stats": {
6
+ "total_entries": 3647,
7
+ "cache_size_mb": 31.64,
8
+ "hits": 545,
9
+ "misses": 0,
10
+ "hit_rate_percent": 100.0
11
+ },
12
+ "local_model": {
13
+ "model_name": "cambridgeltl/SapBERT-from-PubMedBERT-fulltext",
14
+ "device": "cuda",
15
+ "embedding_size": 768,
16
+ "max_length": 512,
17
+ "batch_size": 32
18
+ }
19
+ }
sdc_classifier.py CHANGED
@@ -202,9 +202,9 @@ class SDCClassifier:
202
  return np.array(emb_list, dtype=np.float32)
203
 
204
  def initialize_signatures(self,
205
- model_name: str = None,
206
- signatures_file: str = "signatures.npz",
207
- force_rebuild: bool = False) -> str:
208
  """
209
  Ініціалізує signatures: завантажує існуючі або створює нові
210
 
@@ -212,9 +212,6 @@ class SDCClassifier:
212
  model_name: назва моделі для ембедінгів
213
  signatures_file: шлях до файлу для збереження (None - не зберігати)
214
  force_rebuild: примусово перебудувати signatures
215
-
216
- Returns:
217
- str: повідомлення про результат
218
  """
219
  if not self.classes_json:
220
  return "Помилка: Не знайдено жодного класу в classes.json"
@@ -244,8 +241,16 @@ class SDCClassifier:
244
 
245
  print(f"Обробка класу {cls_name} ({idx}/{total_classes})...")
246
  try:
 
247
  arr = self.embed_hints(hints, model_name=model_name)
248
- self.class_signatures[cls_name] = arr.mean(axis=0)
 
 
 
 
 
 
 
249
  print(f"Успішно створено signature для {cls_name}")
250
  except Exception as e:
251
  print(f"Помилка при створенні signature для {cls_name}: {str(e)}")
@@ -265,7 +270,7 @@ class SDCClassifier:
265
  return f"Створено нові signatures для {len(self.class_signatures)} класів"
266
  except Exception as e:
267
  return f"Помилка при створенні signatures: {str(e)}"
268
-
269
  def load_data(self, csv_path: str = "messages.csv", emb_path: str = "embeddings.npy") -> str:
270
  """
271
  Завантаження даних з CSV та NPY файлів
@@ -322,25 +327,31 @@ class SDCClassifier:
322
  if self.class_signatures is None:
323
  return {"error": "Спочатку збудуйте signatures!"}
324
 
325
- emb = self.get_embedding(text)
 
326
 
327
- if self.embeddings_mean is not None and self.embeddings_std is not None:
 
328
  emb = (emb - self.embeddings_mean) / self.embeddings_std
329
 
 
330
  predictions = self.predict_classes(emb, threshold)
331
 
332
  if not predictions:
333
  return {"message": text, "result": "Жодного класу не знайдено"}
334
 
 
335
  formatted_results = []
336
  for cls, score in predictions.items():
337
- formatted_results.append(f"{cls}: {score:.2%}")
 
 
338
 
339
  return {
340
  "message": text,
341
- "result": "\n".join(formatted_results)
342
  }
343
-
344
  def classify_rows(self, filter_substring: str = "", threshold: float = 0.3) -> pd.DataFrame:
345
  """
346
  Класифікація всіх або відфільтрованих рядків
 
202
  return np.array(emb_list, dtype=np.float32)
203
 
204
  def initialize_signatures(self,
205
+ model_name: str = None,
206
+ signatures_file: str = "signatures.npz",
207
+ force_rebuild: bool = False) -> str:
208
  """
209
  Ініціалізує signatures: завантажує існуючі або створює нові
210
 
 
212
  model_name: назва моделі для ембедінгів
213
  signatures_file: шлях до файлу для збереження (None - не зберігати)
214
  force_rebuild: примусово перебудувати signatures
 
 
 
215
  """
216
  if not self.classes_json:
217
  return "Помилка: Не знайдено жодного класу в classes.json"
 
241
 
242
  print(f"Обробка класу {cls_name} ({idx}/{total_classes})...")
243
  try:
244
+ # Отримуємо ембедінги для всіх хінтів класу
245
  arr = self.embed_hints(hints, model_name=model_name)
246
+
247
+ # Нормалізуємо кожен ембедінг
248
+ norms = np.linalg.norm(arr, axis=1, keepdims=True)
249
+ arr = arr / norms
250
+
251
+ # Обчислюємо середній нормалізований ембедінг
252
+ self.class_signatures[cls_name] = np.mean(arr, axis=0)
253
+
254
  print(f"Успішно створено signature для {cls_name}")
255
  except Exception as e:
256
  print(f"Помилка при створенні signature для {cls_name}: {str(e)}")
 
270
  return f"Створено нові signatures для {len(self.class_signatures)} класів"
271
  except Exception as e:
272
  return f"Помилка при створенні signatures: {str(e)}"
273
+
274
  def load_data(self, csv_path: str = "messages.csv", emb_path: str = "embeddings.npy") -> str:
275
  """
276
  Завантаження даних з CSV та NPY файлів
 
327
  if self.class_signatures is None:
328
  return {"error": "Спочатку збудуйте signatures!"}
329
 
330
+ # Отримуємо ембедінг
331
+ emb = np.array(self.get_embedding(text))
332
 
333
+ # Нормалізуємо відносно даних навчання, якщо вони доступні
334
+ if self.embeddings_mean is not None and self.embeddings_std is not None and not self.using_local:
335
  emb = (emb - self.embeddings_mean) / self.embeddings_std
336
 
337
+ # Отримуємо передбачення
338
  predictions = self.predict_classes(emb, threshold)
339
 
340
  if not predictions:
341
  return {"message": text, "result": "Жодного класу не знайдено"}
342
 
343
+ # Форматуємо результати
344
  formatted_results = []
345
  for cls, score in predictions.items():
346
+ # Конвертуємо score в відсотки, обмежуємо до 100%
347
+ score_percent = min(abs(float(score)) * 100, 100)
348
+ formatted_results.append(f"{cls}: {score_percent:.2f}%")
349
 
350
  return {
351
  "message": text,
352
+ "result": " ".join(formatted_results)
353
  }
354
+
355
  def classify_rows(self, filter_substring: str = "", threshold: float = 0.3) -> pd.DataFrame:
356
  """
357
  Класифікація всіх або відфільтрованих рядків