1262 lines
50 KiB
Python
1262 lines
50 KiB
Python
import numpy as np
|
|
import pandas as pd
|
|
import os
|
|
import sys
|
|
import time
|
|
from datetime import datetime
|
|
import json
|
|
import gc
|
|
import signal
|
|
import multiprocessing
|
|
from multiprocessing import Pool, cpu_count
|
|
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
|
|
import psutil
|
|
|
|
# Import bibliotek kwantowych
|
|
from qiskit import Aer
|
|
from qiskit.circuit.library import ZZFeatureMap, PauliFeatureMap, EfficientSU2
|
|
from qiskit_machine_learning.kernels import QuantumKernel
|
|
from qiskit_machine_learning.algorithms import QSVC
|
|
import dimod
|
|
|
|
# Dodanie zalecanego zamiennika dla ZZFeatureMap
|
|
from qiskit.circuit import QuantumCircuit, Parameter
|
|
from qiskit.circuit.library.data_preparation import ZFeatureMap
|
|
|
|
# Dodanie bibliotek do kodowania amplitudowego
|
|
from qiskit.circuit import QuantumCircuit
|
|
from qiskit.extensions import Initialize
|
|
import scipy.linalg as la
|
|
|
|
# Dodanie biblioteki UMAP
|
|
import umap
|
|
|
|
# Maksymalny czas trwania eksperymentu
|
|
MAX_EXECUTION_TIME = 24 * 60 * 60 * 7 * 3
|
|
|
|
def timeout_handler(signum, frame):
|
|
print("\n\n======= PRZEKROCZONO MAKSYMALNY CZAS WYKONANIA =======")
|
|
print(f"Eksperyment został przerwany po {MAX_EXECUTION_TIME/3600:.1f} godzinach.")
|
|
sys.exit(1)
|
|
|
|
# Ustawienie obsługi sygnału
|
|
signal.signal(signal.SIGALRM, timeout_handler)
|
|
signal.alarm(MAX_EXECUTION_TIME)
|
|
|
|
# ----------------- CZĘŚĆ 0: PARAMETRY KONFIGURACYJNE OPTYMALIZOWANE DLA VAST.AI -----------------
|
|
|
|
# Parametry danych
|
|
DATA_FILES = [
|
|
'dane/TCGA_GBM_LGG_Mutations_clean.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_1percent_added.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_5percent_added.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_10percent_added.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_15percent_added.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_20percent_added.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_1percent_substituted.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_5percent_substituted.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_10percent_substituted.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_15percent_substituted.csv',
|
|
'dane/TCGA_GBM_LGG_Mutations_noise_20percent_substituted.csv'
|
|
]
|
|
TEST_SIZE = 0.3
|
|
RANDOM_STATE = 42
|
|
|
|
# Parametry redukcji wymiarowości
|
|
USE_PCA = True
|
|
USE_TSNE = False
|
|
USE_UMAP = False
|
|
PCA_COMPONENTS = 12
|
|
TSNE_COMPONENTS = 3
|
|
TSNE_PERPLEXITY = 100
|
|
TSNE_LEARNING_RATE = 50
|
|
TSNE_MAX_ITER = 1000
|
|
UMAP_COMPONENTS = 14
|
|
UMAP_NEIGHBORS = 15
|
|
UMAP_MIN_DIST = 0.8
|
|
UMAP_METRIC = 'euclidean'
|
|
EVALUATE_SILHOUETTE = False
|
|
OPTIMAL_SILHOUETTE_SCORE = 0.1964
|
|
|
|
# Wybór eksperymentów do przeprowadzenia
|
|
RUN_CLASSIC_SVM = False
|
|
RUN_QUANTUM_SVM = True
|
|
RUN_HYBRID_APPROACH = False
|
|
|
|
# Parametry klasycznego SVM - OPTYMALIZOWANE DLA WIELU RDZENI
|
|
SVM_PARAM_GRID = {
|
|
'C': [0.1, 1, 10, 100],
|
|
'gamma': ['scale', 'auto', 0.1, 0.01],
|
|
'kernel': ['linear', 'rbf', 'poly']
|
|
}
|
|
SVM_CV = 5
|
|
|
|
# Parametry kwantowego SVM
|
|
BACKEND_NAME = 'qasm_simulator'
|
|
C_VALUES = [0.1, 1.0, 10.0]
|
|
QSVM_CV = 10
|
|
|
|
# Parametry wyżarzania kwantowego
|
|
NUM_READS = 100
|
|
QUBO_PENALTY = 10.0
|
|
|
|
# Parametry analizy cech
|
|
IMPORTANCE_THRESHOLD = 0.01
|
|
|
|
# Parametry wyjściowe
|
|
OUTPUT_DIR = f'wyniki/2025-08-30-2-{QSVM_CV}-fold-zFeature'
|
|
|
|
# Parametry IBM Quantum Cloud
|
|
USE_IBM_QUANTUM = False
|
|
IBM_BACKEND = 'qasm_simulator'
|
|
IBM_REAL_BACKEND = 'qasm_simulator'
|
|
IBM_TOKEN = None
|
|
IBM_INSTANCE = None
|
|
IBM_MAX_SHOTS = 1024
|
|
IBM_OPTIMIZATION_LEVEL = 1
|
|
IBM_RESILIENCE_LEVEL = 1
|
|
|
|
# BEZPIECZNE OPTYMALIZACJE DLA VAST.AI - Z OGRANICZENIAMI
|
|
def get_optimal_cpu_config():
|
|
total_cores = cpu_count()
|
|
available_memory = psutil.virtual_memory().total / (1024**3) # GB
|
|
|
|
print(f"=== KONFIGURACJA SYSTEMU ===")
|
|
print(f"Liczba rdzeni CPU: {total_cores}")
|
|
print(f"Dostępna pamięć RAM: {available_memory:.1f} GB")
|
|
|
|
# BEZPIECZNA konfiguracja - maksymalnie 70% rdzeni
|
|
safe_cores = int(total_cores * 0.7)
|
|
|
|
if total_cores >= 200:
|
|
# BEZPIECZNA konfiguracja dla 255 rdzeni
|
|
n_jobs_kernel = min(30, safe_cores // 4) # 15% rdzeni dla obliczeń jądra
|
|
n_jobs_svm = min(20, safe_cores // 6) # 10% rdzeni dla SVM
|
|
n_jobs_parallel = min(15, safe_cores // 8) # 7% rdzeni dla równoległości
|
|
print(f"Konfiguracja: BEZPIECZNA (200+ rdzeni) - OGRANICZONE WYKORZYSTANIE")
|
|
print(f"Bezpieczne wykorzystanie: {n_jobs_kernel + n_jobs_svm + n_jobs_parallel}/{total_cores} rdzeni ({((n_jobs_kernel + n_jobs_svm + n_jobs_parallel)/total_cores)*100:.1f}%)")
|
|
elif total_cores >= 100:
|
|
# Bezpieczna konfiguracja (100-199 rdzeni)
|
|
n_jobs_kernel = min(25, safe_cores // 3)
|
|
n_jobs_svm = min(15, safe_cores // 5)
|
|
n_jobs_parallel = min(10, safe_cores // 7)
|
|
print(f"Konfiguracja: BEZPIECZNA (100+ rdzeni)")
|
|
elif total_cores >= 40:
|
|
# Bezpieczna konfiguracja (40-99 rdzeni)
|
|
n_jobs_kernel = min(15, safe_cores // 3)
|
|
n_jobs_svm = min(8, safe_cores // 5)
|
|
n_jobs_parallel = min(6, safe_cores // 7)
|
|
print(f"Konfiguracja: BEZPIECZNA (40+ rdzeni)")
|
|
elif total_cores >= 32:
|
|
# Bezpieczna konfiguracja (32-39 rdzeni)
|
|
n_jobs_kernel = min(12, safe_cores // 3)
|
|
n_jobs_svm = min(6, safe_cores // 5)
|
|
n_jobs_parallel = min(4, safe_cores // 8)
|
|
print(f"Konfiguracja: BEZPIECZNA (32+ rdzeni)")
|
|
elif total_cores >= 16:
|
|
# Bezpieczna konfiguracja (16-31 rdzeni)
|
|
n_jobs_kernel = min(8, safe_cores // 3)
|
|
n_jobs_svm = min(4, safe_cores // 4)
|
|
n_jobs_parallel = min(3, safe_cores // 5)
|
|
print(f"Konfiguracja: BEZPIECZNA (16+ rdzeni)")
|
|
else:
|
|
# Bezpieczna konfiguracja (<16 rdzeni)
|
|
n_jobs_kernel = min(4, safe_cores // 3)
|
|
n_jobs_svm = min(2, safe_cores // 4)
|
|
n_jobs_parallel = min(2, safe_cores // 4)
|
|
print(f"Konfiguracja: BEZPIECZNA (<16 rdzeni)")
|
|
|
|
print(f"n_jobs_kernel: {n_jobs_kernel}")
|
|
print(f"n_jobs_svm: {n_jobs_svm}")
|
|
print(f"n_jobs_parallel: {n_jobs_parallel}")
|
|
print(f"Bezpieczne wykorzystanie: {n_jobs_kernel + n_jobs_svm + n_jobs_parallel}/{total_cores} rdzeni")
|
|
|
|
return {
|
|
'n_jobs_kernel': n_jobs_kernel,
|
|
'n_jobs_svm': n_jobs_svm,
|
|
'n_jobs_parallel': n_jobs_parallel,
|
|
'total_cores': total_cores,
|
|
'available_memory': available_memory
|
|
}
|
|
|
|
# Pobierz optymalną konfigurację
|
|
CPU_CONFIG = get_optimal_cpu_config()
|
|
|
|
# BEZPIECZNA OPTYMALIZACJA PAMIĘCI DLA VAST.AI
|
|
def optimize_memory_for_large_system():
|
|
memory_gb = CPU_CONFIG['available_memory']
|
|
|
|
if memory_gb >= 200:
|
|
print(f"BEZPIECZNA OPTYMALIZACJA PAMIĘCI: {memory_gb:.1f} GB")
|
|
# Bezpieczne ustawienia dla dużych macierzy
|
|
import numpy as np
|
|
np.set_printoptions(precision=4, suppress=True)
|
|
|
|
# Częstsze garbage collection dla bezpieczeństwa
|
|
import gc
|
|
gc.set_threshold(700, 10, 10) # Częstsze GC
|
|
|
|
print("Pamięć zoptymalizowana bezpiecznie")
|
|
else:
|
|
print(f"Pamięć: {memory_gb:.1f} GB - standardowa optymalizacja")
|
|
|
|
# Dodaj monitoring pamięci
|
|
start_memory_monitoring()
|
|
|
|
# Dodaj funkcje timeout i monitoring
|
|
def timeout(seconds):
|
|
def decorator(func):
|
|
import functools
|
|
@functools.wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
def handler(signum, frame):
|
|
raise TimeoutError(f"Funkcja {func.__name__} przekroczyła limit {seconds}s")
|
|
|
|
signal.signal(signal.SIGALRM, handler)
|
|
signal.alarm(seconds)
|
|
try:
|
|
result = func(*args, **kwargs)
|
|
finally:
|
|
signal.alarm(0)
|
|
return result
|
|
return wrapper
|
|
return decorator
|
|
|
|
def start_memory_monitoring():
|
|
import threading
|
|
|
|
def monitor_resources():
|
|
while True:
|
|
try:
|
|
cpu_percent = psutil.cpu_percent(interval=1)
|
|
memory_percent = psutil.virtual_memory().percent
|
|
|
|
if cpu_percent > 95 or memory_percent > 90:
|
|
print(f"WYSOKIE WYKORZYSTANIE - CPU: {cpu_percent}%, RAM: {memory_percent}%")
|
|
|
|
time.sleep(30)
|
|
except Exception as e:
|
|
print(f"Błąd monitoringu: {e}")
|
|
time.sleep(60)
|
|
|
|
# Uruchom monitoring w tle
|
|
monitor_thread = threading.Thread(target=monitor_resources, daemon=True)
|
|
monitor_thread.start()
|
|
print("Monitoring zasobów uruchomiony")
|
|
|
|
# Uruchom optymalizację pamięci
|
|
optimize_memory_for_large_system()
|
|
|
|
# Upewnij się, że katalog wyjściowy istnieje
|
|
if not os.path.exists(OUTPUT_DIR):
|
|
os.makedirs(OUTPUT_DIR)
|
|
|
|
# Upewnij się, że katalog cache istnieje
|
|
CACHE_DIR = 'cache'
|
|
if not os.path.exists(CACHE_DIR):
|
|
os.makedirs(CACHE_DIR)
|
|
print(f"Utworzono katalog cache: {CACHE_DIR}")
|
|
|
|
# ZAAWANSOWANY SYSTEM LOGOWANIA
|
|
class Logger:
|
|
def __init__(self, filename):
|
|
self.terminal = sys.stdout
|
|
self.log = open(filename, 'w', encoding='utf-8')
|
|
self.start_time = time.time()
|
|
|
|
def write(self, message):
|
|
# Dodaj timestamp do każdego komunikatu
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
formatted_message = f"[{timestamp}] {message}"
|
|
|
|
self.terminal.write(formatted_message)
|
|
self.log.write(formatted_message)
|
|
self.log.flush()
|
|
|
|
def flush(self):
|
|
self.terminal.flush()
|
|
self.log.flush()
|
|
|
|
def close(self):
|
|
self.log.close()
|
|
|
|
# FUNKCJA DO LOGOWANIA Z TIMESTAMPEM
|
|
def log_message(message, level="INFO"):
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
formatted_message = f"[{timestamp}] [{level}] {message}\n"
|
|
|
|
# Wyświetl w konsoli
|
|
sys.stdout.write(formatted_message)
|
|
sys.stdout.flush()
|
|
|
|
# Zapisz do pliku log
|
|
try:
|
|
with open('qsvm_experiments.log', 'a', encoding='utf-8') as f:
|
|
f.write(formatted_message)
|
|
f.flush()
|
|
except Exception as e:
|
|
print(f"Błąd zapisu do log: {e}")
|
|
|
|
# FUNKCJA DO LOGOWANIA POSTĘPU
|
|
def log_progress(current, total, description="Postęp"):
|
|
percentage = (current / total) * 100
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
message = f"[{timestamp}] [PROGRESS] {description}: {current}/{total} ({percentage:.1f}%)"
|
|
|
|
sys.stdout.write(f"\r{message}")
|
|
sys.stdout.flush()
|
|
|
|
# Zapisz do pliku log
|
|
try:
|
|
with open('qsvm_experiments.log', 'a', encoding='utf-8') as f:
|
|
f.write(message + "\n")
|
|
f.flush()
|
|
except Exception as e:
|
|
print(f"Błąd zapisu do log: {e}")
|
|
|
|
# FUNKCJA DO LOGOWANIA BŁĘDÓW
|
|
def log_error(error_message, exception=None):
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
if exception:
|
|
error_details = f"[{timestamp}] [ERROR] {error_message}\nException: {str(exception)}\nTraceback: {traceback.format_exc()}"
|
|
else:
|
|
error_details = f"[{timestamp}] [ERROR] {error_message}"
|
|
|
|
# Wyświetl w konsoli
|
|
sys.stderr.write(error_details + "\n")
|
|
sys.stderr.flush()
|
|
|
|
# Zapisz do pliku log
|
|
try:
|
|
with open('qsvm_experiments.log', 'a', encoding='utf-8') as f:
|
|
f.write(error_details + "\n")
|
|
f.flush()
|
|
except Exception as e:
|
|
print(f"Błąd zapisu do log: {e}")
|
|
|
|
# FUNKCJA DO LOGOWANIA WYNIKÓW
|
|
def log_results(results_dict, experiment_name):
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
message = f"[{timestamp}] [RESULTS] Eksperyment: {experiment_name}\n"
|
|
|
|
for key, value in results_dict.items():
|
|
if isinstance(value, (int, float)):
|
|
message += f" {key}: {value}\n"
|
|
elif isinstance(value, dict):
|
|
message += f" {key}: {json.dumps(value, indent=2)}\n"
|
|
else:
|
|
message += f" {key}: {str(value)}\n"
|
|
|
|
# Wyświetl w konsoli
|
|
sys.stdout.write(message)
|
|
sys.stdout.flush()
|
|
|
|
# Zapisz do pliku log
|
|
try:
|
|
with open('qsvm_experiments.log', 'a', encoding='utf-8') as f:
|
|
f.write(message)
|
|
f.flush()
|
|
except Exception as e:
|
|
print(f"Błąd zapisu do log: {e}")
|
|
|
|
# IMPORT TRACEBACK DLA BŁĘDÓW
|
|
import traceback
|
|
|
|
# Funkcja do zapisywania szczegółowych metryk
|
|
def save_metrics(y_true, y_pred, model_name):
|
|
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score
|
|
|
|
accuracy = accuracy_score(y_true, y_pred)
|
|
precision = precision_score(y_true, y_pred, average='weighted', zero_division=0)
|
|
recall = recall_score(y_true, y_pred, average='weighted', zero_division=0)
|
|
f1 = f1_score(y_true, y_pred, average='weighted', zero_division=0)
|
|
|
|
try:
|
|
roc_auc = roc_auc_score(y_true, y_pred)
|
|
except:
|
|
roc_auc = "N/A"
|
|
|
|
print(f"\nSzczegółowe metryki dla modelu {model_name}:")
|
|
print(f"Accuracy: {accuracy:.4f}")
|
|
print(f"Precision: {precision:.4f}")
|
|
print(f"Recall: {recall:.4f}")
|
|
print(f"F1 Score: {f1:.4f}")
|
|
print(f"ROC AUC: {roc_auc}")
|
|
|
|
cm = confusion_matrix(y_true, y_pred)
|
|
print("\nMacierz pomyłek:")
|
|
print(cm)
|
|
|
|
return {
|
|
'accuracy': accuracy,
|
|
'precision': precision,
|
|
'recall': recall,
|
|
'f1': f1,
|
|
'roc_auc': roc_auc,
|
|
'confusion_matrix': cm.tolist()
|
|
}
|
|
|
|
# Funkcja do zapisywania wyników pośrednich
|
|
def save_results_cache(results_dict, cache_file):
|
|
cache_data = {
|
|
'timestamp': datetime.now().isoformat(),
|
|
'results': results_dict
|
|
}
|
|
with open(cache_file, 'w') as f:
|
|
json.dump(cache_data, f, indent=2)
|
|
log_message(f"Zapisano cache: {cache_file}", "CACHE")
|
|
|
|
# Funkcja do wczytywania wyników pośrednich
|
|
def load_results_cache(cache_file):
|
|
if os.path.exists(cache_file):
|
|
try:
|
|
with open(cache_file, 'r') as f:
|
|
cache_data = json.load(f)
|
|
log_message(f"Wczytano cache z: {cache_file}", "CACHE")
|
|
log_message(f"Timestamp: {cache_data.get('timestamp', 'N/A')}", "CACHE")
|
|
return cache_data.get('results', {})
|
|
except Exception as e:
|
|
log_error(f"Błąd wczytywania cache: {e}")
|
|
return {
|
|
'quantum_results': [],
|
|
'quantum_times': {},
|
|
'completed_feature_maps': [],
|
|
'hybrid_scores': {},
|
|
'hybrid_eval_times': {},
|
|
'classic_svm_results': {},
|
|
'data_preparation_cache': {},
|
|
'kernel_cache': {}
|
|
}
|
|
|
|
# FUNKCJE CACHE DLA JĄDRA KWANTOWEGO
|
|
def get_kernel_cache_key(X1_shape, X2_shape, feature_map_name, shots):
|
|
return f"kernel_{X1_shape[0]}x{X1_shape[1]}_{X2_shape[0]}x{X2_shape[1]}_{feature_map_name}_{shots}"
|
|
|
|
def save_kernel_cache(kernel_matrix, cache_key, cache_dir=CACHE_DIR):
|
|
if not os.path.exists(cache_dir):
|
|
os.makedirs(cache_dir)
|
|
|
|
cache_file = os.path.join(cache_dir, f"{cache_key}.npy")
|
|
np.save(cache_file, kernel_matrix)
|
|
log_message(f"Zapisano jądro do cache: {cache_file}", "CACHE")
|
|
|
|
def load_kernel_cache(cache_key, cache_dir=CACHE_DIR):
|
|
cache_file = os.path.join(cache_dir, f"{cache_key}.npy")
|
|
if os.path.exists(cache_file):
|
|
try:
|
|
kernel_matrix = np.load(cache_file)
|
|
log_message(f"Wczytano jądro z cache: {cache_file}", "CACHE")
|
|
return kernel_matrix
|
|
except Exception as e:
|
|
log_error(f"Błąd wczytywania jądra z cache: {e}")
|
|
return None
|
|
|
|
# FUNKCJE CACHE DLA PRZYGOTOWANIA DANYCH
|
|
def get_data_cache_key(data_file, test_size, random_state, pca_components):
|
|
#Generuje klucz cache dla przygotowanych danych
|
|
return f"data_{os.path.basename(data_file)}_{test_size}_{random_state}_{pca_components}"
|
|
|
|
def save_data_cache(data_dict, cache_key, cache_dir=CACHE_DIR):
|
|
if not os.path.exists(cache_dir):
|
|
os.makedirs(cache_dir)
|
|
|
|
cache_file = os.path.join(cache_dir, f"{cache_key}.npz")
|
|
np.savez_compressed(cache_file, **data_dict)
|
|
log_message(f"Zapisano dane do cache: {cache_file}", "CACHE")
|
|
|
|
def load_data_cache(cache_key, cache_dir=CACHE_DIR):
|
|
cache_file = os.path.join(cache_dir, f"{cache_key}.npz")
|
|
if os.path.exists(cache_file):
|
|
try:
|
|
data = np.load(cache_file)
|
|
data_dict = {key: data[key] for key in data.files}
|
|
log_message(f"Wczytano dane z cache: {cache_file}", "CACHE")
|
|
return data_dict
|
|
except Exception as e:
|
|
log_error(f"Błąd wczytywania danych z cache: {e}")
|
|
return None
|
|
|
|
# FUNKCJE CACHE DLA WYNIKÓW EKSPERYMENTÓW
|
|
def save_experiment_cache(experiment_name, results, cache_dir=CACHE_DIR):"
|
|
if not os.path.exists(cache_dir):
|
|
os.makedirs(cache_dir)
|
|
|
|
cache_file = os.path.join(cache_dir, f"experiment_{experiment_name}.json")
|
|
cache_data = {
|
|
'timestamp': datetime.now().isoformat(),
|
|
'experiment_name': experiment_name,
|
|
'results': results
|
|
}
|
|
with open(cache_file, 'w') as f:
|
|
json.dump(cache_data, f, indent=2)
|
|
log_message(f"Zapisano eksperyment do cache: {cache_file}", "CACHE")
|
|
|
|
def load_experiment_cache(experiment_name, cache_dir=CACHE_DIR):
|
|
cache_file = os.path.join(cache_dir, f"experiment_{experiment_name}.json")
|
|
if os.path.exists(cache_file):
|
|
try:
|
|
with open(cache_file, 'r') as f:
|
|
cache_data = json.load(f)
|
|
log_message(f"Wczytano eksperyment z cache: {cache_file}", "CACHE")
|
|
return cache_data.get('results', {})
|
|
except Exception as e:
|
|
log_error(f"Błąd wczytywania eksperymentu z cache: {e}")
|
|
return None
|
|
|
|
# FUNKCJA DO CZYSZCZENIA CACHE
|
|
def clear_cache(cache_dir=CACHE_DIR):
|
|
if os.path.exists(cache_dir):
|
|
import shutil
|
|
shutil.rmtree(cache_dir)
|
|
log_message(f"Wyczyszczono cache: {cache_dir}", "CACHE")
|
|
|
|
# FUNKCJA DO SPRAWDZANIA STATUSU CACHE
|
|
def check_cache_status(cache_dir=CACHE_DIR):
|
|
if not os.path.exists(cache_dir):
|
|
log_message("Brak katalogu cache", "CACHE")
|
|
return
|
|
|
|
cache_files = os.listdir(cache_dir)
|
|
log_message(f"Katalog cache: {cache_dir}", "CACHE")
|
|
log_message(f"Liczba plików cache: {len(cache_files)}", "CACHE")
|
|
|
|
for file in cache_files:
|
|
file_path = os.path.join(cache_dir, file)
|
|
file_size = os.path.getsize(file_path) / (1024 * 1024) # MB
|
|
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
|
|
log_message(f" - {file}: {file_size:.2f} MB, {file_time}", "CACHE")
|
|
|
|
# BEZPIECZNA FUNKCJA DO RÓWNOLEGŁEGO OBLICZANIA JĄDRA KWANTOWEGO Z TIMEOUTAMI
|
|
@timeout(1800) # 30 minut timeout
|
|
def parallel_quantum_kernel_evaluation(X1, X2, feature_map, backend_name='qasm_simulator', shots=1024):
|
|
# SPRAWDZENIE CACHE
|
|
feature_map_name = feature_map.__class__.__name__
|
|
cache_key = get_kernel_cache_key(X1.shape, X2.shape, feature_map_name, shots)
|
|
|
|
log_message(f"Sprawdzanie cache dla jądra: {cache_key}", "KERNEL")
|
|
cached_kernel = load_kernel_cache(cache_key)
|
|
|
|
if cached_kernel is not None:
|
|
log_message(f"Znaleziono jądro w cache! Oszczędność: ~{X1.shape[0] * X2.shape[0] * 8 / (1024**2):.1f} MB", "KERNEL")
|
|
return cached_kernel
|
|
|
|
log_message(f"Brak jądra w cache - obliczanie od nowa", "KERNEL")
|
|
|
|
n_jobs = CPU_CONFIG['n_jobs_kernel']
|
|
log_message(f"Bezpieczne obliczanie jądra kwantowego (n_jobs={n_jobs})", "KERNEL")
|
|
log_message(f"Rozmiar danych: {X1.shape} x {X2.shape}", "KERNEL")
|
|
log_message(f"Bezpieczne wykorzystanie rdzeni: {n_jobs}/{CPU_CONFIG['total_cores']} ({n_jobs/CPU_CONFIG['total_cores']*100:.1f}%)", "KERNEL")
|
|
|
|
# Sprawdź rozmiar danych - ograniczenie dla bezpieczeństwa
|
|
max_matrix_size = 1000 * 1000 # Maksymalnie 1M elementów
|
|
if X1.shape[0] * X2.shape[0] > max_matrix_size:
|
|
log_message(f"Zbyt duża macierz jądra: {X1.shape[0] * X2.shape[0]} > {max_matrix_size}", "WARNING")
|
|
log_message(f"Redukcja rozmiaru danych dla bezpieczeństwa", "KERNEL")
|
|
# Redukuj rozmiar danych
|
|
X1 = X1[:min(500, X1.shape[0])]
|
|
X2 = X2[:min(500, X2.shape[0])]
|
|
|
|
# Inicjalizacja backendu
|
|
try:
|
|
backend = Aer.get_backend(backend_name)
|
|
backend.set_options(shots=shots)
|
|
except Exception as e:
|
|
log_error(f"Błąd backendu: {e}, używam qasm_simulator")
|
|
backend = Aer.get_backend('qasm_simulator')
|
|
backend.set_options(shots=shots)
|
|
|
|
# Utworzenie quantum kernel
|
|
try:
|
|
from qiskit.utils import QuantumInstance
|
|
quantum_instance = QuantumInstance(backend=backend, shots=shots)
|
|
quantum_kernel = QuantumKernel(
|
|
feature_map=feature_map,
|
|
quantum_instance=quantum_instance
|
|
)
|
|
except Exception as e:
|
|
log_error(f"Błąd tworzenia quantum kernel: {e}")
|
|
return None
|
|
|
|
# BEZPIECZNA OPTYMALIZACJA CHUNK SIZE
|
|
chunk_size = max(1, min(X1.shape[0] // n_jobs, 5)) # Mniejsze chunki dla bezpieczeństwa
|
|
|
|
kernel_matrix = np.zeros((X1.shape[0], X2.shape[0]))
|
|
|
|
@timeout(300) # 5 minut timeout na chunk
|
|
def compute_kernel_chunk(start_idx):
|
|
end_idx = min(start_idx + chunk_size, X1.shape[0])
|
|
chunk_X1 = X1[start_idx:end_idx]
|
|
|
|
try:
|
|
chunk_kernel = quantum_kernel.evaluate(chunk_X1, X2)
|
|
return start_idx, end_idx, chunk_kernel
|
|
except Exception as e:
|
|
log_error(f"Błąd obliczania chunk'a {start_idx}-{end_idx}: {e}")
|
|
return start_idx, end_idx, np.zeros((end_idx - start_idx, X2.shape[0]))
|
|
|
|
# Bezpieczne równoległe obliczenia
|
|
from concurrent.futures import ProcessPoolExecutor, as_completed
|
|
|
|
log_message(f"Używam {n_jobs} rdzeni bezpiecznie", "KERNEL")
|
|
log_message(f"Chunk size: {chunk_size}", "KERNEL")
|
|
log_message(f"Liczba chunk'ów: {len(range(0, X1.shape[0], chunk_size))}", "KERNEL")
|
|
|
|
# BEZPIECZNA LICZBA PROCESÓW
|
|
max_workers = min(n_jobs, 20) # Maksymalnie 20 procesów jednocześnie
|
|
|
|
with ProcessPoolExecutor(max_workers=max_workers) as executor:
|
|
futures = []
|
|
for i in range(0, X1.shape[0], chunk_size):
|
|
futures.append(executor.submit(compute_kernel_chunk, i))
|
|
|
|
# Zbierz wyniki z timeoutami
|
|
completed_chunks = 0
|
|
for future in as_completed(futures, timeout=1800): # 30 minut timeout
|
|
try:
|
|
start_idx, end_idx, chunk_kernel = future.result(timeout=300)
|
|
kernel_matrix[start_idx:end_idx] = chunk_kernel
|
|
completed_chunks += 1
|
|
log_message(f"Ukończono chunk {completed_chunks}/{len(futures)}", "KERNEL")
|
|
except Exception as e:
|
|
log_error(f"Błąd w chunk'u: {e}")
|
|
continue
|
|
|
|
# ZAPISZ DO CACHE
|
|
log_message(f"Zapisuję jądro do cache: {cache_key}", "KERNEL")
|
|
save_kernel_cache(kernel_matrix, cache_key)
|
|
|
|
return kernel_matrix
|
|
|
|
# OPTYMALIZOWANA FUNKCJA PRZYGOTOWANIA DANYCH Z CACHE
|
|
def prepare_data(data_file):
|
|
from sklearn.model_selection import train_test_split
|
|
from sklearn.preprocessing import StandardScaler
|
|
from sklearn.decomposition import PCA
|
|
from sklearn.manifold import TSNE
|
|
from sklearn.metrics import silhouette_score
|
|
|
|
# SPRAWDZENIE CACHE DLA DANYCH
|
|
cache_key = get_data_cache_key(data_file, TEST_SIZE, RANDOM_STATE, PCA_COMPONENTS)
|
|
print(f"Sprawdzanie cache dla danych: {cache_key}")
|
|
|
|
cached_data = load_data_cache(cache_key)
|
|
if cached_data is not None:
|
|
print(f"Znaleziono dane w cache! Oszczędność czasu przygotowania.")
|
|
return cached_data
|
|
|
|
print(f"Brak danych w cache - przygotowanie od nowa")
|
|
print(f"\n======= PRZYGOTOWANIE DANYCH =======")
|
|
start_time_data = time.time()
|
|
|
|
# Wczytanie danych
|
|
data = pd.read_csv(data_file)
|
|
print(f"Wymiary oryginalnych danych: {data.shape}")
|
|
|
|
# Wydzielenie zmiennej docelowej
|
|
y = data['Primary_Diagnosis']
|
|
print(f"Unikalne wartości zmiennej docelowej: {y.unique()}")
|
|
print(f"Rozkład klas: {y.value_counts().to_dict()}")
|
|
|
|
# Usunięcie kolumn identyfikacyjnych
|
|
id_columns = ['Project', 'Case_ID']
|
|
data_processed = data.drop(id_columns + ['Grade'], axis=1)
|
|
print(f"Wymiary danych po usunięciu kolumn identyfikacyjnych: {data_processed.shape}")
|
|
|
|
# Przekształcenie kolumn kategorycznych na binarne
|
|
print("Przekształcanie kolumn kategorycznych na binarne...")
|
|
categorical_columns = data_processed.select_dtypes(include=['object']).columns.tolist()
|
|
print(f"Kolumny kategoryczne do przekształcenia: {categorical_columns}")
|
|
|
|
# Specjalna obsługa kolumny Age_at_diagnosis (jeśli istnieje)
|
|
if 'Age_at_diagnosis' in categorical_columns:
|
|
print("Znaleziono kolumnę Age_at_diagnosis - sprawdzanie formatu...")
|
|
age_col = data_processed['Age_at_diagnosis']
|
|
|
|
# Sprawdź czy wartości są już numeryczne (dni)
|
|
try:
|
|
data_processed['Age_at_diagnosis'] = pd.to_numeric(age_col, errors='raise')
|
|
print("Kolumna Age_at_diagnosis została przekształcona na numeryczną (dni).")
|
|
categorical_columns.remove('Age_at_diagnosis') # Usuń z listy kolumn kategorycznych
|
|
except:
|
|
print("UWAGA: Kolumna Age_at_diagnosis nie jest numeryczna!")
|
|
|
|
# Przekształcenie każdej kolumny kategorycznej
|
|
for col in categorical_columns:
|
|
unique_values = data_processed[col].unique()
|
|
print(f"Kolumna {col} zawiera wartości: {unique_values}")
|
|
|
|
if len(unique_values) == 2:
|
|
if set(unique_values) == {'Yes', 'No'}:
|
|
data_processed[col] = data_processed[col].map({'Yes': 1, 'No': 0})
|
|
elif set(unique_values) == {'Male', 'Female'}:
|
|
data_processed[col] = data_processed[col].map({'Male': 1, 'Female': 0})
|
|
elif set(unique_values) == {'GBM', 'LGG'}:
|
|
data_processed[col] = data_processed[col].map({'GBM': 1, 'LGG': 0})
|
|
else:
|
|
data_processed[col] = pd.factorize(data_processed[col])[0]
|
|
else:
|
|
# Ograniczenie one-hot encoding do maksymalnie 10 kategorii
|
|
MAX_CATEGORIES = 10
|
|
if len(unique_values) > MAX_CATEGORIES:
|
|
print(f"Kolumna {col} ma {len(unique_values)} kategorii - używam factorize zamiast one-hot.")
|
|
data_processed[col] = pd.factorize(data_processed[col])[0]
|
|
else:
|
|
try:
|
|
data_processed[col] = pd.to_numeric(data_processed[col], errors='raise')
|
|
print(f"Kolumna {col} została przekształcona na liczbową.")
|
|
except:
|
|
print(f"Kolumna {col} zostanie zakodowana jako one-hot ({len(unique_values)} kategorii).")
|
|
dummies = pd.get_dummies(data_processed[col], prefix=col, drop_first=True)
|
|
data_processed = pd.concat([data_processed, dummies], axis=1)
|
|
data_processed.drop(col, axis=1, inplace=True)
|
|
|
|
# Sprawdzenie, czy wszystkie dane są numeryczne
|
|
non_numeric = data_processed.select_dtypes(include=['object']).columns.tolist()
|
|
if non_numeric:
|
|
print(f"UWAGA: Pozostały kolumny nieliczbowe: {non_numeric}")
|
|
print("Usuwanie pozostałych kolumn nieliczbowych...")
|
|
data_processed = data_processed.drop(non_numeric, axis=1)
|
|
|
|
print(f"Wymiary danych po przekształceniu: {data_processed.shape}")
|
|
|
|
# Kontrola liczby wymiarów
|
|
MAX_DIMENSIONS = 27 # Maksymalna liczba wymiarów
|
|
if data_processed.shape[1] > MAX_DIMENSIONS:
|
|
print(f"UWAGA: Zbyt wiele wymiarów ({data_processed.shape[1]})! Maksymalnie {MAX_DIMENSIONS}.")
|
|
print("Rozważ zwiększenie PCA_COMPONENTS lub ograniczenie one-hot encoding.")
|
|
|
|
# Wypełnienie brakujących wartości
|
|
if data_processed.isnull().sum().sum() > 0:
|
|
print("Wypełnianie brakujących wartości...")
|
|
data_processed.fillna(data_processed.mean(), inplace=True)
|
|
|
|
# Przygotowanie danych do modelowania
|
|
X = data_processed.values
|
|
print(f"Wymiary danych wejściowych: {X.shape}")
|
|
|
|
# Przetwarzanie cech
|
|
scaler = StandardScaler()
|
|
X_scaled = scaler.fit_transform(X)
|
|
print(f"Wymiary danych po skalowaniu: {X_scaled.shape}")
|
|
|
|
# Redukcja wymiarowości
|
|
print("\n======= REDUKCJA WYMIAROWOŚCI =======")
|
|
|
|
# Przygotowanie różnych wersji zredukowanych danych
|
|
X_reduced_versions = {}
|
|
|
|
if USE_PCA:
|
|
pca_components = min(PCA_COMPONENTS, X_scaled.shape[1])
|
|
print(f"Liczba komponentów PCA: {pca_components}")
|
|
pca = PCA(n_components=pca_components)
|
|
X_reduced_pca = pca.fit_transform(X_scaled)
|
|
print(f"Wymiary danych po redukcji PCA: {X_reduced_pca.shape}")
|
|
print(f"Wyjaśniona wariancja: {sum(pca.explained_variance_ratio_):.4f}")
|
|
X_reduced_versions['pca'] = X_reduced_pca
|
|
|
|
if USE_TSNE:
|
|
print(f"\nStosowanie t-SNE na danych skalowanych...")
|
|
tsne = TSNE(
|
|
n_components=TSNE_COMPONENTS,
|
|
perplexity=TSNE_PERPLEXITY,
|
|
learning_rate=TSNE_LEARNING_RATE,
|
|
n_iter=TSNE_MAX_ITER,
|
|
random_state=RANDOM_STATE
|
|
)
|
|
tsne_start_time = time.time()
|
|
X_reduced_tsne = tsne.fit_transform(X_scaled)
|
|
tsne_end_time = time.time()
|
|
tsne_time = tsne_end_time - tsne_start_time
|
|
print(f"Wymiary danych po redukcji t-SNE: {X_reduced_tsne.shape}")
|
|
print(f"Czas wykonania t-SNE: {tsne_time:.2f} sekund")
|
|
|
|
if EVALUATE_SILHOUETTE:
|
|
try:
|
|
silhouette_avg = silhouette_score(X_reduced_tsne, y)
|
|
print(f"Silhouette Score dla t-SNE: {silhouette_avg:.4f}")
|
|
except Exception as e:
|
|
print(f"Nie udało się obliczyć Silhouette Score: {str(e)}")
|
|
|
|
X_reduced_versions['tsne'] = X_reduced_tsne
|
|
|
|
if USE_UMAP:
|
|
print(f"\nStosowanie UMAP na danych skalowanych...")
|
|
umap_reducer = umap.UMAP(
|
|
n_components=UMAP_COMPONENTS,
|
|
n_neighbors=UMAP_NEIGHBORS,
|
|
min_dist=UMAP_MIN_DIST,
|
|
metric=UMAP_METRIC,
|
|
random_state=RANDOM_STATE
|
|
)
|
|
umap_start_time = time.time()
|
|
X_reduced_umap = umap_reducer.fit_transform(X_scaled)
|
|
umap_end_time = time.time()
|
|
umap_time = umap_end_time - umap_start_time
|
|
print(f"Wymiary danych po redukcji UMAP: {X_reduced_umap.shape}")
|
|
print(f"Czas wykonania UMAP: {umap_time:.2f} sekund")
|
|
|
|
if EVALUATE_SILHOUETTE:
|
|
try:
|
|
silhouette_avg_umap = silhouette_score(X_reduced_umap, y)
|
|
print(f"Silhouette Score dla UMAP: {silhouette_avg_umap:.4f}")
|
|
except Exception as e:
|
|
print(f"Nie udało się obliczyć Silhouette Score dla UMAP: {str(e)}")
|
|
|
|
X_reduced_versions['umap'] = X_reduced_umap
|
|
|
|
# Wybór domyślnej wersji zredukowanych danych
|
|
if 'pca' in X_reduced_versions:
|
|
X_reduced = X_reduced_versions['pca']
|
|
print("Używanie danych zredukowanych przez PCA jako domyślnych.")
|
|
elif 'umap' in X_reduced_versions:
|
|
X_reduced = X_reduced_versions['umap']
|
|
print("Używanie danych zredukowanych przez UMAP jako domyślnych.")
|
|
elif 'tsne' in X_reduced_versions:
|
|
X_reduced = X_reduced_versions['tsne']
|
|
print("Używanie danych zredukowanych przez t-SNE jako domyślnych.")
|
|
else:
|
|
X_reduced = X_scaled
|
|
print("Nie wybrano żadnej metody redukcji wymiarowości. Używanie oryginalnych danych skalowanych.")
|
|
|
|
# Podział na zbiory treningowy i testowy
|
|
X_train_reduced, X_test_reduced, y_train, y_test = train_test_split(
|
|
X_reduced, y, test_size=TEST_SIZE, random_state=RANDOM_STATE
|
|
)
|
|
|
|
# Podział dla oryginalnych danych
|
|
X_train, X_test, _, _ = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE)
|
|
|
|
print(f"Wymiary zbioru treningowego: {X_train_reduced.shape}")
|
|
print(f"Wymiary zbioru testowego: {X_test_reduced.shape}")
|
|
|
|
end_time_data = time.time()
|
|
data_preparation_time = end_time_data - start_time_data
|
|
print(f"\nCzas przygotowania danych: {data_preparation_time:.2f} sekund")
|
|
|
|
# PRZYGOTUJ DANE DO CACHE
|
|
data_dict = {
|
|
'X_train': X_train,
|
|
'X_test': X_test,
|
|
'X_train_reduced': X_train_reduced,
|
|
'X_test_reduced': X_test_reduced,
|
|
'y_train': y_train,
|
|
'y_test': y_test,
|
|
'data_processed': data_processed,
|
|
'preparation_time': data_preparation_time
|
|
}
|
|
|
|
# ZAPISZ DO CACHE
|
|
print(f"Zapisuję dane do cache: {cache_key}")
|
|
save_data_cache(data_dict, cache_key)
|
|
|
|
return data_dict
|
|
|
|
def run_experiment_parallel(exp_file):
|
|
experiment_name = exp_file.replace('.py', '')
|
|
|
|
# SPRAWDZENIE CACHE DLA EKSPERYMENTU
|
|
log_message(f"Sprawdzanie cache dla eksperymentu: {experiment_name}", "EXPERIMENT")
|
|
cached_results = load_experiment_cache(experiment_name)
|
|
|
|
if cached_results is not None:
|
|
log_message(f"Znaleziono wyniki eksperymentu w cache: {experiment_name}", "EXPERIMENT")
|
|
return cached_results
|
|
|
|
log_message(f"Brak wyników w cache - uruchamianie eksperymentu: {experiment_name}", "EXPERIMENT")
|
|
|
|
# URUCHOM EKSPERYMENT
|
|
if exp_file == 'qsvm1_zz.py':
|
|
import qsvm1_zz
|
|
results = qsvm1_zz.run_experiment()
|
|
elif exp_file == 'qsvm2_pauli.py':
|
|
import qsvm2_pauli
|
|
results = qsvm2_pauli.run_experiment()
|
|
elif exp_file == 'qsvm3_z.py':
|
|
import qsvm3_z
|
|
results = qsvm3_z.run_experiment()
|
|
elif exp_file == 'qsvm4_amplitude.py':
|
|
import qsvm4_amplitude
|
|
results = qsvm4_amplitude.run_experiment()
|
|
elif exp_file == 'qsvm5_hybrid.py':
|
|
import qsvm5_hybrid
|
|
results = qsvm5_hybrid.run_experiment()
|
|
else:
|
|
log_error(f"Nieznany eksperyment: {exp_file}")
|
|
return None
|
|
|
|
# ZAPISZ WYNIKI DO CACHE
|
|
if results is not None:
|
|
log_message(f"Zapisuję wyniki eksperymentu do cache: {experiment_name}", "EXPERIMENT")
|
|
save_experiment_cache(experiment_name, results)
|
|
|
|
return results
|
|
|
|
def run_single_file_experiment(args):
|
|
exp_file, data_file = args
|
|
experiment_name = exp_file.replace('.py', '')
|
|
file_name = os.path.basename(data_file).split('.')[0]
|
|
|
|
log_message(f"Uruchamianie {experiment_name} na pliku: {file_name}", "FILE_EXPERIMENT")
|
|
|
|
# SPRAWDZENIE CACHE DLA KOMBINACJI EKSPERYMENT+PLIK
|
|
cache_key = f"{experiment_name}_{file_name}"
|
|
cached_results = load_experiment_cache(cache_key)
|
|
|
|
if cached_results is not None:
|
|
log_message(f"Znaleziono wyniki w cache: {cache_key}", "FILE_EXPERIMENT")
|
|
return (exp_file, data_file, cached_results)
|
|
|
|
log_message(f"Brak wyników w cache - obliczanie: {cache_key}", "FILE_EXPERIMENT")
|
|
|
|
# URUCHOM EKSPERYMENT NA POJEDYNCZYM PLIKU
|
|
try:
|
|
if exp_file == 'qsvm1_zz.py':
|
|
import qsvm1_zz
|
|
results = qsvm1_zz.run_single_file_experiment(data_file)
|
|
elif exp_file == 'qsvm2_pauli.py':
|
|
import qsvm2_pauli
|
|
results = qsvm2_pauli.run_single_file_experiment(data_file)
|
|
elif exp_file == 'qsvm3_z.py':
|
|
import qsvm3_z
|
|
results = qsvm3_z.run_single_file_experiment(data_file)
|
|
elif exp_file == 'qsvm4_amplitude.py':
|
|
import qsvm4_amplitude
|
|
results = qsvm4_amplitude.run_single_file_experiment(data_file)
|
|
elif exp_file == 'qsvm5_hybrid.py':
|
|
import qsvm5_hybrid
|
|
results = qsvm5_hybrid.run_single_file_experiment(data_file)
|
|
else:
|
|
log_error(f"Nieznany eksperyment: {exp_file}")
|
|
return (exp_file, data_file, None)
|
|
|
|
# ZAPISZ WYNIKI DO CACHE
|
|
if results is not None:
|
|
log_message(f"Zapisuję wyniki do cache: {cache_key}", "FILE_EXPERIMENT")
|
|
save_experiment_cache(cache_key, results)
|
|
|
|
return (exp_file, data_file, results)
|
|
|
|
except Exception as e:
|
|
log_error(f"Błąd w eksperymencie {exp_file} na pliku {data_file}: {e}")
|
|
return (exp_file, data_file, None)
|
|
|
|
@timeout(7200) # 2 godziny timeout na cały eksperyment
|
|
def run_all_experiments_parallel():
|
|
experiment_files = [
|
|
'qsvm3_z.py' # ZFeatureMap - ZAKOMENTOWANE
|
|
# 'qsvm4_amplitude.py', # Amplitude Encoding - ZAKOMENTOWANE
|
|
# 'qsvm1_zz.py', # ZZFeatureMap - ZAKOMENTOWANE
|
|
# 'qsvm2_pauli.py' # PauliFeatureMap - TYLKO TEN
|
|
# 'qsvm5_hybrid.py' # Hybrid Approach - ZAKOMENTOWANE
|
|
]
|
|
|
|
# GENERUJ WSZYSTKIE KOMBINACJE EKSPERYMENT+PLIK
|
|
all_combinations = []
|
|
for exp_file in experiment_files:
|
|
for data_file in DATA_FILES:
|
|
all_combinations.append((exp_file, data_file))
|
|
|
|
total_combinations = len(all_combinations)
|
|
log_message(f"Łączna liczba kombinacji eksperyment+plik: {total_combinations}", "MAIN")
|
|
|
|
# BEZPIECZNE WYKORZYSTANIE RDZENI
|
|
n_processes = min(CPU_CONFIG['n_jobs_parallel'], total_combinations, 8) # Maksymalnie 8 procesów
|
|
log_message(f"Uruchamianie {total_combinations} kombinacji z {n_processes} procesami bezpiecznie", "MAIN")
|
|
log_message(f"Eksperymenty: {experiment_files}", "MAIN")
|
|
log_message(f"Pliki danych: {len(DATA_FILES)}", "MAIN")
|
|
log_message(f"Bezpieczne przyspieszenie: ~{n_processes/2:.1f}x", "MAIN")
|
|
|
|
# Dodatkowe informacje o wydajności
|
|
log_message(f"Dostępna pamięć: {CPU_CONFIG['available_memory']:.1f} GB", "MAIN")
|
|
log_message(f"Bezpieczna konfiguracja rdzeni:", "MAIN")
|
|
log_message(f" - Jądro kwantowe: {CPU_CONFIG['n_jobs_kernel']} rdzeni", "MAIN")
|
|
log_message(f" - SVM: {CPU_CONFIG['n_jobs_svm']} rdzeni", "MAIN")
|
|
log_message(f" - Równoległość: {CPU_CONFIG['n_jobs_parallel']} rdzeni", "MAIN")
|
|
|
|
# Przewidywany czas dla wszystkich kombinacji
|
|
log_message(f"PRZEWIDYWANY CZAS Z TIMEOUTAMI:", "MAIN")
|
|
log_message(f" - Amplitude: 20-45 minut na plik (max 2h)", "MAIN")
|
|
log_message(f" - ŁĄCZNIE: {total_combinations} kombinacji z timeoutami", "MAIN")
|
|
|
|
# URUCHOM KOMBINACJE Z TIMEOUTAMI
|
|
results = []
|
|
for i, combination in enumerate(all_combinations):
|
|
try:
|
|
log_message(f"Uruchamianie kombinacji {i+1}/{total_combinations}: {combination}", "MAIN")
|
|
|
|
# Timeout na pojedynczą kombinację
|
|
@timeout(3600) # 1 godzina na kombinację
|
|
def run_single_with_timeout():
|
|
return run_single_file_experiment(combination)
|
|
|
|
result = run_single_with_timeout()
|
|
results.append(result)
|
|
|
|
log_message(f"Ukończono kombinację {i+1}/{total_combinations}", "MAIN")
|
|
|
|
except TimeoutError:
|
|
log_message(f"Timeout dla kombinacji {i+1}: {combination}", "WARNING")
|
|
results.append((combination[0], combination[1], None))
|
|
except Exception as e:
|
|
log_error(f"Błąd w kombinacji {i+1}: {e}")
|
|
results.append((combination[0], combination[1], None))
|
|
|
|
# GRUPUJ WYNIKI WG EKSPERYMENTÓW
|
|
grouped_results = {}
|
|
for exp_file in experiment_files:
|
|
grouped_results[exp_file] = []
|
|
|
|
for exp_file, data_file, result in results:
|
|
if result is not None:
|
|
grouped_results[exp_file].append((data_file, result))
|
|
|
|
return grouped_results
|
|
|
|
# FUNKCJA DO URACHAMIANIA KLASYCZNEGO SVM
|
|
def run_classic_svm_single_file(data_file):
|
|
from sklearn.svm import SVC
|
|
from sklearn.model_selection import GridSearchCV, cross_val_score
|
|
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score
|
|
|
|
file_name = os.path.basename(data_file).split('.')[0]
|
|
log_message(f"Uruchamianie klasycznego SVM na pliku: {file_name}", "CLASSIC_SVM")
|
|
|
|
# SPRAWDZENIE CACHE DLA KLASYCZNEGO SVM
|
|
cache_key = f"classic_svm_{file_name}"
|
|
cached_results = load_experiment_cache(cache_key)
|
|
|
|
if cached_results is not None:
|
|
log_message(f"Znaleziono wyniki klasycznego SVM w cache: {cache_key}", "CLASSIC_SVM")
|
|
return cached_results
|
|
|
|
log_message(f"Brak wyników w cache - obliczanie klasycznego SVM: {cache_key}", "CLASSIC_SVM")
|
|
|
|
try:
|
|
# Przygotowanie danych
|
|
data_dict = prepare_data(data_file)
|
|
X_train_reduced = data_dict['X_train_reduced']
|
|
X_test_reduced = data_dict['X_test_reduced']
|
|
y_train = data_dict['y_train']
|
|
y_test = data_dict['y_test']
|
|
|
|
log_message(f"Wymiary danych treningowych: {X_train_reduced.shape}", "CLASSIC_SVM")
|
|
log_message(f"Wymiary danych testowych: {X_test_reduced.shape}", "CLASSIC_SVM")
|
|
|
|
# Uruchomienie klasycznego SVM z GridSearchCV
|
|
start_time = time.time()
|
|
|
|
# BEZPIECZNE WYKORZYSTANIE RDZENI
|
|
n_jobs = min(CPU_CONFIG['n_jobs_svm'], 8) # Maksymalnie 8 rdzeni dla bezpieczeństwa
|
|
log_message(f"Używam {n_jobs} rdzeni dla klasycznego SVM", "CLASSIC_SVM")
|
|
|
|
grid = GridSearchCV(
|
|
SVC(random_state=RANDOM_STATE),
|
|
SVM_PARAM_GRID,
|
|
cv=SVM_CV,
|
|
scoring='accuracy',
|
|
n_jobs=n_jobs,
|
|
verbose=1
|
|
)
|
|
|
|
log_message("Rozpoczynam GridSearchCV dla klasycznego SVM...", "CLASSIC_SVM")
|
|
grid.fit(X_train_reduced, y_train)
|
|
|
|
# Najlepszy model
|
|
best_model = grid.best_estimator_
|
|
best_params = grid.best_params_
|
|
best_score = grid.best_score_
|
|
|
|
# Predykcje na zbiorze testowym
|
|
classic_pred = best_model.predict(X_test_reduced)
|
|
|
|
end_time = time.time()
|
|
classic_svm_time = end_time - start_time
|
|
|
|
# Obliczenie metryk
|
|
accuracy = accuracy_score(y_test, classic_pred)
|
|
precision = precision_score(y_test, classic_pred, average='weighted', zero_division=0)
|
|
recall = recall_score(y_test, classic_pred, average='weighted', zero_division=0)
|
|
f1 = f1_score(y_test, classic_pred, average='weighted', zero_division=0)
|
|
|
|
try:
|
|
roc_auc = roc_auc_score(y_test, classic_pred)
|
|
except:
|
|
roc_auc = "N/A"
|
|
|
|
# Macierz pomyłek
|
|
cm = confusion_matrix(y_test, classic_pred)
|
|
|
|
# Raport klasyfikacji
|
|
class_report = classification_report(y_test, classic_pred, output_dict=True)
|
|
|
|
# Wyniki
|
|
results = {
|
|
'file_name': file_name,
|
|
'best_params': best_params,
|
|
'best_cv_score': best_score,
|
|
'test_accuracy': accuracy,
|
|
'test_precision': precision,
|
|
'test_recall': recall,
|
|
'test_f1': f1,
|
|
'test_roc_auc': roc_auc,
|
|
'confusion_matrix': cm.tolist(),
|
|
'classification_report': class_report,
|
|
'training_time': classic_svm_time,
|
|
'data_shape': X_train_reduced.shape,
|
|
'timestamp': datetime.now().isoformat()
|
|
}
|
|
|
|
log_message(f"Klasyczny SVM ukończony dla {file_name}:", "CLASSIC_SVM")
|
|
log_message(f" - Najlepsze parametry: {best_params}", "CLASSIC_SVM")
|
|
log_message(f" - Dokładność CV: {best_score:.4f}", "CLASSIC_SVM")
|
|
log_message(f" - Dokładność test: {accuracy:.4f}", "CLASSIC_SVM")
|
|
log_message(f" - Czas treningu: {classic_svm_time:.2f} sekund", "CLASSIC_SVM")
|
|
|
|
# ZAPISZ DO CACHE
|
|
log_message(f"Zapisuję wyniki klasycznego SVM do cache: {cache_key}", "CLASSIC_SVM")
|
|
save_experiment_cache(cache_key, results)
|
|
|
|
return results
|
|
|
|
except Exception as e:
|
|
log_error(f"Błąd w klasycznym SVM dla pliku {data_file}: {e}")
|
|
return None
|
|
|
|
# FUNKCJA DO URACHAMIANIA KLASYCZNEGO SVM NA WSZYSTKICH PLIKACH
|
|
def run_classic_svm_all_files():
|
|
log_message(f"Uruchamianie klasycznego SVM na {len(DATA_FILES)} plikach", "CLASSIC_SVM_ALL")
|
|
|
|
# Sprawdź które pliki istnieją
|
|
existing_files = []
|
|
for data_file in DATA_FILES:
|
|
if os.path.exists(data_file):
|
|
existing_files.append(data_file)
|
|
else:
|
|
log_message(f"Plik nie istnieje: {data_file}", "WARNING")
|
|
|
|
log_message(f"Znaleziono {len(existing_files)} istniejących plików", "CLASSIC_SVM_ALL")
|
|
|
|
# Uruchom klasyczny SVM na wszystkich plikach
|
|
results = []
|
|
for i, data_file in enumerate(existing_files):
|
|
try:
|
|
log_message(f"Przetwarzanie pliku {i+1}/{len(existing_files)}: {os.path.basename(data_file)}", "CLASSIC_SVM_ALL")
|
|
|
|
# Timeout na pojedynczy plik
|
|
@timeout(1800) # 30 minut na plik
|
|
def run_single_with_timeout():
|
|
return run_classic_svm_single_file(data_file)
|
|
|
|
result = run_single_with_timeout()
|
|
if result is not None:
|
|
results.append(result)
|
|
log_message(f"Ukończono plik {i+1}/{len(existing_files)}", "CLASSIC_SVM_ALL")
|
|
else:
|
|
log_message(f"Błąd w pliku {i+1}/{len(existing_files)}", "CLASSIC_SVM_ALL")
|
|
|
|
except TimeoutError:
|
|
log_message(f"Timeout dla pliku {i+1}: {os.path.basename(data_file)}", "WARNING")
|
|
except Exception as e:
|
|
log_error(f"Błąd w pliku {i+1}: {e}")
|
|
|
|
# Zapisanie wszystkich wyników
|
|
if results:
|
|
output_file = os.path.join(OUTPUT_DIR, f'wyniki_classic_svm_all_{datetime.now().strftime("%Y%m%d_%H%M%S")}.json')
|
|
with open(output_file, 'w') as f:
|
|
json.dump(results, f, indent=2)
|
|
log_message(f"Zapisano wszystkie wyniki do: {output_file}", "CLASSIC_SVM_ALL")
|
|
|
|
# Podsumowanie
|
|
log_message("PODSUMOWANIE KLASYCZNEGO SVM:", "CLASSIC_SVM_ALL")
|
|
for result in results:
|
|
log_message(f" {result['file_name']}: {result['test_accuracy']:.4f} (czas: {result['training_time']:.1f}s)", "CLASSIC_SVM_ALL")
|
|
|
|
return results
|
|
|
|
if __name__ == "__main__":
|
|
print("======= KONTROLER EKSPERYMENTÓW QSVM - BEZPIECZNE ZFEATUREMAP Z TIMEOUTAMI =======")
|
|
print(f"BEZPIECZNA KONFIGURACJA: {CPU_CONFIG['total_cores']} rdzeni")
|
|
print(f"Dostępna pamięć: {CPU_CONFIG['available_memory']:.1f} GB")
|
|
print(f"BEZPIECZNA KONFIGURACJA: {CPU_CONFIG}")
|
|
print("")
|
|
print("Uruchamianie TYLKO PAULIFEATUREMAP z BEZPIECZNYMI timeoutami:")
|
|
print(" - PauliFeatureMap (qsvm2_pauli.py) - TYLKO TEN")
|
|
print(" - Amplitude Encoding (qsvm4_amplitude.py) - ZAKOMENTOWANE")
|
|
print(" - ZZFeatureMap (qsvm1_zz.py) - ZAKOMENTOWANE")
|
|
print(" - ZFeatureMap (qsvm3_z.py) - ZAKOMENTOWANE")
|
|
print(" - Hybrid Approach (qsvm5_hybrid.py) - ZAKOMENTOWANE")
|
|
print("")
|
|
print("SYSTEM BEZPIECZEŃSTWA:")
|
|
print(" - Timeouty na wszystkie operacje - zapobieganie zawieszeniu")
|
|
print(" - Monitoring zasobów - wykrywanie przeciążenia")
|
|
print(" - Ograniczone wykorzystanie rdzeni - 70% maksymalnie")
|
|
print(" - Cache z timeoutami - bezpieczne zapisywanie")
|
|
print("")
|
|
print("SYSTEM CACHE:")
|
|
print(" - Cache jądra kwantowego - oszczędność obliczeń")
|
|
print(" - Cache przygotowania danych - oszczędność czasu")
|
|
print(" - Cache wyników eksperymentów - wznowienie po przerwaniu")
|
|
print("")
|
|
print("PRZEWIDYWANE WYNIKI:")
|
|
print(f" - Czas wykonania: 1-2 godziny (z timeoutami)")
|
|
print(f" - Bezpieczne wykorzystanie rdzeni: {CPU_CONFIG['n_jobs_kernel'] + CPU_CONFIG['n_jobs_svm'] + CPU_CONFIG['n_jobs_parallel']}/{CPU_CONFIG['total_cores']}")
|
|
print(f" - Przewidywane przyspieszenie: ~{CPU_CONFIG['total_cores']/16:.1f}x (bezpieczne)")
|
|
print(" - Oszczędność dzięki cache: 50-80% przy ponownym uruchomieniu")
|
|
print(" - Zero zawieszeń dzięki timeoutom")
|
|
print("")
|
|
|
|
# SPRAWDZENIE STATUSU CACHE
|
|
print("Sprawdzanie statusu cache...")
|
|
check_cache_status()
|
|
print("")
|
|
|
|
try:
|
|
start_time = time.time()
|
|
|
|
print("URUCHAMIANIE KWANTOWEGO SVM (ZFEATUREMAP)")
|
|
print("Uruchamianie TYLKO PAULIFEATUREMAP z BEZPIECZNYMI timeoutami:")
|
|
print(" - PauliFeatureMap (qsvm2_pauli.py) - TYLKO TEN")
|
|
print(" - Amplitude Encoding (qsvm4_amplitude.py) - ZAKOMENTOWANE")
|
|
print(" - ZZFeatureMap (qsvm1_zz.py) - ZAKOMENTOWANE")
|
|
print(" - ZFeatureMap (qsvm3_z.py) - ZAKOMENTOWANE")
|
|
print(" - Hybrid Approach (qsvm5_hybrid.py) - ZAKOMENTOWANE")
|
|
print("")
|
|
print("PRZEWIDYWANE WYNIKI:")
|
|
print(f" - Czas wykonania: 1-2 godziny (z timeoutami)")
|
|
print(f" - Bezpieczne wykorzystanie rdzeni: {CPU_CONFIG['n_jobs_kernel'] + CPU_CONFIG['n_jobs_svm'] + CPU_CONFIG['n_jobs_parallel']}/{CPU_CONFIG['total_cores']}")
|
|
print(f" - Przewidywane przyspieszenie: ~{CPU_CONFIG['total_cores']/16:.1f}x (bezpieczne)")
|
|
print(" - Oszczędność dzięki cache: 50-80% przy ponownym uruchomieniu")
|
|
print(" - Zero zawieszeń dzięki timeoutom")
|
|
print("")
|
|
|
|
results = run_all_experiments_parallel()
|
|
end_time = time.time()
|
|
|
|
total_time = end_time - start_time
|
|
print("")
|
|
print("======= PAULIFEATUREMAP ZAKOŃCZONE - BEZPIECZNIE Z TIMEOUTAMI =======")
|
|
print(f"Całkowity czas wykonania: {total_time/60:.1f} minut ({total_time/3600:.1f} godzin)")
|
|
print(f"⚡ Średni czas na eksperyment: {total_time/1/60:.1f} minut")
|
|
print(f"Bezpieczne wykorzystanie rdzeni: {CPU_CONFIG['n_jobs_kernel'] + CPU_CONFIG['n_jobs_svm'] + CPU_CONFIG['n_jobs_parallel']}/{CPU_CONFIG['total_cores']} ({((CPU_CONFIG['n_jobs_kernel'] + CPU_CONFIG['n_jobs_svm'] + CPU_CONFIG['n_jobs_parallel'])/CPU_CONFIG['total_cores'])*100:.1f}%)")
|
|
print("Finalny status cache:")
|
|
check_cache_status()
|
|
print("PAULIFEATUREMAP ZAKOŃCZONE BEZPIECZNIE!")
|
|
|
|
except TimeoutError:
|
|
print("")
|
|
print("======= EKSPERYMENT PRZERWANY PRZEZ TIMEOUT =======")
|
|
print("Eksperyment został bezpiecznie przerwany po przekroczeniu limitu czasu")
|
|
print("Wyniki częściowe zostały zapisane w cache")
|
|
print("Status cache:")
|
|
check_cache_status()
|
|
print("Można wznowić eksperyment - cache zostanie wykorzystany")
|
|
|
|
except Exception as e:
|
|
print("")
|
|
print("======= BŁĄD W EKSPERYMENCIE =======")
|
|
print(f"Błąd: {str(e)}")
|
|
print("Status cache:")
|
|
check_cache_status()
|
|
print("Sprawdź logi i spróbuj ponownie")
|