Japanese
言語
English
Japanese
German
Korean
Portuguese, Brazilian
French
Shortcuts

注釈

このページは tutorials/algorithms/04_vqe_advanced.ipynb から生成されました。

IBM Quantum lab でインタラクティブに実行します。

VQE の高度な使い方

VQE のより高度な機能を設定して使用するために、いくつかのパラメータが用意されています。このチュートリアルでは、 initial_point, expectation, gradient などのパラメーターについて説明します。

また、 Matrix Product State 法による Aer の利用法など、シミュレーターの高度な使用法についても解説します。

[1]:
from qiskit import BasicAer
from qiskit.aqua.operators import X, Z, I
from qiskit.aqua import QuantumInstance, aqua_globals
from qiskit.aqua.algorithms import VQE
from qiskit.aqua.components.optimizers import SLSQP
from qiskit.circuit.library import TwoLocal

ここでは、他の VQE アルゴリズムのチュートリアルで用いたものと同じ演算子を使用します。

[2]:
H2_op = (-1.052373245772859 * I ^ I) + \
        (0.39793742484318045 * I ^ Z) + \
        (-0.39793742484318045 * Z ^ I) + \
        (-0.01128010425623538 * Z ^ Z) + \
        (0.18093119978423156 * X ^ X)

初期点(Initial point)

パラメータ initial_point によって、最適化を開始する点を指定することができます。デフォルトで初期値は None であり、この場合 VQE が初期点を選びます。このときの選択は、初期状態に基づいて変分形式に好ましい点がある場合にはその点が選ばれ、そうでない場合には変分法の全ての境界条件に適合するランダムな初期点が選ばれます。初期点が与えられたときは、それが優先的に用いられます。ただしその長さは、変分回路のパラメーター数と一致していなければならないことに注意してください。

なぜ初期点を使うのでしょうか。理由としては、問題にとって合理的な出発点が推測される場合や、過去の実験から得られた情報がある場合などが考えられます。

使い方を説明するために、まず algorithms introduction チュートリアルの最初の作業例を繰り返して、解を与える最適点を求めてみましょう。

