[PYTHON] Qiskit: Implementierung einer Quantenbolzenmaschine

Einführung

Ich habe neulich einen Artikel mit dem gleichen Inhalt gepostet, bin aber eingeschlafen und habe ihn gelöscht. Es tut mir Leid.

Dieses Mal habe ich eine Quanten-Boltzmann-Maschine mit Qiskit implementiert. Hier ist das Nachschlagewerk. A quantum algorithm to train neural networks using low-depth circuits Auch die Boltzmann-Maschine, die die Quantenglühmaschine verwendet, wird in dem Artikel von Herrn Minato vorgestellt, deshalb möchte ich es dem überlassen. RBM Boltzmann Lernen von D-Wave zu Quantum Gate Machine

Eingeschränkte Boltsman-Maschinen sollen die kleinste Einheit neuronaler Netze sein. Der Autor ist übrigens kein Experte für maschinelles Lernen, daher überlasse ich die ausführliche Erklärung anderen.

QABoM

In diesem Artikel wird es als QABoM-Algorithmus (Quantum Approximate Boltzmann Machine) vorgestellt. Ich habe keine Zeit, auf die Details einzugehen, daher möchte ich den im Anhang vorgestellten QABoM-Ablauf vorstellen.

Der zu verwendende Index lautet wie folgt. ・ V: sichtbare Schicht ・ H: versteckte Schicht ・ U: sichtbare + versteckte Ebene

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 

Bei Betrachtung der Formel geht es bei full um sichtbar + versteckt und bei partiell um versteckt. Nächster Define the full and partial mixer Hamiltonians.

H_M = \sum_{j \in u} X_j \\
H_{\tilde{M}} = \sum_{j \in h} X_j 

Definieren Sie das Gewicht $ J_ {jk} ^ 0 $ und das Bias $ B_j ^ 0 $, die die Variablen der Boltzmann-Maschine sind. Wiederholen Sie die unten gezeigten Schritte 1 bis 5 für Epoche 1 und höher.

step 1

Wir definieren Hamiltonian mit Vollkosten und Hamiltonian mit Teilkosten in Epoche 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 wird unter Verwendung der in Schritt 0 und Schritt 1 definierten Formeln ausgeführt.

a

Initialisieren Sie die Impulsparameter-> $ \ gamma, \ beta $

b

Führen Sie QAOA mit $ H_M $ und $ H_C $ aus (Siehe andere Websites für QAOA-Kommentare ...) Suchen Sie den Optimierungsparameter. Hier wird der erwartete Wert mit $ \ hat {H} _C ^ n $ berechnet.

c

Führen Sie die Parameterschaltung mit dem eingegebenen optimalen Parameter aus und suchen Sie die erwarteten Werte $ \ <Z_j Z_k> $ und $ \ <Z_j> $.

step 3 Clamped thermalization

Für jede Datenzeichenfolge $ x $

a

Initialisieren Sie die Impulsparameter-> $ \ gamma, \ beta $

b

Codiere $ x $ in der sichtbaren Ebene.

c

Führen Sie QAOA mit $ H_M $ und $ H_C $ aus (Siehe andere Websites für QAOA-Kommentare ...) Suchen Sie den Optimierungsparameter. Hier wird der erwartete Wert von $ \ hat {H} _ {\ tilde {C}} ^ n $ übernommen.

d

Führen Sie die Parameterschaltung mit dem eingegebenen optimalen Parameter aus und suchen Sie die erwarteten Werte $ \ <Z_j Z_k> $ und $ \ <Z_j> $.

step 4

Wir werden die Parameter aktualisieren. Wobei $ \ <\ bar {\ cdots}> _D $ der Durchschnitt der Ergebnisse von Schritt 3 ist.

\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

Import und Klasseninitialisierung

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

Schaffung von beobachtbaren. Sie können $$ erstellen, indem Sie tilde = True setzen.

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

Erstellen Sie die Parameterschaltung.

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

Führen Sie Schritt 2 aus.

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

