File size: 4,482 Bytes
0f755ec | 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 | import numpy as np
import os
import time
# --- M1 OPTIMIZATIONS ---
os.environ["OMP_NUM_THREADS"] = "4"
os.environ["QISKIT_IN_PARALLEL"] = "TRUE"
from sklearn.svm import SVC
from sklearn.metrics import roc_auc_score
from qiskit.circuit import ParameterVector
from qiskit.circuit.library import ZZFeatureMap, RealAmplitudes
from qiskit_machine_learning.kernels import TrainableFidelityQuantumKernel
from qiskit_machine_learning.utils.loss_functions import SVCLoss
from qiskit_algorithms.optimizers import COBYLA
from qiskit_aer import AerSimulator
# --- CONFIGURATION ---
N_QUBITS = 8
TRAIN_SIZE = 150 # Smaller subset for alignment (speed) now 150 for even faster
TEST_SIZE = 300
MAX_ITERS = 50 # Optimization steps
OUTPUT_DIR = "optimized_kernel_results"
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
def main():
print(f"π Starting Quantum Kernel Optimization (QKA)...")
print(" Goal: Calculate optimal kernel geometry instead of guessing.")
# 1. LOAD DATA
possible_paths = ['vG.0.1/qgan_data_optimized.npz', 'qgan_data_optimized.npz']
data_path = next((p for p in possible_paths if os.path.exists(p)), None)
if not data_path:
print("β Error: qgan_data_optimized.npz not found.")
return
data = np.load(data_path)
X_train_full = data['X_train']
y_train_full = data['y_train']
X_test_full = data['X_test']
y_test_full = data['y_test']
# 2. SUBSAMPLE (Balanced)
pos_idx = np.where(y_train_full == 1)[0]
neg_idx = np.where(y_train_full == 0)[0]
train_idx = np.concatenate([
np.random.choice(pos_idx, TRAIN_SIZE // 2, replace=False),
np.random.choice(neg_idx, TRAIN_SIZE // 2, replace=False)
])
np.random.shuffle(train_idx)
X_train = X_train_full[train_idx]
y_train = y_train_full[train_idx]
X_test = X_test_full[:TEST_SIZE]
y_test = y_test_full[:TEST_SIZE]
print(f" π Training Alignment on {len(X_train)} samples...")
# 3. DEFINE TRAINABLE FEATURE MAP
# Circuit = Data Encoding (ZZ) + Trainable Rotation (RealAmplitudes)
# This acts as a "Quantum Lens" that the optimizer focuses.
print(" βοΈ Initializing Trainable Kernel...")
fm = ZZFeatureMap(N_QUBITS, reps=2, entanglement='linear')
ansatz = RealAmplitudes(N_QUBITS, reps=1)
combined_circuit = fm.compose(ansatz)
# FIX: Only pass the training_parameters.
# The class automatically infers that the other params (fm.parameters) are data inputs.
quant_kernel = TrainableFidelityQuantumKernel(
feature_map=combined_circuit,
training_parameters=ansatz.parameters
)
# 4. OPTIMIZE KERNEL (ALIGNMENT)
print(" π§ Optimizing Kernel Geometry (COBYLA)...")
# SVCLoss minimizes the classification error of the kernel
loss_func = SVCLoss(C=1.0, gamma='auto')
optimizer = COBYLA(maxiter=MAX_ITERS)
from qiskit_machine_learning.kernels.algorithms import QuantumKernelTrainer
trainer = QuantumKernelTrainer(
quantum_kernel=quant_kernel,
loss=loss_func,
optimizer=optimizer,
initial_point=[0.1] * len(ansatz.parameters)
)
start_time = time.time()
# Train the Kernel parameters
results = trainer.fit(X_train, y_train)
print(f" β
Optimization Complete in {time.time() - start_time:.1f}s")
print(f" π― Final Loss: {results.optimal_value:.4f}")
# 5. RUN FINAL SVC WITH OPTIMIZED KERNEL
print(" π Training Final SVM with Optimized Kernel...")
optimized_kernel = results.quantum_kernel
# We use the optimized kernel to fit the full SVM
qsvc = SVC(kernel=optimized_kernel.evaluate, probability=True)
qsvc.fit(X_train, y_train)
# Evaluate
test_probs = qsvc.predict_proba(X_test)[:, 1]
test_auc = roc_auc_score(y_test, test_probs)
print("\n" + "="*40)
print("π OPTIMIZED QUANTUM KERNEL RESULTS")
print("="*40)
print(f"β
Test AUC: {test_auc:.4f}")
print(f"π Linear Base: 0.7500")
print("="*40)
# Check if we beat the baseline
if test_auc > 0.75:
print("π SUCCESS: Optimization found a better topology than brute force.")
np.save(f"{OUTPUT_DIR}/optimized_weights.npy", results.optimal_point)
else:
print("πΈ Result: Optimization matched or slightly underperformed baseline.")
if __name__ == "__main__":
main() |