QGAN_Project / vG.0.1 /train_quantum_classifier
1bnjmn3's picture
Add files using upload-large-folder tool
0f755ec verified
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes, ZFeatureMap
from qiskit_aer import AerSimulator
from qiskit_machine_learning.connectors import TorchConnector
from qiskit_machine_learning.neural_networks import SamplerQNN
from sklearn.metrics import roc_auc_score
# 1. Load Data (The Optimized Set from Phase VI)
print("Loading validated data...")
data = np.load('qgan_data_optimized.npz')
X_train = data['X_train']
X_test = data['X_test']
y_train = data['y_train']
y_test = data['y_test']
# 2. Select Top 4 Features Only
# Quantum hardware is small. We take the 4 most important physics signals.
# (Beta_94, Beta_93, Beta_91, Beta_82 based on your previous output)
num_qubits = 4
X_train_q = X_train[:, :num_qubits]
X_test_q = X_test[:, :num_qubits]
# Convert to PyTorch Tensors
X_train_tensor = torch.tensor(X_train_q, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train, dtype=torch.float32).reshape(-1, 1)
X_test_tensor = torch.tensor(X_test_q, dtype=torch.float32)
print(f"Training Quantum Model on {len(X_train)} shots using {num_qubits} Qubits.")
# 3. Build the Quantum Circuit
# A. Feature Map: Encodes classical data into quantum states (Rotation Z)
feature_map = ZFeatureMap(feature_dimension=num_qubits, reps=1)
# B. Ansatz: The "Neural Network" weights (Entanglement + Rotations)
ansatz = RealAmplitudes(num_qubits, reps=1)
# C. Combine
qc = QuantumCircuit(num_qubits)
qc.compose(feature_map, inplace=True)
qc.compose(ansatz, inplace=True)
# 4. Define the Quantum Neural Network
qnn = SamplerQNN(
circuit=qc,
input_params=feature_map.parameters,
weight_params=ansatz.parameters,
interpret=lambda x: x % 2, # Map quantum measurements to 0 or 1
output_shape=2
)
# 5. Hybrid PyTorch Module
class HybridQNN(nn.Module):
def __init__(self):
super().__init__()
self.qnn = TorchConnector(qnn)
# Classical post-processing (Weighted sum of quantum output)
self.fc = nn.Linear(1, 1)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# Scale input to [0, 2pi] for quantum rotation
x_scaled = x * torch.pi
x_q = self.qnn(x_scaled)
# We look at probability of state '1' (Disruption)
x_out = self.fc(x_q[:, 1:2])
return self.sigmoid(x_out)
model = HybridQNN()
optimizer = optim.Adam(model.parameters(), lr=0.01)
loss_func = nn.BCELoss()
# 6. Training Loop
epochs = 15 # Kept short for demonstration speed
loss_list = []
print(f"\nπŸš€ Starting Hybrid Training ({epochs} epochs)...")
model.train()
for epoch in range(epochs):
optimizer.zero_grad()
# Forward pass
output = model(X_train_tensor)
loss = loss_func(output, y_train_tensor)
# Backward pass
loss.backward()
optimizer.step()
loss_list.append(loss.item())
print(f" Epoch {epoch+1}/{epochs} | Loss: {loss.item():.4f}")
# 7. Evaluation
print("\nEvaluating Quantum Model...")
model.eval()
with torch.no_grad():
test_preds = model(X_test_tensor).numpy()
auc = roc_auc_score(y_test, test_preds)
print("="*40)
print(f"πŸ”¬ QUANTUM MODEL RESULTS")
print("="*40)
print(f"βœ… QNN AUC Score: {auc:.4f}")
print(f"πŸ“Š Classical Benchmark to Beat: 0.8951")
print("="*40)
if auc > 0.8951:
print("πŸ† RESULT: QUANTUM ADVANTAGE ACHIEVED (on this dataset)")
elif auc > 0.85:
print("πŸ₯ˆ RESULT: Competitive Performance (Close to Classical)")
else:
print("⚠️ RESULT: Underperformed (Expected for simple NISQ circuits)")