squ11z1 commited on
Commit
25f5493
·
verified ·
1 Parent(s): 41ab1ac

Upload quantum_kernel.py: IBM Quantum kernel implementation

Browse files
Files changed (1) hide show
  1. quantum_kernel.py +376 -0
quantum_kernel.py ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Быстрое создание квантового ядра для IBM Quantum
3
+ Оптимизировано для выполнения за ~8 минут
4
+ """
5
+
6
+ # ===== ШАГ 1: УСТАНОВКА И ИМПОРТЫ =====
7
+ # Выполните в терминале:
8
+ # pip install qiskit qiskit-ibm-runtime qiskit-machine-learning scikit-learn
9
+
10
+ import numpy as np
11
+ from sklearn.datasets import make_classification
12
+ from sklearn.model_selection import train_test_split
13
+ from sklearn.svm import SVC
14
+ from sklearn.metrics import accuracy_score
15
+
16
+ from qiskit import QuantumCircuit
17
+ from qiskit.circuit import ParameterVector
18
+ from qiskit.circuit.library import ZZFeatureMap, PauliFeatureMap
19
+ from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
20
+ from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
21
+
22
+ # ===== ШАГ 2: СОЗДАНИЕ ДАННЫХ =====
23
+ # Создаём простой датасет для бинарной классификации
24
+ print("Создание датасета...")
25
+
26
+ # Рассчитываем оптимальный размер на основе вашей скорости
27
+ # Ваша скорость: 108 схем за 44.3 секунды = 2.44 схемы/сек
28
+ # Доступно времени: ~7.5 минут = 450 секунд
29
+ # Максимум схем: 450 * 2.44 = ~1100 схем
30
+ # Оптимально: ~900 схем (запас 20%)
31
+
32
+ # Для 900 схем нужно: sqrt(900 * 0.75) ≈ 26 train образцов
33
+ # 26 train + 9 test = 35 образцов → 26^2 + 9*26 = 676 + 234 = 910 схем
34
+
35
+ X, y = make_classification(
36
+ n_samples=35, # Оптимально под вашу скорость!
37
+ n_features=4, # 4 признака -> 2 кубита
38
+ n_informative=4,
39
+ n_redundant=0,
40
+ n_clusters_per_class=1,
41
+ random_state=42
42
+ )
43
+
44
+ # Нормализация данных в диапазон [0, 2π]
45
+ X_min, X_max = X.min(), X.max()
46
+ X_normalized = 2 * np.pi * (X - X_min) / (X_max - X_min)
47
+
48
+ # Разделение на train/test (74/26)
49
+ X_train, X_test, y_train, y_test = train_test_split(
50
+ X_normalized, y, test_size=0.26, random_state=42 # ~26 train, ~9 test
51
+ )
52
+
53
+ print(f"Train: {len(X_train)} образцов, Test: {len(X_test)} образцов")
54
+ total_circuits = len(X_train)**2 + len(X_test)*len(X_train)
55
+ expected_time = total_circuits / 2.44 # На основе вашей реальной скорости
56
+ print(f"ВАЖНО: Общее количество схем = {len(X_train)**2} + {len(X_test)*len(X_train)} = {total_circuits}")
57
+ print(f"📊 Ожидаемое время (на основе вашей скорости 2.44 схем/сек):")
58
+ print(f" ~{expected_time:.0f} секунд ({expected_time/60:.1f} минут)")
59
+ print(f" Запас до 8 минут: {8 - expected_time/60:.1f} минут")
60
+
61
+ # ===== ШАГ 3: СОЗДАНИЕ FEATURE MAP =====
62
+ num_qubits = 2 # Используем 2 кубита (4 признака / 2)
63
+
64
+ # ZZFeatureMap с минимальными reps для ibm_fez
65
+ feature_map = ZZFeatureMap(
66
+ feature_dimension=num_qubits,
67
+ reps=1, # МИНИМУМ для экономии времени!
68
+ entanglement='linear'
69
+ )
70
+
71
+ print(f"\nFeature map создана с {num_qubits} кубитами")
72
+ print(f"Количество параметров: {feature_map.num_parameters}")
73
+ print(f"Глубина схемы: {feature_map.depth()}")
74
+
75
+ # ===== ШАГ 4: ПОДКЛЮЧЕНИЕ К IBM QUANTUM =====
76
+ print("\nПодключение к IBM Quantum...")
77
+
78
+ # ibm_quantum_platform - это канал по умолчанию, можно не указывать
79
+ try:
80
+ # Простейший вариант: token + instance (необязательно)
81
+ service = QiskitRuntimeService(token='YDU7vuX8jQb4gFHEaxnLPkuyg05ueEzfB2baajl3dmP_')
82
+
83
+ # Сохраняем для будущего использования
84
+ QiskitRuntimeService.save_account(
85
+ token='YDU7vuX8jQb4gFHEaxnLPkuyg05ueEzfB2baajl3dmP_',
86
+ overwrite=True
87
+ )
88
+ print("✅ API токен успешно сохранён!")
89
+ print("✅ Подключение установлено!")
90
+
91
+ except Exception as e:
92
+ print(f"❌ Ошибка подключения: {e}")
93
+ raise
94
+
95
+ # Подключаемся к ibm_fez (реальный квантовый компьютер!)
96
+ try:
97
+ backend = service.backend('ibm_fez')
98
+ print(f"\n{'='*50}")
99
+ print(f"Используем РЕАЛЬНЫЙ квантовый компьютер: {backend.name}")
100
+ print(f"Количество кубитов: {backend.num_qubits}")
101
+ print(f"Статус: {'✅ Operational' if backend.status().operational else '❌ Not operational'}")
102
+ print(f"{'='*50}\n")
103
+ except Exception as e:
104
+ print(f"\n⚠️ Backend ibm_fez недоступен: {e}")
105
+ print("\nДоступные backends:")
106
+ backends = service.backends()
107
+ for b in backends:
108
+ status = "✅" if b.status().operational else "❌"
109
+ print(f" {status} {b.name} ({b.num_qubits} qubits)")
110
+
111
+ print("\n💡 Используем наименее загруженный backend...")
112
+ backend = service.least_busy(operational=True, simulator=False, min_num_qubits=2)
113
+ print(f"Выбран: {backend.name}\n")
114
+
115
+ # ===== ШАГ 5: ФУНКЦИЯ ДЛЯ ВЫЧИСЛЕНИЯ ЯДРА =====
116
+ def compute_kernel_matrix(X1, X2, feature_map, backend, shots=1024):
117
+ """
118
+ Вычисляет матрицу квантового ядра между X1 и X2
119
+
120
+ Параметры:
121
+ - X1, X2: массивы данных
122
+ - feature_map: квантовая карта признаков
123
+ - backend: IBM Quantum backend
124
+ - shots: количество измерений на схему
125
+ """
126
+ n1, n2 = len(X1), len(X2)
127
+ kernel_matrix = np.zeros((n1, n2))
128
+
129
+ circuits = []
130
+ indices = []
131
+
132
+ # Создаём схемы для всех пар (i, j)
133
+ for i in range(n1):
134
+ for j in range(n2):
135
+ # Берём только первые num_qubits признаков
136
+ x1_features = X1[i][:num_qubits]
137
+ x2_features = X2[j][:num_qubits]
138
+
139
+ # Создаём overlap circuit
140
+ qc = QuantumCircuit(num_qubits)
141
+
142
+ # Применяем feature map для x1
143
+ qc.compose(feature_map.assign_parameters(x1_features), inplace=True)
144
+
145
+ # Применяем inverse feature map для x2
146
+ qc.compose(
147
+ feature_map.assign_parameters(x2_features).inverse(),
148
+ inplace=True
149
+ )
150
+
151
+ qc.measure_all()
152
+ circuits.append(qc)
153
+ indices.append((i, j))
154
+
155
+ # Оптимизация схем для ibm_fez
156
+ print(f"Транспиляция {len(circuits)} схем для ibm_fez...")
157
+ pm = generate_preset_pass_manager(
158
+ optimization_level=2, # Хороший баланс для реального QPU
159
+ backend=backend
160
+ )
161
+ transpiled_circuits = pm.run(circuits)
162
+
163
+ # Выполнение на квантовом компьютере ibm_fez
164
+ print(f"Отправка задачи на {backend.name} (shots={shots})...")
165
+ print("⏳ Ожидание выполнения на реальном квантовом компьютере...")
166
+
167
+ sampler = Sampler(mode=backend)
168
+ job = sampler.run(transpiled_circuits, shots=shots)
169
+
170
+ # Показываем ID задачи для отслеживания
171
+ print(f"Job ID: {job.job_id()}")
172
+ print(f"Статус: {job.status()}")
173
+
174
+ result = job.result()
175
+ print("✅ Выполнение завершено!")
176
+
177
+ # Обработка результатов
178
+ for idx, (i, j) in enumerate(indices):
179
+ counts = result[idx].data.meas.get_counts()
180
+ # Вероятность измерить |00...0>
181
+ zero_state = '0' * num_qubits
182
+ prob_zero = counts.get(zero_state, 0) / shots
183
+ kernel_matrix[i, j] = prob_zero
184
+
185
+ return kernel_matrix
186
+
187
+ # ===== ШАГ 6: ВЫЧИСЛЕНИЕ МАТРИЦ ЯДРА =====
188
+ print("\n" + "="*60)
189
+ print("ВЫЧИСЛЕНИЕ КВАНТОВОГО ЯДРА НА IBM_FEZ")
190
+ print("="*60)
191
+
192
+ # Для реального QPU используем меньше shots для экономии времени
193
+ shots = 1024 # Минимум для приемлемой точности
194
+
195
+ import time
196
+ start_time = time.time()
197
+
198
+ # Вычисляем матрицу ядра для обучающих данных
199
+ print(f"\n🔬 Вычисление K_train ({len(X_train)}x{len(X_train)} = {len(X_train)**2} схем)...")
200
+ K_train = compute_kernel_matrix(X_train, X_train, feature_map, backend, shots)
201
+ train_time = time.time() - start_time
202
+ print(f"⏱️ Время: {train_time:.1f} секунд")
203
+
204
+ # Вычисляем матрицу ядра для тестовых данных
205
+ print(f"\n🔬 Вычисление K_test ({len(X_test)}x{len(X_train)} = {len(X_test)*len(X_train)} схем)...")
206
+ K_test = compute_kernel_matrix(X_test, X_train, feature_map, backend, shots)
207
+ test_time = time.time() - start_time - train_time
208
+ print(f"⏱️ Время: {test_time:.1f} секунд")
209
+
210
+ total_time = time.time() - start_time
211
+ print(f"\n✅ Все матрицы ядра готовы!")
212
+ print(f"📊 Общее время выполнения: {total_time:.1f} секунд ({total_time/60:.2f} минут)")
213
+ print(f"K_train shape: {K_train.shape}")
214
+ print(f"K_test shape: {K_test.shape}")
215
+
216
+ # ===== ШАГ 7: ОБУЧЕНИЕ SVM =====
217
+ print("\n=== ОБУЧЕНИЕ SVM КЛАССИФИКАТОРА ===")
218
+
219
+ # Используем SVM с предвычисленным ядром
220
+ svm = SVC(kernel='precomputed')
221
+ svm.fit(K_train, y_train)
222
+
223
+ # Предсказание
224
+ y_pred = svm.predict(K_test)
225
+
226
+ # Оценка точности
227
+ accuracy = accuracy_score(y_test, y_pred)
228
+ print(f"\nТочность на тестовой выборке: {accuracy:.2%}")
229
+
230
+ # ===== ШАГ 8: ВИЗУАЛИЗАЦИЯ =====
231
+ print("\n=== ВИЗУАЛИЗАЦИЯ РЕЗУЛЬТАТОВ ===")
232
+
233
+ import matplotlib.pyplot as plt
234
+
235
+ fig, axes = plt.subplots(1, 2, figsize=(12, 5))
236
+
237
+ # Визуализация матрицы ядра
238
+ im1 = axes[0].imshow(K_train, cmap='hot', interpolation='nearest')
239
+ axes[0].set_title('Матрица квантового ядра (Train)')
240
+ axes[0].set_xlabel('Образец j')
241
+ axes[0].set_ylabel('Образец i')
242
+ plt.colorbar(im1, ax=axes[0])
243
+
244
+ # Визуализация предсказаний
245
+ axes[1].scatter(range(len(y_test)), y_test, c='blue',
246
+ marker='o', label='Истинные метки', s=100)
247
+ axes[1].scatter(range(len(y_pred)), y_pred, c='red',
248
+ marker='x', label='Предсказания', s=100)
249
+ axes[1].set_title('Предсказания vs Истинные метки')
250
+ axes[1].set_xlabel('Индекс образца')
251
+ axes[1].set_ylabel('Класс')
252
+ axes[1].legend()
253
+ axes[1].grid(True, alpha=0.3)
254
+
255
+ plt.tight_layout()
256
+ plt.savefig('quantum_kernel_results.png', dpi=150, bbox_inches='tight')
257
+ print("График сохранён в 'quantum_kernel_results.png'")
258
+ plt.show()
259
+
260
+ # ===== ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ =====
261
+ print("\n=== ИТОГИ ===")
262
+ print(f"Общее количество схем выполнено: {len(X_train)**2 + len(X_test)*len(X_train)}")
263
+ print(f"Shots на схему: {shots}")
264
+ print(f"Точность классификации: {accuracy:.2%}")
265
+ print(f"\nСредние значения в матрице ядра:")
266
+ print(f" K_train: min={K_train.min():.3f}, max={K_train.max():.3f}, mean={K_train.mean():.3f}")
267
+ print(f" K_test: min={K_test.min():.3f}, max={K_test.max():.3f}, mean={K_test.mean():.3f}")
268
+
269
+ # ===== СОХРАНЕНИЕ РЕЗУЛЬТАТОВ =====
270
+ print("\n=== СОХРАНЕНИЕ РЕЗУЛЬТАТОВ ===")
271
+
272
+ import pickle
273
+ import json
274
+ from datetime import datetime
275
+
276
+ # Создаём папку для результатов
277
+ import os
278
+ results_dir = "quantum_kernel_results"
279
+ os.makedirs(results_dir, exist_ok=True)
280
+
281
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
282
+
283
+ # 1. Сохраняем матрицы ядра (numpy arrays)
284
+ np.save(f'{results_dir}/K_train_{timestamp}.npy', K_train)
285
+ np.save(f'{results_dir}/K_test_{timestamp}.npy', K_test)
286
+ print(f"✅ Матрицы ядра сохранены:")
287
+ print(f" - {results_dir}/K_train_{timestamp}.npy")
288
+ print(f" - {results_dir}/K_test_{timestamp}.npy")
289
+
290
+ # 2. Сохраняем данные и метки
291
+ np.save(f'{results_dir}/X_train_{timestamp}.npy', X_train)
292
+ np.save(f'{results_dir}/X_test_{timestamp}.npy', X_test)
293
+ np.save(f'{results_dir}/y_train_{timestamp}.npy', y_train)
294
+ np.save(f'{results_dir}/y_test_{timestamp}.npy', y_test)
295
+ print(f"✅ Данные и метки сохранены")
296
+
297
+ # 3. Сохраняем обученную модель SVM
298
+ with open(f'{results_dir}/svm_model_{timestamp}.pkl', 'wb') as f:
299
+ pickle.dump(svm, f)
300
+ print(f"✅ Модель SVM сохранена: {results_dir}/svm_model_{timestamp}.pkl")
301
+
302
+ # 4. Сохраняем метаданные эксперимента
303
+ metadata = {
304
+ 'timestamp': timestamp,
305
+ 'backend': backend.name,
306
+ 'num_qubits': num_qubits,
307
+ 'shots': shots,
308
+ 'num_train_samples': len(X_train),
309
+ 'num_test_samples': len(X_test),
310
+ 'total_circuits': len(X_train)**2 + len(X_test)*len(X_train),
311
+ 'execution_time_seconds': total_time,
312
+ 'accuracy': float(accuracy),
313
+ 'feature_map': {
314
+ 'type': 'ZZFeatureMap',
315
+ 'reps': 1,
316
+ 'entanglement': 'linear'
317
+ },
318
+ 'kernel_stats': {
319
+ 'K_train_min': float(K_train.min()),
320
+ 'K_train_max': float(K_train.max()),
321
+ 'K_train_mean': float(K_train.mean()),
322
+ 'K_test_min': float(K_test.min()),
323
+ 'K_test_max': float(K_test.max()),
324
+ 'K_test_mean': float(K_test.mean()),
325
+ }
326
+ }
327
+
328
+ with open(f'{results_dir}/metadata_{timestamp}.json', 'w') as f:
329
+ json.dump(metadata, f, indent=2)
330
+ print(f"✅ Метаданные сохранены: {results_dir}/metadata_{timestamp}.json")
331
+
332
+ # 5. Сохраняем график
333
+ plt.savefig(f'{results_dir}/results_{timestamp}.png', dpi=150, bbox_inches='tight')
334
+ print(f"✅ График сохранён: {results_dir}/results_{timestamp}.png")
335
+
336
+ print(f"\n📁 Все результаты в папке: {results_dir}/")
337
+ print("\n" + "="*60)
338
+ print("КАК ИСПОЛЬЗОВАТЬ СОХРАНЁННЫЕ ДАННЫЕ:")
339
+ print("="*60)
340
+ print("""
341
+ # Загрузить матрицы ядра:
342
+ import numpy as np
343
+ K_train = np.load('quantum_kernel_results/K_train_TIMESTAMP.npy')
344
+ K_test = np.load('quantum_kernel_results/K_test_TIMESTAMP.npy')
345
+
346
+ # Загрузить обученную модель:
347
+ import pickle
348
+ with open('quantum_kernel_results/svm_model_TIMESTAMP.pkl', 'rb') as f:
349
+ svm = pickle.load(f)
350
+
351
+ # Использовать для новых предсказаний:
352
+ # 1. Вычислите квантовое ядро для но��ых данных X_new
353
+ # 2. predictions = svm.predict(K_new)
354
+
355
+ # Загрузить метаданные:
356
+ import json
357
+ with open('quantum_kernel_results/metadata_TIMESTAMP.json', 'r') as f:
358
+ metadata = json.load(f)
359
+ print(f"Точность модели: {metadata['accuracy']}")
360
+ """)
361
+
362
+ # СОВЕТЫ ПО ОПТИМИЗАЦИИ ДЛЯ IBM_FEZ:
363
+ print("\n" + "="*60)
364
+ print("ИСПОЛЬЗОВАНО НА IBM_FEZ:")
365
+ print("="*60)
366
+ print(f"✅ Образцов данных: {len(X_train) + len(X_test)}")
367
+ print(f"✅ Всего схем выполнено: {len(X_train)**2 + len(X_test)*len(X_train)}")
368
+ print(f"✅ Shots на схему: {shots}")
369
+ print(f"✅ Общее время: {total_time/60:.2f} минут")
370
+ remaining = 8 - total_time/60
371
+ print(f"✅ Оставшееся время: ~{remaining:.2f} минут")
372
+ print(f"\n📈 Статистика:")
373
+ print(f" Скорость: ~{(len(X_train)**2 + len(X_test)*len(X_train)) / total_time:.1f} схем/сек")
374
+ print(f" Среднее время на схему: ~{total_time / (len(X_train)**2 + len(X_test)*len(X_train)):.2f} сек")
375
+ if remaining > 0:
376
+ print(f"\n💡 Времени хватило! Можно было выполнить ещё ~{int(remaining * 60 / (total_time / (len(X_train)**2 + len(X_test)*len(X_train))))} схем")