[3]:
from qiskit.aqua import aqua_globals
seed = 50
aqua_globals.random_seed = seed
qi = QuantumInstance(BasicAer.get_backend('statevector_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi)
result = vqe.run()

import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(result)
{   'cost_function_evals': 72,
    'eigenstate': array([-9.55448660e-05+2.12037105e-17j,  9.93766273e-01+2.25293943e-16j,
       -1.11483565e-01+1.52657541e-16j, -1.77521351e-05+3.71607315e-17j]),
    'eigenvalue': (-1.857275017559769+0j),
    'optimal_parameters': {   Parameter(θ[0]): 4.296520551468743,
                              Parameter(θ[1]): 4.426962086704216,
                              Parameter(θ[2]): 0.5470753710293924,
                              Parameter(θ[3]): 6.09294789784282,
                              Parameter(θ[4]): -2.598325857134344,
                              Parameter(θ[5]): 1.5683261371389359,
                              Parameter(θ[6]): -4.717618235040379,
                              Parameter(θ[7]): 0.3602072316165878},
    'optimal_point': array([ 4.29652055,  4.42696209,  0.54707537,  6.0929479 , -2.59832586,
        1.56832614, -4.71761824,  0.36020723]),
    'optimal_value': -1.857275017559769,
    'optimizer_evals': 72,
    'optimizer_time': 1.2399418354034424}

上の結果から optimal_point を取り出して、これを initial_point として用います。

[4]:
initial_pt = result.optimal_point

aqua_globals.random_seed = seed
qi = QuantumInstance(BasicAer.get_backend('statevector_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, initial_point=initial_pt, quantum_instance=qi)
result1 = vqe.run()

pp.pprint(result1)
{   'cost_function_evals': 10,
    'eigenstate': array([-9.55448660e-05+2.12037105e-17j,  9.93766273e-01+2.25293943e-16j,
       -1.11483565e-01+1.52657541e-16j, -1.77521351e-05+3.71607315e-17j]),
    'eigenvalue': (-1.857275017559769+0j),
    'optimal_parameters': {   Parameter(θ[1]): 4.426962086704216,
                              Parameter(θ[0]): 4.296520551468743,
                              Parameter(θ[4]): -2.598325857134344,
                              Parameter(θ[6]): -4.717618235040379,
                              Parameter(θ[3]): 6.09294789784282,
                              Parameter(θ[2]): 0.5470753710293924,
                              Parameter(θ[5]): 1.5683261371389359,
                              Parameter(θ[7]): 0.3602072316165878},
    'optimal_point': array([ 4.29652055,  4.42696209,  0.54707537,  6.0929479 , -2.59832586,
        1.56832614, -4.71761824,  0.36020723]),
    'optimal_value': -1.857275017559769,
    'optimizer_evals': 10,
    'optimizer_time': 0.27449989318847656}

optimizer_evals の値が、初期値が与えられず (デフォルトでNone) ランダムな値から開始した場合では72でしたが、ここでは10となっていることから、結果がより早く得られているのがわかります。

これが役に立つのは、例えばある問題に対する解を、それに非常に似た問題に対する解の推測のために使える場合です。化学は、分子の原子間距離を変えて、解離プロファイルをプロットするという、非常に良い例です。距離の変化が小さい場合には、解がその前の解の近くにあることが予測されます。一つの手法として単純に、ある解の最適点を次のステップの出発点として用いることがあります。現在では、前の解を直接的に用いるのではなく、前の解に基づいて外挿を行って初期値を計算するという、より複雑なテクニックが可能となっています。Qiskit Chemistry の sampling_potential_energy_surfaces チュートリアルでは、このようなブートストラップと外挿を紹介しています。

期待値(Expectation)

VQEが求めているハミルトニアン演算子のエネルギーは、パラメーター化された変分形式で評価された場合の期待値です。期待値を計算するために、 VQE は expectation オブジェクトのインスタンスを使用しています。このようなインスタンスは expectation パラメーターで与えられますが、デフォルトで None の値を取っている場合に VQE は、 ExpectationFactory を用いて、与えられたバックエンドに基づき、適切なインスタンスを作成します。

ほとんどの場合は VQE に作成させるだけで十分です。しかし Qiskit Aer の qasm_simulator はスナップショット命令をサポートしており、演算子の期待値計算と組み合わせて用いることができます。これを使えば、状態ベクトル・シミュレーターのように、出力はショット・ノイズの乗らない理想的なものとなります。通常はショット・ノイズ (サンプリング・ノイズ) を乗せて、より実デバイスに近い結果が得られるよう、 qasm_simulator を選択するので、 VQE にはExpectationFactory に渡される include_custom フラグが用意されています。これを True に設定すると、スナップショット命令を使用した AerPauliExpectation が返され、デフォルトの False に設定すると、通常の PauliExpectation が返されます。

以下の例では、結果が statevector_simulator と一致する、 include_custom=True の場合を示しています。実際は、 statevector_simulator を直接使うよりもこちらの方法の方が、実行がより速くなることがあります。これは、 Pauli 行列の和として表されたハミルトニアンは行列形式に変換される必要がありますが、include_custom をTrue としてスナップショット命令を使うことで、これを回避できるからです。

[5]:
from qiskit import Aer

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi, include_custom=True)
result = vqe.run()

pp.pprint(result)
{   'cost_function_evals': 72,
    'eigenstate': {'01': 1008, '10': 16},
    'eigenvalue': (-1.8572750175597519+0j),
    'optimal_parameters': {   Parameter(θ[0]): 4.296520463599476,
                              Parameter(θ[1]): 4.426962139199476,
                              Parameter(θ[2]): 0.5470754235069875,
                              Parameter(θ[3]): 6.092947836794945,
                              Parameter(θ[4]): -2.5983258956331645,
                              Parameter(θ[5]): 1.568326000491598,
                              Parameter(θ[6]): -4.717618128585369,
                              Parameter(θ[7]): 0.3602072910298268},
    'optimal_point': array([ 4.29652046,  4.42696214,  0.54707542,  6.09294784, -2.5983259 ,
        1.568326  , -4.71761813,  0.36020729]),
    'optimal_value': -1.8572750175597519,
    'optimizer_evals': 72,
    'optimizer_time': 1.2052154541015625}

念のため、ここで再度 qasm_simulator を実行しますが、 include_custom はデフォルトの False のままとしておきます。すると、おそらくショット・ノイズが SLSQP オプティマイザー を混乱させたために、最適化は突然終了しています。最適値も正解の -1.857 に対して -1.098 と、間違っています。

[6]:
aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi)
result = vqe.run()

pp.pprint(result)
{   'cost_function_evals': 10,
    'eigenstate': {'00': 620, '01': 244, '10': 159, '11': 1},
    'eigenvalue': (-1.0987888676631705+0j),
    'optimal_parameters': {   Parameter(θ[5]): 1.8462931831829383,
                              Parameter(θ[6]): -5.466043598406607,
                              Parameter(θ[7]): 0.6984088030463615,
                              Parameter(θ[2]): 0.6019852007557844,
                              Parameter(θ[1]): 4.19301252102391,
                              Parameter(θ[0]): 3.611860069224077,
                              Parameter(θ[4]): -3.3070470445355764,
                              Parameter(θ[3]): 5.949536809130025},
    'optimal_point': array([ 3.61186007,  4.19301252,  0.6019852 ,  5.94953681, -3.30704704,
        1.84629318, -5.4660436 ,  0.6984088 ]),
    'optimal_value': -1.0987888676631705,
    'optimizer_evals': 10,
    'optimizer_time': 0.5309410095214844}

オプティマイザーをノイズの多い環境で動作するよう設計された SPSA に変更すると、より良い結果が得られます。ただし、ノイズが結果に影響を与えているため、正確性は劣ります。

[7]:
from qiskit.aqua.components.optimizers import SPSA

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SPSA(maxiter=100)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi)
result = vqe.run()

pp.pprint(result)
{   'cost_function_evals': 241,
    'eigenstate': {'01': 1007, '10': 17},
    'eigenvalue': (-1.8623464125433034+0j),
    'optimal_parameters': {   Parameter(θ[3]): 7.149874669811867,
                              Parameter(θ[7]): -1.8648388048829714,
                              Parameter(θ[2]): 2.146860065695897,
                              Parameter(θ[1]): 2.0047037904408738,
                              Parameter(θ[5]): 0.026059065222908795,
                              Parameter(θ[6]): -4.4426207121597745,
                              Parameter(θ[4]): -4.6685058886658455,
                              Parameter(θ[0]): 4.731406884288576},
    'optimal_point': array([ 4.73140688,  2.00470379,  2.14686007,  7.14987467, -4.66850589,
        0.02605907, -4.44262071, -1.8648388 ]),
    'optimal_value': -1.8623464125433034,
    'optimizer_time': 11.047632932662964}

上述のように、期待値オブジェクトは明示的に与えることができます。 (そのため、内部の ExpectationFactory や include_custom は決して使用されることも、必要とされることはありません) 以下では AerPauliExpectation を作成し、 VQE に渡しています。結果は、 include_custom を True として VQE に独自の期待値オブジェクトを作成させた、上の結果と一致していることが確認できます。

[8]:
from qiskit.aqua.operators import AerPauliExpectation

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi,
          expectation=AerPauliExpectation())
