File size: 3,590 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
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)")