J'ai posté un article avec le même contenu l'autre jour, mais je me suis endormi et je l'ai supprimé. Je suis désolé.
Cette fois, j'ai implémenté une machine quantique de Boltzmann en utilisant Qiskit. Voici le document de référence. A quantum algorithm to train neural networks using low-depth circuits De plus, la machine de Boltzmann utilisant la machine de recuit quantique est présentée dans l'article de M. minato, je voudrais donc m'en tenir à cela. Apprendre RBM Boltzmann de D-Wave à Quantum Gate Machine
On dit que les machines Boltsman restreintes sont la plus petite unité de réseaux neuronaux. À propos, l'auteur n'est pas un expert en apprentissage automatique, je vais donc laisser l'explication détaillée à d'autres personnes.
QABoM
Cet article l'introduit sous le nom d'algorithme QABoM (Quantum Approximate Boltzmann Machine). Je n'ai pas le temps d'entrer dans les détails, je voudrais donc vous présenter le flux de QABoM présenté en annexe.
L'index à utiliser est le suivant. ・ V: couche visible ・ H: couche cachée ・ U: couche visible + cachée
step 0
Define the full and partial initial Hamiltonians.
H_I = \sum_{j \in u} Z_j \\
H_{\tilde{I}} = \sum_{j \in h} Z_j
En regardant la formule, plein signifie visible + caché, et partiel signifie caché. prochain Define the full and partial mixer Hamiltonians.
H_M = \sum_{j \in u} X_j \\
H_{\tilde{M}} = \sum_{j \in h} X_j
Définissez le poids $ J_ {jk} ^ 0 $ et le biais $ B_j ^ 0 $, qui sont les variables de la machine de Boltzmann. Répétez les étapes 1 à 5 ci-dessous pour l'époque 1 et plus.
step 1
Nous définissons l'hamiltonien à coût complet et l'hamiltonien à coût partiel à l'époque n.
\hat{H}_C^n = \sum_{j,k \in u} J_{jk}^n \hat{Z}_j \hat{Z}_k + \sum_{j \in u} B_j^n \hat{Z}_j \\
\hat{H}_{\tilde{C}}^n = \sum_{j,k \in u} J_{jk}^n \hat{Z}_j \hat{Z}_k + \sum_{j \in h} B_j^n \hat{Z}_j
step 2 Unclamped Thermalization
QAOA est exécuté en utilisant les formules définies aux étapes 0 et 1.
a
Initialiser les paramètres d'impulsion-> $ \ gamma, \ beta $
b
Exécutez QAOA en utilisant $ H_M $ et $ H_C $ (Voir d'autres sites pour les commentaires QAOA ...) Trouvez le paramètre d'optimisation. Ici, la valeur attendue est calculée par $ \ hat {H} _C ^ n $.
c
Exécutez le circuit de paramètres avec le paramètre optimal entré, et trouvez les valeurs attendues $ \ <Z_j Z_k> $ et $ \ <Z_j> $.
step 3 Clamped thermalization
Pour chaque chaîne de données $ x $
a
Initialiser les paramètres d'impulsion-> $ \ gamma, \ beta $
b
Encodez $ x $ dans le calque visible.
c
Exécutez QAOA en utilisant $ H_M $ et $ H_C $ (Voir d'autres sites pour les commentaires QAOA ...) Trouvez le paramètre d'optimisation. Ici, la valeur attendue est prise par $ \ hat {H} _ {\ tilde {C}} ^ n $.
d
Exécutez le circuit de paramètres avec le paramètre optimal entré, et trouvez les valeurs attendues $ \ <Z_j Z_k> $ et $ \ <Z_j> $.
step 4
Nous mettrons à jour les paramètres. Où $ \ <\ bar {\ cdots}> _D $ est la moyenne des résultats de l'étape 3.
\delta J_{jk}^n = <\bar{Z_j Z_k}>_D -< Z_j Z_k> \\
\delta B_j^n = < \bar{Z_j}> - <Z_j>_D \\
J_j^{n+1} = J_j^n + \delta J_j^n \\
B_j^{n+1} = B_j^n + \delta B_j^n
step 5
epoch = n+1 back to step 1
code
Importation et initialisation de classe
python
# coding: utf-8
from qiskit.aqua.utils import tensorproduct
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.quantum_info.analysis import average_data
import numpy as np
from copy import deepcopy
from QAOA import QAOA
from my_functions import sigmoid
class QBM:
def __init__(self, num_visible=2, num_hidden=1, steps=3,
tmep=1.0, quant_meas_num=None, bias=False, reduced=False):
self.visible_units = num_visible # v
self.hidden_units = num_hidden # h
self.total_units = self.visible_units + self.hidden_units
self.quant_meas_num = quant_meas_num
self.qaoa_steps = steps
self.beta_temp = tmep
self.state_prep_angle = np.arctan(np.exp(-1 / self.beta_temp)) * 2.0
self.param_wb = 0.1 * np.sqrt(6. / self.total_units)
self.WEIGHTS = np.asarray(np.zeros(shape=[self.visible_units, self.hidden_units]))
if bias:
self.BIAS = np.asarray(np.zeros(shape=[self.hidden_units]))
else:
self.BIAS = None
self.reduced = reduced
self.obs = self.observable()
self.obs_tilde = self.observable(tilde=True)
self.data_point = None
Création d'observable. Vous pouvez créer $$ en définissant tilde = True.
python
def Zi_Zj(self, q1, q2):
I_mat = np.array([[1, 0], [0, 1]])
Z_mat = np.array([[1, 0], [0, -1]])
if q1 == 0 or q2 == 0:
tensor = Z_mat
else:
tensor = I_mat
for i in range(1, self.total_units):
if i == q1 or i == q2:
tensor = tensorproduct(tensor, Z_mat)
else:
tensor = tensorproduct(tensor, I_mat)
return tensor
def Zi(self, q):
I_mat = np.array([[1, 0], [0, 1]])
Z_mat = np.array([[1, 0], [0, -1]])
if q == 0:
tensor = Z_mat
else:
tensor = I_mat
for i in range(1, self.total_units):
if i == q:
tensor = tensorproduct(tensor, Z_mat)
else:
tensor = tensorproduct(tensor, I_mat)
return tensor
def observable(self, tilde=False):
visible_indices = [i for i in range(self.visible_units)]
hidden_indices = [i + self.visible_units for i in range(self.hidden_units)]
total_indices = [i for i in range(self.total_units)]
obs = np.zeros((2**self.total_units, 2**self.total_units))
for q1 in visible_indices:
for q2 in hidden_indices:
obs += -1.0 * self.Zi_Zj(q1, q2)
if self.BIAS is not None:
if tilde:
for q in hidden_indices:
obs += -1.0 * self.Zi(q)
elif not tilde:
for q in total_indices:
obs += -1.0 * self.Zi(q)
return obs
Créez le circuit de paramètres.
python
def U_circuit(self, params, qc):
visible_indices = [i for i in range(self.visible_units)]
hidden_indices = [i + self.visible_units for i in range(self.hidden_units)]
total_indices = [i for i in range(self.total_units)]
p = 2
alpha = self.state_prep_angle
for i in total_indices:
qc.rx(alpha, i)
for i in visible_indices:
for j in hidden_indices:
qc.cx(i, j)
beta, gamma = params[:p], params[p:]
def add_U_X(qc, beta):
for i in total_indices:
qc.rx(-2**beta, i)
return qc
def add_U_C(qc, gamma):
for q1 in visible_indices:
for q2 in hidden_indices:
qc.cx(q1, q2)
qc.rz(-2**gamma, q2)
qc.cx(q1, q2)
return qc
for i in range(p):
qc = add_U_C(qc, gamma[i])
qc = add_U_X(qc, beta[i])
return qc
Exécutez l'étape 2.
python
def unclamped_circuit(self, params):
qr = QuantumRegister(self.total_units)
cr = ClassicalRegister(self.total_units)
qc = QuantumCircuit(qr, cr)
qc = self.U_circuit(params, qc)
qc.measure(range(self.total_units), range(self.total_units))
return qc
def make_unclamped_QAOA(self):
qaoa = QAOA(qc=self.unclamped_circuit, observable=self.obs, num_shots=10000, p=2)
counts = qaoa.qaoa_run()
return counts
J'utilise ici une bibliothèque auto-créée appelée QAOA, mais je la présenterai ci-dessous. Vient ensuite l'étape 3. La différence avec l'étape 2 est que le code des données est inclus.
python
def clamped_circuit(self, params):
qr = QuantumRegister(self.total_units)
cr = ClassicalRegister(self.total_units)
qc = QuantumCircuit(qr, cr)
for i in range(len(self.data_point)):
if self.data_point[i] == 1:
qc.x(i)
qc = self.U_circuit(params, qc)
qc.measure(range(self.total_units), range(self.total_units))
return qc
def make_clamped_QAOA(self, data_point):
self.data_point = data_point
qaoa = QAOA(qc=self.clamped_circuit, observable=self.obs_tilde, num_shots=10000, p=2)
counts = qaoa.qaoa_run()
return counts
Enfin, l'exécution de l'apprentissage.
python
def train(self, DATA, learning_rate=1, n_epochs=100, quantum_percentage=1.0, classical_percentage=0.0):
assert (quantum_percentage + classical_percentage == 1.0)
DATA = np.asarray(DATA)
assert (len(DATA[0]) <= self.visible_units)
for epoch in range(n_epochs):
print('Epoch: {}'.format(epoch+1))
visible_indices = [i for i in range(self.visible_units)]
hidden_indices = [i + self.visible_units for i in range(self.hidden_units)]
total_indices = [i for i in range(self.total_units)]
new_weights = deepcopy(self.WEIGHTS)
if self.BIAS is not None:
new_bias = deepcopy(self.BIAS)
counts = self.make_unclamped_QAOA()
unc_neg_phase_quant = np.zeros_like(self.WEIGHTS)
for i in range(self.visible_units):
for j in range(self.hidden_units):
model_expectation = average_data(counts, self.Zi_Zj(visible_indices[i], hidden_indices[j]))
unc_neg_phase_quant[i][j] = model_expectation
unc_neg_phase_quant *= (1. / float(len(DATA)))
if self.BIAS is not None:
unc_neg_phase_quant_bias = np.zeros_like(self.BIAS)
for i in range(self.hidden_units):
model_expectation = average_data(counts, self.Zi(hidden_indices[i]))
unc_neg_phase_quant_bias[i] = model_expectation
unc_neg_phase_quant_bias *= (1. / float(len(DATA)))
pos_hidden_probs = sigmoid(np.dot(DATA, self.WEIGHTS))
pos_hidden_states = pos_hidden_probs > np.random.rand(len(DATA), self.hidden_units)
pos_phase_classical = np.dot(DATA.T, pos_hidden_probs) * 1. / len(DATA)
c_pos_phase_quant = np.zeros_like(self.WEIGHTS)
if self.BIAS is not None:
c_pos_phase_quant_bias = np.zeros_like(self.BIAS)
if not self.reduced:
iter_dat = len(DATA)
pro_size = len(DATA)
pro_step = 1
for data in DATA:
counts = self.make_clamped_QAOA(data)
ct_pos_phase_quant = np.zeros_like(self.WEIGHTS)
for i in range(self.visible_units):
for j in range(self.hidden_units):
model_expectation = average_data(counts, self.Zi_Zj(visible_indices[i], hidden_indices[j]))
ct_pos_phase_quant[i][j] = model_expectation
c_pos_phase_quant += ct_pos_phase_quant
if self.BIAS is not None:
ct_pos_phase_quant_bias = np.zeros_like(self.BIAS)
for i in range(self.hidden_units):
model_expectation = average_data(counts, self.Zi(hidden_indices[i]))
ct_pos_phase_quant_bias[i] = model_expectation
c_pos_phase_quant_bias *= ct_pos_phase_quant_bias
pro_bar = ('==' * pro_step) + ('--' * (pro_size - pro_step))
print('\r[{0}] {1}/{2}'.format(pro_bar, pro_step, pro_size), end='')
pro_step += 1
c_pos_phase_quant *= (1. / float(len(DATA)))
if self.BIAS is not None:
c_pos_phase_quant_bias *= (1. / float(len(DATA)))
neg_visible_activations = np.dot(pos_hidden_states, self.WEIGHTS.T)
neg_visible_probs = sigmoid(neg_visible_activations)
neg_hidden_activations = np.dot(neg_visible_probs, self.WEIGHTS)
neg_hidden_probs = sigmoid(neg_hidden_activations)
neg_phase_classical = np.dot(
neg_visible_probs.T, neg_hidden_probs) * 1. / len(DATA)
new_weights += learning_rate * \
(classical_percentage * (pos_phase_classical - neg_phase_classical) +
quantum_percentage * (c_pos_phase_quant - unc_neg_phase_quant))
if self.BIAS is not None:
new_bias = new_bias + learning_rate * \
(quantum_percentage * (c_pos_phase_quant_bias - unc_neg_phase_quant_bias))
self.WEIGHTS = deepcopy(new_weights)
print(self.WEIGHTS)
if self.BIAS is not None:
self.BIAS = deepcopy(new_bias)
with open("RBM_info.txt", "w") as f:
np.savetxt(f, self.WEIGHTS)
if self.BIAS is not None:
np.savetxt(f, self.BIAS)
with open("RBM_history.txt", "a") as f:
np.savetxt(f, self.WEIGHTS)
if self.BIAS is not None:
np.savetxt(f, self.BIAS)
f.write(str('*' * 72) + '\n')
print('')
print("Training Done! ")
def transform(self, DATA):
return sigmoid(np.dot(DATA, self.WEIGHTS))
if __name__ == '__main__':
qbm = QBM(num_visible=6, num_hidden=2,bias=True)
train_data = [[1, 1, 1, 1, 1, 1],
[1, 1, -1, -1, 1, 1], [1, -1, -1, -1, 1, 1], [1, 1, 1, -1, -1, -1]]
qbm.train(DATA=train_data, n_epochs=100, quantum_percentage=1.0, classical_percentage=0.0)
print(qbm.transform(train_data))
QAOA
La bibliothèque QAOA est une extension à usage général du code utilisé dans [Implémentation de QAOA sans Qiskit Aqua] précédemment introduite (https://qiita.com/hotaru_46/items/c4b51e3038d260ef1fc8).
QAOA.py
# coding: utf-8
from qiskit import BasicAer, execute
from qiskit.quantum_info.analysis import average_data
from scipy.optimize import minimize
import numpy as np
import random
def classica_minimize(cost_func, initial_params, options, method='powell'):
result = minimize(cost_func, initial_params, options=options, method=method)
return result.x
class QAOA:
def __init__(self, qc, observable, num_shots, p=1, initial_params=None):
self.QC = qc
self.obs = observable
self.SHOTS = num_shots
self.P = p
if initial_params is None:
self.initial_params = [0.1 for _ in range(self.P * 2)]
else:
self.initial_params = initial_params
def QAOA_output_layer(self, params):
qc = self.QC(params)
backend = BasicAer.get_backend('qasm_simulator')
results = execute(qc, backend, shots=self.SHOTS).result()
counts = results.get_counts(qc)
expectation = average_data(counts, self.obs)
return expectation
def minimize(self):
initial_params = np.array(self.initial_params)
opt_params = classica_minimize(self.QAOA_output_layer, initial_params,
options={'maxiter':500}, method='powell')
return opt_params
def qaoa_run(self):
opt_params = self.minimize()
qc = self.QC(opt_params)
backend = BasicAer.get_backend('qasm_simulator')
results = execute(qc, backend, shots=self.SHOTS).result()
counts = results.get_counts(qc)
return counts
if __name__ == '__main__':
pass
Cette fois, nous avons mené des expériences informatiques en utilisant les mêmes données sur la machine classique de Boltzmann restreinte et les avons comparées. La machine Boltzmann classique restreinte a été implémentée par une autre personne, je l'ai donc utilisée comme référence. Implémentation de la machine de contrainte Boltzmann avec python
OS: macOS Catalina ver 10.15.5 CPU: intel Core i7 Mémoire: 16 Go
Taux d'apprentissage: 0,2 epochs: 100
[[7.57147606e-220 4.69897282e-106]
[1.00548918e-308 1.00000000e+000]
[1.00000000e+000 3.79341879e-197]
[1.00000000e+000 7.56791638e-202]
[1.00000000e+000 2.85625356e-196]
[1.00000000e+000 2.51860403e-243]
[0.00000000e+000 1.00000000e+000]
[9.02745172e-142 1.00000000e+000]]
[[0.59991237 0.68602485]
[0.74497707 0.89553788]
[0.26436565 0.113528 ]
[0.2682931 0.1131361 ]
[0.58273232 0.3268427 ]
[0.41413436 0.14647751]
[0.74056361 0.94317095]
[0.7317069 0.8868639 ]]
Soit dit en passant, cela prend presque une demi-journée à calculer. (J'ai oublié de mesurer ...) Pour le moment, le même résultat que le RBM classique a été obtenu. Cependant, la solution n'est pas aussi claire que la solution classique.
Cette fois, j'ai présenté l'implémentation de QABoM qui a été publiée dans le journal. Je pense que je vais faire un peu plus d'expériences informatiques et mettre à jour l'article.
Je suis désolé pour mon pauvre japonais. Nous nous efforcerons d'améliorer nos compétences linguistiques.
QABoM: A quantum algorithm to train neural networks using low-depth circuits RBM: Implémentation de la machine de contrainte Boltzmann avec python
Recommended Posts