Ich verwende hier eine selbst erstellte Bibliothek namens QAOA, aber ich werde sie unten vorstellen. Als nächstes folgt Schritt 3. Der Unterschied zu Schritt 2 besteht darin, dass der Code der Daten enthalten ist.

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

Schließlich die Ausführung des Lernens.

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

Die selbst erstellte Bibliothek QAOA ist eine universelle Erweiterung des Codes, der in der zuvor eingeführten Implementierung von QAOA ohne Qiskit Aqua verwendet wurde.

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

Berechnungsergebnis

Dieses Mal haben wir Computerexperimente mit denselben Daten auf der klassischen eingeschränkten Boltzmann-Maschine durchgeführt und diese verglichen. Die klassische eingeschränkte Boltzmann-Maschine wurde von einer anderen Person implementiert, daher habe ich sie als Referenz verwendet. Implementierung der Constraint-Boltzmann-Maschine mit Python

Ausführungsumgebung

OS: macOS Catalina ver 10.15.5 CPU: intel Core i7 Speicher: 16 GB

Parameter

Lernrate: 0,2 epochs: 100

Ergebnisse der klassischen Boltzmann-Maschine

[[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]]

QABoM-Ergebnisse

[[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 ]]

Die Berechnung dauert übrigens fast einen halben Tag. (Ich habe vergessen zu messen ...) Vorerst wurde das gleiche Ergebnis wie beim klassischen RBM erzielt. Die Lösung ist jedoch nicht so klar wie die klassische.

Zusammenfassung

Dieses Mal stellte ich die Implementierung von QABoM vor, die in dem Papier veröffentlicht wurde. Ich denke, ich werde ein bisschen mehr Computerexperimente machen und den Artikel aktualisieren.

Es tut mir leid für mein armes Japanisch. Wir werden uns bemühen, unsere Sprachkenntnisse zu verbessern.

Referenzenliste

QABoM: A quantum algorithm to train neural networks using low-depth circuits RBM: Implementierung einer Constraint-Boltzmann-Maschine mit Python

Recommended Posts

Qiskit: Implementierung einer Quantenbolzenmaschine
Qiskit: Implementierung von Quantenhypergraphzuständen
Qiskit: Implementierung von Quantum Circuit Learning (QCL)
Quantum Computer Implementierung von Quantum Walk 2
Quantum Computer Implementierung von Quantum Walk 3
Quantum Computer Implementierung von Quantum Walk 1
Quantencomputer-Implementierung eines 3-Zustands-Quantenlaufs
[Mit einfacher Erklärung] Scratch-Implementierung einer Deep Boltsman-Maschine mit Python ②
[Mit einfacher Erklärung] Scratch-Implementierung einer tiefen Boltzmann-Maschine mit Python ①
Qiskit: Implementierung von QAOA ohne Qiskit Aqua
Algorithmus für maschinelles Lernen (Implementierung einer Klassifizierung mit mehreren Klassen)
[Coding Interview] Implementierung der Enigma-Kryptografiemaschine (Python)
Qiskit: Realisierung künstlicher Neuronen mit Quantenschaltungen (Implementierung)
Quantenteleportation mit Qiskit!
Über das Testen bei der Implementierung von Modellen für maschinelles Lernen
Implementierung der Fibonacci-Sequenz
Qiskit: Quanten-Fourier-Transformation
Implementierung von TF-IDF mit Gensim
Implementierung von MathJax auf Sphinx
Grundlagen des maschinellen Lernens (Denkmal)
Erklärung und Implementierung von SocialFoceModel
Implementierung der Spieltheorie - Gefangenendilemma -
Implementierung einer unabhängigen Komponentenanalyse
Python-Implementierung des Partikelfilters
Bedeutung von Datensätzen für maschinelles Lernen
Implementierung der schnellen Sortierung in Python
Tiefes Lernen der Verstärkung 2 Implementierung des Lernens der Verstärkung
Implementierung von Scale-Space für SIFT