result = vqe.run()

pp.pprint(result)
{   'cost_function_evals': 72,
    'eigenstate': {'01': 1008, '10': 16},
    'eigenvalue': (-1.8572750175597519+0j),
    'optimal_parameters': {   Parameter(θ[5]): 1.568326000491598,
                              Parameter(θ[6]): -4.717618128585369,
                              Parameter(θ[4]): -2.5983258956331645,
                              Parameter(θ[2]): 0.5470754235069875,
                              Parameter(θ[3]): 6.092947836794945,
                              Parameter(θ[7]): 0.3602072910298268,
                              Parameter(θ[0]): 4.296520463599476,
                              Parameter(θ[1]): 4.426962139199476},
    'optimal_point': array([ 4.29652046,  4.42696214,  0.54707542,  6.09294784, -2.5983259 ,
        1.568326  , -4.71761813,  0.36020729]),
    'optimal_value': -1.8572750175597519,
    'optimizer_evals': 72,
    'optimizer_time': 1.3454556465148926}

By default, the PauliExpectation object, that would have be chosen when include_custom is False (or when using BasicAer qasm_simulator, or a real device) groups Paulis into commuting sets. This is efficient as it runs less circuits to compute the expectation. However, if for some reason you wanted to run a circuit for each Pauli then then grouping can be turned off when constructing the PauliExpectation. You need to explicitly pass in such an expectation instance to VQE to have it work this way though as shown below.

