梯度和变分优化#

概述#

TensorCircuit 旨在使参数化量子门的优化变得简单、快速和方便。 在本说明中,我们回顾了如何获得电路梯度和运行变分优化。

设置#

[1]:
import numpy as np
import scipy.optimize as optimize
import tensorflow as tf
import tensorcircuit as tc

K = tc.set_backend("tensorflow")

PQC#

考虑一个作用于 \(n\) 个量子比特的变分电路,由 \(k\) 层组成,其中每一层包含相邻量子比特之间的参数化 \(e^{i\theta X\otimes X}\) 门, 然后是一系列参数化的单量子比特 \(Z\)\(X\) 旋转。 我们现在展示如何在 TensorCircuit 中实现此类电路,以及如何使用机器学习后端之一轻松高效地计算损失函数和梯度。

一般\(n,k\)的电路和参数集可以定义如下::

[2]:
def qcircuit(n, k, params):
    c = tc.Circuit(n)
    for j in range(k):
        for i in range(n - 1):
            c.exp1(
                i, i + 1, theta=params[j * (3 * n - 1) + i], unitary=tc.gates._xx_matrix
            )
        for i in range(n):
            c.rz(i, theta=params[j * (3 * n - 1) + n - 1 + i])
            c.rx(i, theta=params[j * (3 * n - 1) + 2 * n - 1 + i])
    return c

举个例子,我们取 \(n=3, k=2\) ,设置 TensorFlow 作为我们的后端,定义一个能量损失函数来最小化

\[E = \langle X_0 X_1\rangle_\theta + \langle X_1 X_2\rangle_\theta.\]
[3]:
n = 3
k = 2


def energy(params):
    c = qcircuit(n, k, params)
    e = c.expectation_ps(x=[0, 1]) + c.expectation_ps(x=[1, 2])
    return K.real(e)

梯度和即时编译#

使用 ML 后端对自动微分的支持,我们现在可以快速计算能量和能量相对于参数的梯度。

[4]:
energy_val_grad = K.value_and_grad(energy)

这将创建一个函数,给定一组参数作为输入,返回能量和能量梯度。如果只需要梯度,则可以通过 K.grad(energy) 计算。 虽然我们可以直接在一组参数上运行上述代码,但如果要对能量进行多次评估,则可以通过使用该函数的即时编译版本来节省大量时间。

[5]:
energy_val_grad_jit = K.jit(energy_val_grad)

使用 K.jit,能量和梯度的初始评估可能需要更长的时间,但随后的评估将明显快于非 jitted 代码。 我们建议始终使用 jit,只要函数是 张量输入,张量输出 的形式,我们已经努力使电路模拟器的各个方面都与 JIT 兼容。

通过 ML 后端进行优化#

有了可用的能量函数和梯度,参数的优化就很简单了。下面是一个如何通过随机梯度下降来做到这一点的例子。

[6]:
learning_rate = 2e-2
opt = K.optimizer(tf.keras.optimizers.SGD(learning_rate))


def grad_descent(params, i):
    val, grad = energy_val_grad_jit(params)
    params = opt.update(grad, params)
    if i % 10 == 0:
        print(f"i={i}, energy={val}")
    return params


params = K.implicit_randn(k * (3 * n - 1))
for i in range(100):
    params = grad_descent(params, i)
i=0, energy=0.11897378414869308
i=10, energy=-0.3692811131477356
i=20, energy=-0.7194114923477173
i=30, energy=-0.904697597026825
i=40, energy=-1.013866662979126
i=50, energy=-1.1042678356170654
i=60, energy=-1.1998062133789062
i=70, energy=-1.308410406112671
i=80, energy=-1.4276418685913086
i=90, energy=-1.5474387407302856

通过 Scipy 界面进行优化#

使用机器学习后端进行优化的另一种方法是使用 SciPy。 这可以通过 scipy_interface API 调用来完成,并允许使用基于梯度(例如 BFGS)和非基于梯度(例如 COBYLA)的优化器,这在 ML 后端是不可用的。

[7]:
f_scipy = tc.interfaces.scipy_interface(energy, shape=[k * (3 * n - 1)], jit=True)
params = K.implicit_randn(k * (3 * n - 1))
r = optimize.minimize(f_scipy, params, method="L-BFGS-B", jac=True)
r
/Users/shixin/Cloud/newwork/quantum-information/codebases/tensorcircuit/tensorcircuit/interfaces.py:237: ComplexWarning: Casting complex values to real discards the imaginary part
  scipy_gs = scipy_gs.astype(np.float64)
[7]:
      fun: -2.000000476837158
 hess_inv: <16x16 LbfgsInvHessProduct with dtype=float64>
      jac: array([ 2.43186951e-04, -1.50322914e-04,  8.94665718e-05,  1.18807920e-05,
        2.95639038e-05,  1.19209290e-07, -5.96046448e-08, -2.98023224e-08,
        0.00000000e+00, -1.19209290e-07,  3.90738450e-07,  9.34305717e-07,
       -8.22039729e-05,  1.19209290e-07,  0.00000000e+00,  0.00000000e+00])
  message: 'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
     nfev: 60
      nit: 19
     njev: 60
   status: 0
  success: True
        x: array([ 2.35625520e+00,  7.85409154e-01,  1.57088576e+00,  2.10625989e-05,
       -1.57088425e+00, -1.70256902e+00, -5.33743572e-01,  3.11436816e-01,
        1.26543793e+00,  1.91663337e+00, -1.15901008e-07, -1.76623396e-05,
       -1.59972887e-04, -8.97072367e-01,  1.79929630e+00, -9.67278961e-01])

上面的第一行指定了要提供给要最小化的函数的参数的形状,这里是能量函数。 jit=True 参数会自动处理能量函数的即时编译。 通过将 gradient=False 参数提供给scipy_interface,同样可以有效地执行无梯度优化。

[8]:
f_scipy = tc.interfaces.scipy_interface(
    energy, shape=[k * (3 * n - 1)], jit=True, gradient=False
)
params = K.implicit_randn(k * (3 * n - 1))
r = optimize.minimize(f_scipy, params, method="COBYLA")
r
[8]:
     fun: -1.9999911785125732
   maxcv: 0.0
 message: 'Optimization terminated successfully.'
    nfev: 386
  status: 1
 success: True
       x: array([ 7.87597857e-01, -5.14158452e-01, -1.56560250e+00, -3.15230777e-04,
        9.91532990e-01,  5.95588091e-01,  1.38523058e+00, -3.59642968e-04,
       -3.23365306e-01, -4.16465772e-01, -7.32259085e-03,  6.53997758e-05,
        7.71203778e-01,  2.46256921e+00,  8.78602039e-01, -3.51989842e-01])