PennyLane : 使用方法 : TensorFlow インターフェイス

PennyLane 使用方法 : TensorFlow インターフェイス (翻訳)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/19/2019

* 本ページは、PennyLane : Using 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}}
$$

 

使用方法 : TensorFlow インターフェイス

PennyLane は変分回路から成る量子ノードを他のプログラミングと機械学習フレームワークと統合しています。そのようなフレームワークはインターフェイスと呼ばれます。変分回路をどのようにプログラムするかの前のセクションで暗黙的に使用されたデフォルトのインターフェイスは NumPy です。

 
TensorFlow の Eager モードとの組み合わせで量子ノードを使用するには、それを TensorFlow と互換にしなければなりません。TensorFlow 互換量子ノードは qnode デコレータで interface=’tf’ フラグを使用するか、QNode.to_tf 関数を呼び出すことにより作成できます。内部的には、変換は TFQNode 関数により実行されます、これは新しい量子ノード・オブジェクトを返します。

Note
PennyLane で TensorFlow eager execution インターフェイスを使用するには、最初に TensorFlow をインストールしなければなりません。インターフェイスは eager execution モードの TensorFlow version >=1.12 (version 2.0 を含む) だけをサポートすることに注意してください!

TensorFlow は次のようにインポートされる :

import pennylane as qml
import tensorflow as tf

PennyLane で TensorFlow インターフェイスを使用することは容易です — それが成される 2, 3 の方法を考えましょう。

 

デコレータを通して構築

QNode デコレータ は PennyLane で QNode を作成するために推奨される方法です。TensorFlow-capable QNode を構築するために必要な唯一の変更は interface=’tf’ キーワード引数を指定することです :

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='tf')
def circuit1(phi, theta):
    qml.RX(phi[0], wires=0)
    qml.RY(phi[1], wires=1)
    qml.CNOT(wires=[0, 1])
    qml.PhaseShift(theta, wires=0)
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

QNode circuit1() は今では TensorFlow-capable QNode で、入力として tf.Variable オブジェクトを受け取り、tf.Tensor オブジェクトを返します。

>>> phi = tf.Variable([0.5, 0.1])
>>> theta = tf.Variable(0.2)
>>> circuit1(phi, theta)
<tf.Tensor: id=22, shape=(2,), dtype=float64, numpy=array([ 0.87758256,  0.68803733])>

 

基本的な QNode から構築

最初に 2 つの基本的な、NumPy-interfacing QNode を作成します。

dev1 = qml.device('default.qubit', wires=2)
dev2 = qml.device('forest.wavefunction', wires=2)

def circuit2(phi, theta):
    qml.RX(phi[0], wires=0)
    qml.RY(phi[1], wires=1)
    qml.CNOT(wires=[0, 1])
    qml.PhaseShift(theta, wires=0)
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

qnode1 = qml.QNode(circuit2, dev1)
qnode2 = qml.QNode(circuit2, dev2)

to_tf() メソッドを使用してデフォルトの NumPy-interfacing QNode を TensorFlow-interfacing QNode に変換できます :

>>> qnode1 = qnode1.to_tf()
>>> qnode1

内部的には、to_tf() メソッドは変換を行なうために TFQNode() 関数を使用します。

 

TensorFlow を使用する量子勾配

TensorFlow-interfacing QNode は任意の他の TensorFlow 関数のように動作しますので、TensorFlow で eager モードで勾配を計算するために使用される標準メソッドが使用できます。

例えば :

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='tf')
def circuit3(phi, theta):
    qml.RX(phi[0], wires=0)
    qml.RY(phi[1], wires=1)
    qml.CNOT(wires=[0, 1])
    qml.PhaseShift(theta, wires=0)
    return qml.expval(qml.PauliZ(0))

phi = tf.Variable([0.5, 0.1])
theta = tf.Variable(0.2)

grad_fn = tf.implicit_value_and_gradients(circuit3)
result, [(phi_grad, phi_var), (theta_grad, theta_var)] = grad_fn(phi, theta)

今、勾配をプリントして、次を得ます :

>>> phi_grad
array([-0.47942549,  0.        ])
>>> theta_grad
-5.5511151231257827e-17

TensorFlow eager インターフェイスを使用してハイブリッド古典的量子モデルを最適化するためには、tf.train モジュールで提供される TensorFlow optimizer か、貴方自身のカスタム TensorFlow optimizer を利用しなければ なりませんPennyLane optimizer は TensorFlow インターフェイスでは使用できません

例えば、重み x が 0.5 の期待値という結果になるように TensorFlow-interfacing QNode (下) を最適化するためには、次を行なうことができます :

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='tf')
def circuit4(phi, theta):
    qml.RX(phi[0], wires=0)
    qml.RY(phi[1], wires=1)
    qml.CNOT(wires=[0, 1])
    qml.PhaseShift(theta, wires=0)
    return qml.expval(qml.PauliZ(0))

phi = tf.Variable([0.5, 0.1], dtype=tf.float64)
theta = tf.Variable(0.2, dtype=tf.float64)

opt = tf.train.GradientDescentOptimizer(learning_rate=0.1)
steps = 200

for i in range(steps):
    with tf.GradientTape() as tape:
        loss = tf.abs(circuit4(phi, theta) - 0.5)**2
        grads = tape.gradient(loss, [phi, theta])

    opt.apply_gradients(zip(grads, [phi, theta]), global_step=tf.train.get_or_create_global_step())

最終的な重みと回路値は :

>>> phi
<tf.Variable 'Variable:0' shape=(2,) dtype=float64, numpy=array([ 1.04719755,  0.1       ])>
>>> theta
<tf.Variable 'Variable:0' shape=() dtype=float64, numpy=0.20000000000000001>
>>> circuit(phi, theta)
<tf.Tensor: id=106269, shape=(), dtype=float64, numpy=0.5000000000000091>
 

以上