[9]:
from qiskit.aqua.operators import PauliExpectation

aqua_globals.random_seed = seed
qi = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_transpiler=seed, seed_simulator=seed)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SPSA(maxiter=100)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi,
          expectation=PauliExpectation(group_paulis=False))
result = vqe.run()

pp.pprint(result)
{   'cost_function_evals': 241,
    'eigenstate': {'01': 1007, '10': 17},
    'eigenvalue': (-1.8667499370593512+0j),
    'optimal_parameters': {   Parameter(θ[1]): 2.1216349904032947,
                              Parameter(θ[7]): -1.9698662442728732,
                              Parameter(θ[5]): 0.2634941452871489,
                              Parameter(θ[6]): -4.360567678129973,
                              Parameter(θ[0]): 4.718047005792739,
                              Parameter(θ[4]): -4.733789920734712,
                              Parameter(θ[2]): 2.1876557567510497,
                              Parameter(θ[3]): 7.317481602611872},
    'optimal_point': array([ 4.71804701,  2.12163499,  2.18765576,  7.3174816 , -4.73378992,
        0.26349415, -4.36056768, -1.96986624]),
    'optimal_value': -1.8667499370593512,
    'optimizer_time': 20.964618682861328}

勾配(Gradient)

勾配ベースの手法を用いるオプティマイザーには、通常は単純な有限差分で求められるデフォルトの勾配の代わりとして、ユーザー定義の勾配を与えることができます。勾配はオプティマイザーの gradient パラメーターを介して、間接的にオプティマイザーに渡されます。

Monitoring VQE Convergence チュートリアルでは、ユーザー定義の gradient の使用法が示されているので、そちらを参照してください。また Gradients framework チュートリアルには、勾配そのものについての詳細が示されています。

Quantum Instance と高度なシミュレーション

While you may be familiar with passing a QuantumInstancen created from a statevector_simulator a qasm_simulator or real device backend, it is possible to use the advanced simulation modes of Aer too when applicable. For instance we can easily use the Aer Matrix Product State method, that has the potential to scale to larger numbers of qubits.

[10]:
aqua_globals.random_seed = seed

from qiskit.providers.aer import QasmSimulator
quantum_instance = QuantumInstance(QasmSimulator(method='matrix_product_state'), shots=1)

ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
slsqp = SLSQP(maxiter=1000)
vqe = VQE(operator=H2_op, var_form=ansatz, optimizer=slsqp, quantum_instance=qi, include_custom=True)
result = vqe.run()

pp.pprint(result)
{   'cost_function_evals': 72,
    'eigenstate': {'01': 1008, '10': 16},
    'eigenvalue': (-1.8572750175597519+0j),
    'optimal_parameters': {   Parameter(θ[0]): 4.296520463599476,
                              Parameter(θ[6]): -4.717618128585369,
                              Parameter(θ[7]): 0.3602072910298268,
                              Parameter(θ[4]): -2.5983258956331645,
                              Parameter(θ[5]): 1.568326000491598,
                              Parameter(θ[3]): 6.092947836794945,
                              Parameter(θ[2]): 0.5470754235069875,
                              Parameter(θ[1]): 4.426962139199476},
    'optimal_point': array([ 4.29652046,  4.42696214,  0.54707542,  6.09294784, -2.5983259 ,
        1.568326  , -4.71761813,  0.36020729]),
    'optimal_value': -1.8572750175597519,
    'optimizer_evals': 72,
    'optimizer_time': 1.2383882999420166}
[11]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
Qiskit0.23.1
Terra0.16.1
Aer0.7.1
Ignis0.5.1
Aqua0.8.1
IBM Q Provider0.11.1
System information
Python3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:09:58) [GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]
OSLinux
CPUs1
Memory (Gb)5.827335357666016
Tue Nov 17 15:48:57 2020 EST

This code is a part of Qiskit

© Copyright IBM 2017, 2020.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.

[ ]: