在本节中,我们介绍了参数化量子电路,然后描述了它们的特性并实现了一些用于量子机器学习的示例。
参数化量子电路,其中的门是通过可调参数定义的,是近期量子机器学习算法的基本组成部分。在文献中,根据上下文,参数化量子电路也被称为参数化试态、变分形式或分析。
下面是一个简单的参数化电路的例子,有两个参数化门,一个单量子位 z z z旋转门,具有可变的旋转角度 θ \theta θ,然后是两个量子位受控 z z z旋转门,具有相同的可变旋转角度 θ \theta θ:
我们可以使用QuantumCircuit和Parameter类创建上述参数化电路。Parameter类允许我们添加旋转门,而不必指定角度的具体取值:
from qiskit.circuit import QuantumCircuit, Parameter
theta = Parameter('θ')
qc = QuantumCircuit(2)
qc.rz(theta, 0)
qc.crz(theta, 0, 1)
qc.draw()
如果我们想让门有不同的参数,我们可以使用两个参数,或者我们创建一个ParameterVector,它的作用就像一个参数列表:
from qiskit.circuit import ParameterVector
theta_list = ParameterVector('θ', length=2)
qc = QuantumCircuit(2)
qc.rz(theta_list[0], 0)
qc.crz(theta_list[1], 0, 1)
qc.draw()
由于量子电路中使用的所有量子门都是酉的,因此参数化电路本身可以被描述为对 n n n个量子比特的酉操作 U θ U_\theta Uθ,作用于某些初始量子态 ∣ ϕ 0 > \left|\phi_0\right> ∣ϕ0⟩,通常设置为 ∣ 0 > ⊗ n \left|0\right>^{\otimes n} ∣0⟩⊗n。所得到的参数化量子态是 ∣ ψ 0 > = U θ ∣ ϕ 0 > \left|\psi_0\right>=U_\theta \left|\phi_0\right> ∣ψ0⟩=Uθ∣ϕ0⟩,其中 θ \theta θ是一组可调参数。
我们如何选择某一个参数化电路而不是另一个?为了使用参数化量子电路作为机器学习模型,我们需要它们具有良好的泛化能力。这意味着电路应该能够在输出希尔伯特空间内产生一个重要的量子态子集。为了避免在经典计算机上较为容易地模拟,电路还应该纠缠量子位。
在文献1中,作者提出了可表达性和纠缠能力的度量来区分不同的参数化量子电路。我们可以把电路的可表达性看作是它在希尔伯特空间内产生状态的程度,而电路的纠缠能力描述了它产生纠缠态的能力。
参数化量子电路的可表达性本质上是电路的假设空间对希尔伯特空间的覆盖。高度表达的参数化量子电路可以表示许多不同的酉矩阵。有许多方法可以表示这种可表达性,参考资料1中可以找到一个这样的例子。在这里,作者通过计算电路产生的状态偏离均匀分布的程度来量化它。
让我们比较下面的两个单量子比特电路,通过对每个电路的2000个输出状态进行采样并在Bloch球上绘制它们,来了解电路可表达或不可表达的含义。
电路A的结果
电路B的结果
对于电路A,我们看到输出状态分布在布洛赫球的赤道附近。通过电路B附加的参数化旋转栅极,我们可以覆盖所有有输出状态的布洛赫球,但覆盖并不均匀;在布洛赫球的两极上有一些点的集中。
可表达性是一种量化我们刚刚在这些单量子比特电路中观察到的东西的方法。电路A的可表达性得分很低,因为它可以探索的状态集有限,而电路B的可表达性得分很高。
量子纠缠是量子计算中的关键资源。迈耶-瓦拉赫测量法是衡量给定状态的纠缠程度的众多指标之一。未纠缠产物状态的迈耶-瓦拉赫测量为0,而高度纠缠态(如贝尔态)的Meyer-Wallach测量值为1。在文献1中,作者将参数化量子电路的纠缠能力定义为它所能产生的态的平均Meyer-Wallach测度。
例如,考虑以下多量子位参数化电路:
电路A没有纠缠操作,即没有双量子比特门,因此它没有纠缠能力。因此,该电路将产生Meyer-Wallach测量值为0的状态,导致平均值为0。电路B有几个双量子比特门,所以它可以产生一些纠缠的量子态。因此,Meyer-Wallach测量的平均值将大于0。
利用可表达性和纠缠能力这两个参数化量子电路描述符,我们可以识别出具有有限能力的电路。我们预计有限电路是量子机器学习应用的不良候选者。参考文献2对变分量子分类器进行了研究。对于其数据集和参数化电路,发现分类精度与可表达性之间存在较强的相关性,而分类精度纠缠能力之间存在较弱的相关性。
在这个近期量子计算的时代,在真实设备上,量子比特连接,相干时间和门保真度极其有限,我们运行的电路的深度直接影响我们结果的准确性,因为有有限的错误纠正或缓解。
参考文献3介绍了一类硬件高效的参数化电路,以适应设备条件。这些电路的共同特点是使用一组有限的量子门以及特定的量子比特连接拓扑。门组通常由一个双量子位纠缠门和最多三个单量子位门组成。该电路由单量子位门和纠缠门组成,它们可以并行应用于多个或所有量子位。单量子位和纠缠块的一个序列称为一个层,参数化电路通常有多个层。
电路B描述在“纠缠能力”部分(也如下所示)是一个单层硬件高效参数化电路的例子。
在量子机器学习中,参数化量子电路往往用于两件事:
在参考文献4中,作者介绍了以下用于数据编码的参数化电路,我们将在后面详细研究:
U Φ ( x ) = ∏ d U Φ ( x ) , U Φ ( x ) = exp ( i ∑ S ⊆ [ n ] ϕ S ( x ) ∏ k ∈ S P k ) \mathscr{U}_{\Phi(x)}=\prod_d U_{\Phi(x)},U_{\Phi(x)}=\exp\big(i\sum_{S\subseteq [n]}\phi_S(x)\prod_{k\in S}P_k\big) UΦ(x)=d∏UΦ(x),UΦ(x)=exp(iS⊆[n]∑ϕS(x)k∈S∏Pk)
上述式子里有层层叠叠的阿达玛门和纠缠块, U Φ ( x ) U_\Phi(x) UΦ(x)。之所以选择这个酉矩阵,是因为它通常很难计算,但在近期硬件上很容易处理。在纠缠块内 U Φ ( x ) : P k ∈ { I , X , Y , Z } U_\Phi(x):P_k\in\{I,X,Y,Z\} UΦ(x):Pk∈{I,X,Y,Z}为泡利矩阵,该指数描述了不同量子位之间的连通性: S ∈ { C n k 种组合 , k = 1 , … , n } S\in\{C_n^k种组合,k=1,\dots,n\} S∈{Cnk种组合,k=1,…,n}
,以及数据映射函数 ϕ S ( x ) \phi_S(x) ϕS(x)是
ϕ S ( x ) : x ↦ { x i , S = { i } ( π − x i ) ( π − x j ) , S = { i , j } \phi_S(x):x\mapsto\bigg\{\begin{matrix}x_i, S= \{i\}\\(\pi-x_i)(\pi-x_j), S=\{i,j\}\end{matrix} ϕS(x):x↦{xi,S={i}(π−xi)(π−xj),S={i,j}
特别地,取 k = 2 , P 0 = Z , P 1 = Z Z k=2,P_0=Z,P_1=ZZ k=2,P0=Z,P1=ZZ,在Qiskit中就对应了ZZFeatureMap电路:
from qiskit.circuit.library import ZZFeatureMap
qc_zz = ZZFeatureMap(3, reps=1, insert_barriers=True)
qc_zz.decompose().draw()
在参考文献4中,作者还使用硬件高效电路作为量子模型,由单量子位旋转门的交替层组成,然后是两个量子位门。特别是,它们使用和 y y y旋转门和 z z z控制门,我们可以使用TwoLocal电路来构建它们:
from qiskit.circuit.library import TwoLocal
qc_twolocal = TwoLocal(num_qubits=3, reps=2, rotation_blocks=['ry','rz'],
entanglement_blocks='cz', skip_final_rotation_layer=True,
insert_barriers=True)
qc_twolocal.decompose().draw()
Qiskit中的TwoLocal电路可以创建许多参数化电路,例如参考文献1中的电路13:
qc_13 = TwoLocal(3, rotation_blocks='ry',
entanglement_blocks='crz', entanglement='sca',
reps=3, skip_final_rotation_layer=True,
insert_barriers=True)
qc_13.decompose().draw()
Qiskit的NLocal电路还可以创建具有交替旋转和纠缠层的更通用的参数化电路。
这是一个NLocal电路,使用线性纠缠,在2个量子位上有一个旋转块,在4个量子位上有一个纠缠块:
from qiskit.circuit.library import NLocal
# rotation block:
rot = QuantumCircuit(2)
params = ParameterVector('r', 2)
rot.ry(params[0], 0)
rot.rz(params[1], 1)
# entanglement block:
ent = QuantumCircuit(4)
params = ParameterVector('e', 3)
ent.crx(params[0], 0, 1)
ent.crx(params[1], 1, 2)
ent.crx(params[2], 2, 3)
qc_nlocal = NLocal(num_qubits=6, rotation_blocks=rot,
entanglement_blocks=ent, entanglement='linear',
skip_final_rotation_layer=True, insert_barriers=True)
qc_nlocal.decompose().draw()