注釈
このページは tutorials/algorithms/02_vqe_convergence.ipynb から生成されました。
VQE の収束性モニタリング¶
VQE や QAOA といった Qiskit における変分アルゴリズムでは、アルゴリズムが実行されて最小値に収束するまでの最適化の進捗状況を監視することができ、そのためのコールバック・メソッドをユーザーに提供するオプションが用意されています。このコールバックは、オプティマイザーによる関数評価ごとに呼び出され、現在のオプティマイザーのパラメーターや関数値、評価回数などを返します。オプティマイザーによっては、これが各反復 (ステップ) ごとでない場合があることに注意してください。
このノートブックでは Qiskit の VQE アルゴリズムを用いて、選択したオプティマイザーのセットによる基底エネルギーへの収束の様子を、グラフにプロットする方法を示します。
[1]:
import numpy as np
import pylab
from qiskit import Aer
from qiskit.opflow import X, Z, I
from qiskit.utils import QuantumInstance, algorithm_globals
from qiskit.algorithms import VQE, NumPyMinimumEigensolver
from qiskit.algorithms.optimizers import COBYLA, L_BFGS_B, SLSQP
from qiskit.circuit.library import TwoLocal
まず、 VQE用の量子ビット演算子を作成します。ここでは、アルゴリズム入門で用いたものと同じ演算子を使用します。この演算子は元々 H2 分子用に Qiskit Nature によって計算されたものです。
[2]:
H2_op = (-1.052373245772859 * I ^ I) + \
(0.39793742484318045 * I ^ Z) + \
(-0.39793742484318045 * Z ^ I) + \
(-0.01128010425623538 * Z ^ Z) + \
(0.18093119978423156 * X ^ X)
比較するためのオプティマイザーのセットにおける、コールバックの使用法を以下に示します。 H2 ハミルトニアンの最小エネルギーは非常に容易に見つけることができるので、 maxiters を小さな値に設定することができます。
[3]:
optimizers = [COBYLA(maxiter=80), L_BFGS_B(maxiter=60), SLSQP(maxiter=60)]
converge_cnts = np.empty([len(optimizers)], dtype=object)
converge_vals = np.empty([len(optimizers)], dtype=object)
for i, optimizer in enumerate(optimizers):
print('\rOptimizer: {} '.format(type(optimizer).__name__), end='')
algorithm_globals.random_seed = 50
ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
counts = []
values = []
def store_intermediate_result(eval_count, parameters, mean, std):
counts.append(eval_count)
values.append(mean)
vqe = VQE(ansatz, optimizer, callback=store_intermediate_result,
quantum_instance=QuantumInstance(backend=Aer.get_backend('statevector_simulator')))
result = vqe.compute_minimum_eigenvalue(operator=H2_op)
converge_cnts[i] = np.asarray(counts)
converge_vals[i] = np.asarray(values)
print('\rOptimization complete ');
Optimization complete
保存されたコールバック・データから、各オプティマイザーが行う目的関数の呼び出しごとのエネルギー値をプロットすることができます。勾配の計算に有限差分法を用いたオプティマイザーでは、勾配を得るために多くの評価では近くにある点の値を計算していて、プロットのように特徴的なステップを示します。 (近くにある点は非常に似た値をもち、その差を今回のグラフのスケールで見ることはできません。)
[4]:
pylab.rcParams['figure.figsize'] = (12, 8)
for i, optimizer in enumerate(optimizers):
pylab.plot(converge_cnts[i], converge_vals[i], label=type(optimizer).__name__)
pylab.xlabel('Eval count')
pylab.ylabel('Energy')
pylab.title('Energy convergence for various optimizers')
pylab.legend(loc='upper right');

最後に、上記の問題は古典的な手法で容易に解くことができるので、 NumPyMinimumEigensolver を用いて厳密解を計算しておきます。このようにすることで、 VQE によってエネルギーが古典的な厳密解である最小値へ収束していく過程において、厳密解との差をプロットすることができるようになります。
[5]:
npme = NumPyMinimumEigensolver()
result = npme.compute_minimum_eigenvalue(operator=H2_op)
ref_value = result.eigenvalue.real
print(f'Reference value: {ref_value:.5f}')
Reference value: -1.85728
[6]:
pylab.rcParams['figure.figsize'] = (12, 8)
for i, optimizer in enumerate(optimizers):
pylab.plot(converge_cnts[i], abs(ref_value - converge_vals[i]), label=type(optimizer).__name__)
pylab.xlabel('Eval count')
pylab.ylabel('Energy difference from solution reference value')
pylab.title('Energy convergence for various optimizers')
pylab.yscale('log')
pylab.legend(loc='upper right');

勾配フレームワークの利用¶
Qiskitには、 Opflow 機能の一部として Gradient フレームワークがあります。オプティマイザー用に計算された勾配によって、最適化ステップそのものを可視化することができます。
[7]:
from qiskit.opflow.gradients import Gradient
algorithm_globals.random_seed = 50
ansatz = TwoLocal(rotation_blocks='ry', entanglement_blocks='cz')
optimizer = SLSQP(maxiter=60)
counts = []
values = []
def store_intermediate_result(eval_count, parameters, mean, std):
counts.append(eval_count)
values.append(mean)
vqe = VQE(ansatz, optimizer, callback=store_intermediate_result,
gradient=Gradient(grad_method='fin_diff'),
quantum_instance=QuantumInstance(backend=Aer.get_backend('statevector_simulator')))
result = vqe.compute_minimum_eigenvalue(operator=H2_op)
print(f'Value using Gradient: {result.eigenvalue.real:.5f}')
Value using Gradient: -1.85728
[8]:
pylab.rcParams['figure.figsize'] = (12, 8)
pylab.plot(counts, values, label=type(optimizer).__name__)
pylab.xlabel('Eval count')
pylab.ylabel('Energy')
pylab.title('Energy convergence using Gradient')
pylab.legend(loc='upper right');

ログによるモニタリング¶
多くのコードは Python の logging ステートメントを用いて実装します。ロギングの際、ログ・レベルなどの構成を変更することができます。 ここでは、ログ・レベルを INFO
に設定します。
[9]:
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger('qiskit.algorithms.minimum_eigen_solvers.vqe').setLevel(logging.INFO)
また INFO レベルのロギングでは、 VQE は評価に関する以下のような情報を含んでいます。
INFO:qiskit.algorithms.minimum_eigen_solvers.vqe:Energy evaluation returned [-1.07392554] - 116.41884 (ms), eval count: 1 INFO:qiskit.algorithms.minimum_eigen_solvers.vqe:Energy evaluation returned [-1.43698938] - 4.05884 (ms), eval count: 2 INFO:qiskit.algorithms.minimum_eigen_solvers.vqe:Energy evaluation returned [-1.74596698] - 7.40194 (ms), eval count: 3 INFO:qiskit.algorithms.minimum_eigen_solvers.vqe:Energy evaluation returned [-1.75399268] - 6.61016 (ms), eval count: 4
[10]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
Qiskit | None |
Terra | 0.18.0.dev0+5920b66 |
Aer | 0.9.0 |
Ignis | 0.7.0.dev0+8195559 |
Aqua | None |
IBM Q Provider | None |
System information | |
Python | 3.8.8 (default, Apr 13 2021, 12:59:45) [Clang 10.0.0 ] |
OS | Darwin |
CPUs | 2 |
Memory (Gb) | 12.0 |
Thu May 27 11:00:06 2021 EDT |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
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.
[ ]: