はじめに
人工ニューロンを量子回路で実現しようという論文があったので私も実装してみました.
An artificial neuron implemented on actual quantum processor
m qubitsを用いた場合,$2^m$次元の入力を扱えるようになるらしいです.
ここでは,シグモイド関数等の活性化関数を作用させる手前までの計算を行います.
軽い解説
入力ベクトル$\vec{i}$と重みベクトル$\vec{w}$を以下のように定義します.
\vec{i} = (i_0, i_1, \cdots,i_{m-1}) \\ \vec{w} = (w_0, w_1, \cdots, w_{m-1})
ただし,$i_j , w_j \in {-1, 1}$とする.
ここで,二つの量子状態を考える.
|\psi_i> = \frac{1}{\sqrt{m}} \sum_{j=0}^{m-1} i_j|j> \\
|\psi_w> = \frac{1}{\sqrt{m}} \sum_{j=0}^{m-1} w_j|j>
ただし,$|j> = {|0>, |1>, \cdots, |m-1>}$とする.
また,$U_i$と$U_w$を次のように定義する.
U_i |0>^{\otimes N} = |\psi_i> \\
U_w |\psi_i> = |1>^{\otimes N} = |m-1> \\
U_w|\psi_i> = \sum_{j=0}^{m-1} c_j |j> \equiv |\phi_{i,w} >
2つの量子状態の内積を求めると,
<\psi_w|\psi_i> = <\psi_w|U_w^{\dagger} U_w|\psi_i>=<m-1|\phi_{i,w}> = c_{m-1}
ancilla bitを追加し,それをtarget bitにしたmulti-controlled NOT gateを作用させると
|\phi_{i,w}>|0>_a = \sum_{j=0}^{m-2} c_j |j>|0>_a + c_{m-1}|m-1>|1>_a
code
$U_i$と$U_w$の作成にはQuantum Hypergraph stateを用いています.
# coding: utf-8
from quantum_hypergraph_state import QuantumHypergraphState
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, execute
from qiskit import BasicAer
import numpy as np
class QuantumNeuron:
def __init__(self, using_qubits, input, weight):
self.num_of_input = using_qubits
self.index = [i for i in range(self.num_of_input)]
self.input = input
self.weight = weight
self.qr = QuantumRegister(self.num_of_input, name='qubits') # input qubits and ancilla bit
self.target = QuantumRegister(1, name='target_bit')
self.qc = QuantumCircuit(self.qr, self.target)
def construct_circuit(self):
inputs = QuantumHypergraphState(self.num_of_input, self.input)
inputs.construct_circuit(self.qc)
weight = QuantumHypergraphState(self.num_of_input, self.weight)
weight.construct_circuit(self.qc, inverse=True)
ancilla_qubits = QuantumRegister(1)
classical = ClassicalRegister(1)
self.qc.add_register(ancilla_qubits)
self.qc.add_register(classical)
self.qc.mct([self.qr[i] for i in range(self.num_of_input)],
self.target[0],
q_ancilla=[ancilla_qubits[i] for i in range(1)])
self.qc.measure(self.target[0], classical[0])
def print_details(self, draw=False):
print('num_of_input: {}'.format(self.num_of_input))
print('index: {}'.format(self.index))
if draw:
print(self.qc.draw())
if __name__ == '__main__':
num_qubits = 2
sample = QuantumNeuron(num_qubits, input=[1, 1, 1, 1], weight=[1, 1, -1, -1])
sample.construct_circuit()
NUM_SHOTS = 10000
seed = 1234
backend = BasicAer.get_backend('qasm_simulator')
results = execute(sample.qc, backend=backend, shots=NUM_SHOTS, seed_simulator=seed).result()
sample.print_details()
counts = results.get_counts()
print(np.sqrt(counts['1'] / NUM_SHOTS) * 2**num_qubits)