らんだむな記憶

blogというものを体験してみようか!的なー

Qiskit (57) —量子機械学習

書籍付属コードの追跡を断念することにしたので、代わりに textbook の Hybrid quantum-classical Neural Networks with PyTorch and Qiskit を見ていく。最初のほうの話は既知なので、2. So How Does Quantum Enter the Picture? の冒頭から眺める。

入力 $x$ を古典的ニューラルネット $h_1 = \sigma(W_1 x)$, $h_2 = \sigma(W_2 x)$ を得る。これを量子回路に投入し、

$$
\begin{align*}
R_y(h_1) \ket{\psi_1} \otimes R_y(h_2) \ket{\psi_2}
\end{align*}
$$

を古典ビットで測定する。観測された確率を $h_3$, $h_4$ とする時、これを古典ニューラルネットに投入し、

$$
\begin{align*}
y = \sigma\left(W_3 \begin{pmatrix}h_3 \\ h_4 \end{pmatrix}\right)
\end{align*}
$$

を得る。という話になっている。実際のコードは古典ニューラルネット部分で畳み込み層を使っていたりするし、$h_1$ と $h_2$ という 2 個の出力ではなく単一の出力であり、その出力を量子回路に投入しているので少し違うのだが、本質的な流れは上記の通りである。
なお、量子回路による層は “回転角” を特徴量として受け取って、状態の確率振幅を次の特徴量として出力するという作りになっている。

What about backpropagation? で妙な式が突然出てくるが、これがパラメータシフト則 - らんだむな記憶で見ておいたパラメータシフト則による偏微分の(断片の)計算である。

さて、コードを確認していく。古典ニューラルネット部分はよくあるやつなのでスキップして、量子回路層を眺めていこう。

class Hybrid(nn.Module)

  • 量子回路層のクラス定義である。
  • class Net(nn.Module) からの使われ方を眺めると shift=np.pi / 2 が渡っており、パラメータソフト則にマッチした値であることが分かる。
  • ショット数は 100 であるが、あまり多くするとこの層での forward が重くなるのでこの辺はトレードオフか?
順伝播
  • HybridFunction.forward で、input[[0.0252]] のような tensor がやってきて、expectation_z としては [0.5965] のようなものを返すことになる。
  • QuantumCircuit.run では、古典ニューラルネットから受け取った角度として thetas = [0.18231424689292908] などが来る。
  • $R_y(\theta) H \ket{0} = \frac{\cos \frac{\theta}{2} - \sin \frac{\theta}{2}}{\sqrt{2}} \ket{0} + \frac{\sin \frac{\theta}{2} + \cos \frac{\theta}{2}}{\sqrt{2}} \ket{1}$ を測定し結果を得る。
    • 例えば [1193 807] で、確率に換算すると [0.5965 0.4035] である。
    • 状態としては例えば、[1. 0.] が得られる。
  • 戻り値としては状態を整数と見た時にどの整数が観測されたかの期待値を返す。(結局は $\ket{1}$ の観測確率が返る。)
>>> zero = np.array([1,0])
>>> one = np.array([0,1])
>>> theta = 0.18231424689292908
>>> Ry = np.array([[math.cos(theta/2), -math.sin(theta/2)], [math.sin(theta/2), math.cos(theta/2)]])
>>> state = Ry@((zero+one)/math.sqrt(2))
>>> state
array([0.63980233, 0.76853951])
>>> state ** 2
array([0.40934703, 0.59065297])

なので大体合っているだろう。(100 ショットくらいではズレが大きくて、2000 ショットくらいにするとそこそこ合う。上記は 2000 ショットで試した。)

  • Net.forward としては上記期待値を受けて、torch.cat((x, 1 - x), -1) で再び 1 の観測確率と 0 の観測確率に戻して返す。(通常は softmax 関数で各クラスの期待値を返すところをベタに書いていると思えば良い。)
逆伝播
  • パラメータシフトした量子回路から期待値を取得し、パラメータシフト則で “偏微分の断片” を計算する。
  • 偏微分の断片” とより後方のネットワークからの偏微分を掛け合わせて返す。

と、素直に実装されていることが分かった。