PennyLane 初級 Tutorials : 基本チュートリアル : 量子回転 (翻訳)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/17/2019
* 本ページは、PennyLane : Tutorials : Learn PennyLane の次のページを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
$$
\def\bra#1{\mathinner{\left\langle{#1}\right|}}
\def\ket#1{\mathinner{\left|{#1}\right\rangle}}
\def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}}
$$
初級 Tutorials : 基本チュートリアル : 量子回転
PennyLane が量子関数の容易な構築と最適化をどのように可能にするかを見るために、量子回転 の単純なケースを考えましょう、‘Hello, world!’ サンプルの PennyLane バージョンです。
手元のタスクはシングル量子ビットを状態 $\ket{0}$ から状態 $\ket{1}$ へ反転するために 2 つの回転ゲートを最適化することです。
量子回路
量子ビット回転サンプルでは、次の量子回路を実装することを望みます :
これをステップ毎に分解します、最初に基底状態 $|0\rangle = \begin{bmatrix}1 & 0 \end{bmatrix}^T$ にある量子ビットから始めます、そしてそれを次のゲートを適用することにより x-軸回りに回転します :
$$\begin{split}R_x(\phi_1) = e^{-i \phi_1 \sigma_x /2} =
\begin{bmatrix} \cos \frac{\phi_1}{2} & -i \sin \frac{\phi_1}{2} \\
-i \sin \frac{\phi_1}{2} & \cos \frac{\phi_1}{2}
\end{bmatrix},\end{split}$$
そしてそれから次のゲートを通して y-軸回りに (回転します) :
$$\begin{split}R_y(\phi_2) = e^{-i \phi_2 \sigma_y/2} =
\begin{bmatrix} \cos \frac{\phi_2}{2} & – \sin \frac{\phi_2}{2} \\
\sin \frac{\phi_2}{2} & \cos \frac{\phi_2}{2}
\end{bmatrix}.\end{split}$$
これらの演算の後、量子ビットは今では次の状態にあります :
$$| \psi \rangle = R_y(\phi_2) R_x(\phi_1) | 0 \rangle.$$
最後に、Pauli-Z 演算子の期待値 $\langle \psi \mid \sigma_z \mid \psi \rangle$ を測定します :
$$\begin{split}\sigma_z =
\begin{bmatrix} 1 & 0 \\
0 & -1
\end{bmatrix}.\end{split}$$
正確な期待値を計算するために上を使用して、次を見出します :
$$\langle \psi \mid \sigma_z \mid \psi \rangle
= \langle 0 \mid R_x(\phi_1)^\dagger R_y(\phi_2)^\dagger \sigma_z R_y(\phi_2) R_x(\phi_1) \mid 0 \rangle
= \cos(\phi_1)\cos(\phi_2).$$
回路パラメータ $\phi_1$ と $\phi_2$ に依拠して、出力期待 (値) は 1 (if $\left|\psi\right\rangle = \left|0\right\rangle$) と -1 (if $\left|\psi\right\rangle = \left|1\right\rangle$) の間にあります。PennyLane を使用してこの回路をどのように容易に実装して最適化できるかを見ましょう。
PennyLane と NumPy をインポートします
最初に行なわければならないことは PennyLane、そして PennyLane により提供される NumPy のラップされたバージョンをインポートすることです。
import pennylane as qml from pennylane import numpy as np
Important
PennyLane でハイブリッド量子/古典的計算モデルを構築するとき、標準 NumPy ではなく、常に PennyLane から NumPy をインポートする ことは重要です!
PennyLane により提供される NumPy のラップされたバージョンをインポートすることにより、NumPy のパワーを PennyLane と結び付けられます :
- 貴方が知りそして好きな、古典的な NumPy 関数と配列を使用し続けられます
- (量子ハードウェア/シミュレータ上で評価される) 量子関数と (NumPy により提供される) 古典的関数を結び付けられます
- PennyLane に古典的そして量子関数の両者の勾配を自動的に計算することを可能にします
デバイスを作成する
量子ノードを構築できる前に、デバイスを初期化する必要があります。
定義
量子演算を適用して、測定値を返すことができる任意の計算オブジェクトを量子 デバイス と呼称します。
PennyLane では、デバイスは (PennyLane-PQ プラグインを通した、IBM QX4 のような) ハードウェアデバイスか、(PennyLane-SF プラグインを通した、Strawberry Fields のような) ソフトウェアシミュレータであり得るでしょう。
PennyLane ではデバイスは関数 device() を通してロードされます。
◆ PennyLane は量子計算の量子ビットモデルを使用するデバイスと、量子計算の CV モデルを使用するデバイスの両者をサポートします。実際には、量子ビットと CV 量子ノードの両者を含むハイブリッド計算でさえ可能です ; より詳細については hybrid computation example を見てください。
このチュートリアルのためには、量子ビットモデルを使用していますので、PennyLane により提供される ‘default.qubit’ デバイスを初期化しましょう ; 単純な純粋状態量子ビットシミュレータです。
dev1 = qml.device("default.qubit", wires=1)
総てのデバイスについて、device() は以下の引数を受け取ります :
- name: ロードされるデバイスの名前
- wires: それでデバイスを初期化するためのサブシステムの数
ここでは、このサンプルのためにシングル量子ビットを必要とするだけですので、wires=1 と設定します。
QNode を構築する
デバイスを初期化した今、量子ノード (or QNode) を構築し始めることができます。
定義
QNode は量子関数の抽象カプセル化で、量子回路により記述されます。QNode は特定の量子デバイスにバインドされます、これは回路の期待値と分散を評価するために使用されます。
QNode は QNode クラスを通して、または提供される qnode decorator を使用して構築できます。
◆ 最初に、QNode 内で評価される量子関数を定義する必要があります :
def circuit(params): qml.RX(params[0], wires=0) qml.RY(params[1], wires=0) return qml.expval(qml.PauliZ(0))
これは単純な回路で、上で説明されたものに適合しています。関数 circuit() はそれが任意の他の Python 関数であるように構築されていることに気が付くでしょう ;それは位置引数 params を受け取ります、これはリスト、タプル、あるいは配列かもしれません、そしてゲート・パラメータのための個々の要素を使用します。
けれども、量子関数は Python 関数の 制限されたサブセット です。Python 関数がまた正当な量子関数であるためには、幾つかの重要な制限があります :
- 量子関数は量子演算だけを含まなければなりません、1 行毎に 1 つの演算、それらが適用される順序で。
加えて、wires 引数を渡すことにより、演算が適用するサブシステムを常に指定しなければなりません ; これはリストか整数で良いです、演算がその上で動作する wire が幾つかに依拠して。
量子演算の完全なリストについては、supported operations を見てください。
- 量子関数は測定された観測可能量のシングルかタプルを返さなければなりません。
その結果、量子関数は常に古典的な量を返し、QNode が他の古典的関数 (そしてまた他の QNode) と相互作用することを可能にします。
観測可能量の完全なリストについては、ドキュメント を見てください。ドキュメントはまたサポートされる 測定 return 型 の詳細も提供します。
量子観測可能量 の完全なリスト、そしてまたサポートされる 測定 return 型 を見てください。
- 量子関数は回路パラメータの任意の古典的処理を含んではなりません。
Note
ある特定のデバイスは利用可能な PennyLane の演算/観測可能量のサブセットだけをサポートするかもしれません、あるいは追加の演算/観測可能量を提供さえもするかもしれません。より詳細はプラグイン/デバイスについてのドキュメントを参考にしてください。
◆ ひとたび量子関数を書けば、関数定義の 上に直接 qnode デコレータを適用することによりそれをデバイス dev1 上で動作する QNode へ変換します :
@qml.qnode(dev1) def circuit(params): qml.RX(params[0], wires=0) qml.RY(params[1], wires=0) return qml.expval(qml.PauliZ(0))
こうして、今では circuit() 量子関数は QNode であり、これはそれが評価されるたびにデバイス dev1 上で実行されます。
評価するためには、ある適切な数値入力とともに単純に関数を呼び出します :
print(circuit([0.54, 0.12]))
0.8515405859048367
量子勾配を計算する
QNode 内にカプセル化された関数 circuit の勾配は、関数自身を評価するために使用したのと同じ量子デバイス (dev1) を利用して評価できます。
PennyLane は解析的微分と、(有限差分法のような) 数値的方法の両者を組み込んでいます。これらの両者は自動的に成されます。
組込み grad() 関数を使用して微分できます。これは、回路の勾配 (i.e., 偏導関数のベクトル) を表わすもう一つの関数を返します。勾配は元の関数と同じ方法で評価できます :
dcircuit = qml.grad(circuit, argnum=0)
関数 grad() 自身は、argnum で指定された引数に関する QNode の導関数を表わす関数を返します。この場合は、関数回路は 1 つの引数 (params) を取るので、argnum=0 を指定します。引数は 2 つの要素を持つので、返された勾配は 2-次元です。それからパラメータ空間の任意のポイントでこの勾配関数を評価することができます。
print(dcircuit([0.54, 0.12]))
[-0.5104386525165021, -0.10267819945693202]
引数についてのノート
Python 関数の制限されたサブセットである量子回路関数はまた複数の位置引数とキーワード引数を利用できます。例えば、一つの配列引数の代わりに、2 つの位置引数を使用して、上の量子回路関数を定義できたでしょう :
@qml.qnode(dev1) def circuit2(phi1, phi2): qml.RX(phi1, wires=0) qml.RY(phi2, wires=0) return qml.expval(qml.PauliZ(0))
そのような関数のために勾配を計算するとき、argnum の使用は少し異なります。この場合、argnum=0 は最初のパラメータ (phi1) だけに関する勾配を返し、そして argnum=1 は phi2 のための勾配を与えます。両者のパラメータに関する勾配を得るためには、argnum=[0,1] を使用することができます :
dcircuit = qml.grad(circuit2, argnum=[0, 1]) print(dcircuit(0.54, 0.12))
(array(-0.51043865), array(-0.1026782))
キーワード引数はまた貴方のカスタム量子関数で使用されるかもしれません。PennyLane はキーワード引数に関して QNode を微分しません ので、それらは貴方の QNode に外部データを渡すために有用です。
最適化
定義
デフォルト NumPy/Autograd インターフェイスを使用する場合、PennyLane は勾配降下に基づく optimizer のコレクションを提供します。これらの optimizer はコスト関数と初期パラメータを受け取り、そして勾配降下を遂行するために PennyLane の自動微分を活用します。
詳細と利用可能な optimizer のドキュメントについては pennylane.optimize を見てください。
◆ 次に、元々状態 $\left|0\right\rangle$ にある量子ビットが状態 $\left|1\right\rangle$ にあるように回転されるように、2 つの回路パラメータ $\phi_1$ と $\phi_2$ を最適化するために PennyLane の組込み optimizer を利用します。これは $-1$ の Pauli-Z 期待値を測定することと同値です、何故ならば状態 $\left|1\right\rangle$ は固有値 $\lambda=-1$ を持つ Pauli-Z 行列の固有ベクトルだからです。
換言すれば、最適化手続きは Bloch 球上の次の回転という結果を生じる重み $\phi_1$ と $\phi_2$ を見つけます :
そのために、コスト 関数を定義する必要があります。コスト関数を最小化することにより、optimizer は望まれる結果を生成する回路パラメータの値を決定します。
この場合、望まれる結果は $-1$ の Pauli-Z 期待値です。Pauli-Z 期待値は [-1, 1] の間に束縛されることを知っていますので、コストを QNode の出力として直接定義できます :
def cost(var): return circuit(var)
最適化を始めるために、$\phi_1$ と $\phi_2$ の小さい初期値を選択しましょう :
init_params = np.array([0.011, 0.012]) print(cost(init_params))
0.9998675058299389
これらの初期パラメータ値について、コスト関数は $1$ に近いことを見て取れます。
最後に、回路パラメータを更新するために 100 ステップの間 optimizer を使用します。組込み GradientDescentOptimizer クラスを利用できます :
# initialise the optimizer opt = qml.GradientDescentOptimizer(stepsize=0.4) # set the number of steps steps = 100 # set the initial parameter values params = init_params for i in range(steps): # update the circuit parameters params = opt.step(cost, params) if (i + 1) % 5 == 0: print("Cost after step {:5d}: {: .7f}".format(i + 1, cost(params))) print("Optimized rotation angles: {}".format(params))
Cost after step 5: 0.9961778 Cost after step 10: 0.8974944 Cost after step 15: 0.1440490 Cost after step 20: -0.1536720 Cost after step 25: -0.9152496 Cost after step 30: -0.9994046 Cost after step 35: -0.9999964 Cost after step 40: -1.0000000 Cost after step 45: -1.0000000 Cost after step 50: -1.0000000 Cost after step 55: -1.0000000 Cost after step 60: -1.0000000 Cost after step 65: -1.0000000 Cost after step 70: -1.0000000 Cost after step 75: -1.0000000 Cost after step 80: -1.0000000 Cost after step 85: -1.0000000 Cost after step 90: -1.0000000 Cost after step 95: -1.0000000 Cost after step 100: -1.0000000 Optimized rotation angles: [9.08664625e-17 3.14159265e+00]
最適化はおよそ 40 ステップで収束することを見て取れます。
これを理論的結果 $\langle \psi \mid \sigma_z \mid \psi \rangle = \cos\phi_1\cos\phi_2$ に置換すると、これは量子ビットが状態 $\left|1\right\rangle$ に回転される結果になる、$\langle \psi \mid \sigma_z \mid \psi \rangle=-1$ を生成する回路パラメータの一つの可能な値であることを確認できます。
Note
AdagradOptimizer のような幾つかの optimizer は optimizer インスタンスにストアされた内部ハイパーパラメータを持ちます。これらは reset() メソッドを使用してリセットできます。
連続変数 (CV) 量子ノードを使用する類似のサンプルを見るには次のチュートリアル、Gaussian transformation へ進んでください。
以上