查看原文
其他

深度全面解读量子计算机性能衡量标准——Quantum Volume

Vincent QULIB 2022-07-07
一、理论篇

目前,关于衡量量子计算机性能并没有统一的标准。为了解决该问题,2018年IBM提出了量子体积的概念用量衡量量子计算机的性能。

与经典计算机不同,衡量量子计算机的性能主要包含三个方面:量子比特的数量、量子线路的可达深度、错误率。其中:

量子比特的数量表明了量子计算机能够表示的信息的规模,可与经典计算机中存储器的容量相对应。

量子线路的可达深度表明了量子计算的计算能力。当线路的深度超过量子计算机最大可达深度时,量子计算机就会出现错误。目前,最大可达线路深度是制约量子计算机实用化的另外一个重要指标。

量子计算机计算的最终结果可通过量子测量实现,最终体现为不同状态出现的概率(如下图所示)。

而量子计算机中的噪声往往会影响这种概率的正确分布,从而使得最终结果计算不正确。


关于这部分的具体实验可参考之前的公众号文章:


10分钟教你使用IBM量子软件平台Qiskit


在IBM关于量子体积的论文(题目见后面的参考文献1)中,



其中,VQ即为量子体积。m表示量子比特的数目,而d(m)为线路可达的最大深度。

2020年3月HoneyWell发布的量子体积为64的量子计算机。这台量子计算机号称是世界上量子体积最大的量子计算机。根据量子体积的定义,我们不难推测其最大可达深度或最大比特数目为6。

这里大家需要注意,不少新闻的噱头号称量子体积翻一倍,事实上仅表明了量子比特的位数或量子线路可达深度增加了1。

IBM的量子体积定义目前仍然颇受争议,但却真实地体现了量子计算机的计算能力,因为其充分考虑到了量子比特位数、线路深度、错误率等几个方面的综合因素。因此,量子体积在量子计算机没有统一性能评测的现状下,成为广泛被使用的标准。

Vincent认为,量子体积最大的问题在于其计算时将比特数目和线路深度整合成了正方形。而一些经典的算法,例如Shor算法,需要的比特位数为O(n),而线路深度则为O(n3)。很明显,绝大多数量子算法并不是正方形的结构。

在衡量量子计算误差率时,量子体积中涉及到一个heavy output probability的概念。我们知道,在理想情况下执行一个线路的测量结果为概率分布。在含有噪声的量子计算机中,计算结果分布于理想情况下并不相同。这里,将概率大于中间概率(比特串出现概率从大到小排列)的情况称为heavy output。计算结果希望能够产生2/3以上的输出字符串出现的概率大于中间概率。

nc表示生成了nc次的随机线路,ns表示每个线路执行ns次。因此,共有nc*ns个实验结果输出。对于每一次线路的执行,可以确定nh为heavy output的次数。因此,最终处理结果要求:



二、实践篇

在IBM关于量子体积的论文中,用来Benchmark量子体积的线路如下所示:



其中,SU(4)为幺正变换群。本质上代表了某种双比特操作,其数学特点是行列式的值为1。IBM的编译器能够将SU(4)编译为量子计算机能够直接使用的基础门操作,包括u1,u2,u3,cx。

IBM量子体积Benchmark线路生成的接口调用如下:

qubit_lists = [[0,1,3,5]]ntrials = 50
qv_circs, qv_circs_nomeas = qv.qv_circuits(qubit_lists, ntrials)


例如,我们选取量子比特[0,1,3,5],来分析到底生成的线路是什么样子。

上面的代码中,ntrials表示了随机生成的量子线路的深度d。在计算量子体积时,该数值刚好等于量子比特的位数,因此,在上述例子中,量子线路的深度为4。

线路生成部分的代码在ignis/verification/quantum_volume/circuits.py中,具体的代码实现如下:

def qv_circuits(qubit_lists=None, ntrials=1, qr=None, cr=None): """ Return a list of square quantum volume circuits (depth=width)
The qubit_lists is specified as a list of qubit lists. For each set of qubits, circuits the depth as the number of qubits in the list are generated
Args: qubit_lists: list of list of qubits to apply qv circuits to. Assume the list is ordered in increasing number of qubits ntrials: number of random iterations qr: quantum register to act on (if None one is created) cr: classical register to measure to (if None one is created)
Returns: qv_circs: list of lists of circuits for the qv sequences (separate list for each trial) qv_circs_nomeas: same as above with no measurements for the ideal simulation """
circuits = [[] for e in range(ntrials)] circuits_nomeas = [[] for e in range(ntrials)]
# get the largest qubit number out of all the lists (for setting the # register)
depth_list = [len(l) for l in qubit_lists]
# go through for each trial for trial in range(ntrials):
# go through for each depth in the depth list for depthidx, depth in enumerate(depth_list):
n_q_max = np.max(qubit_lists[depthidx])
qr = qiskit.QuantumRegister(int(n_q_max+1), 'qr') qr2 = qiskit.QuantumRegister(int(depth), 'qr') cr = qiskit.ClassicalRegister(int(depth), 'cr')
qc = qiskit.QuantumCircuit(qr, cr) qc2 = qiskit.QuantumCircuit(qr2, cr)
qc.name = 'qv_depth_%d_trial_%d' % (depth, trial) qc2.name = qc.name
# build the circuit for _ in range(depth): # Generate uniformly random permutation Pj of [0...n-1] perm = np.random.permutation(depth) # For each pair p in Pj, generate Haar random SU(4) for k in range(int(np.floor(depth/2))): U = random_unitary(4) pair = int(perm[2*k]), int(perm[2*k+1]) qc.append(U, [qr[qubit_lists[depthidx][pair[0]]], qr[qubit_lists[depthidx][pair[1]]]]) qc2.append(U, [qr2[pair[0]], qr2[pair[1]]])
# append an id to all the qubits in the ideal circuits # to prevent a truncation error in the statevector # simulators qc2.u1(0, qr2)
circuits_nomeas[trial].append(qc2)
# add measurement for qind, qubit in enumerate(qubit_lists[depthidx]): qc.measure(qr[qubit], cr[qind])
circuits[trial].append(qc)
return circuits, circuits_nomeas

在线路生成时,首先根据线路深度生成均匀分布的随机序列串:


perm = np.random.permutation(depth)


接下来随机产生一个unitary矩阵U,从perm中选取两个下标对2×k,2×k+1。


Qc线路将U应用在随机选择的两个量子比特上。

最后生成的qc和qc2两个量子线路,其中一个包含了测量,一个不包含测量。qc和qc2的区别在于qc包含测量,则需要将生成的线路映射到真实的量子比特上,而不测量的话,则只需要将序号标注为0,1,2,3即可。

随机生成的SU可通过编译器转化为基础量子门:


qv_circs_nomeas[0] = qiskit.compiler.transpile(qv_circs_nomeas[0], basis_gates=['u1','u2','u3','cx'])


在生成一个具体的SU(4)时,即生成一个矩阵,其具体的代码实现为:


z = 1/math.sqrt(2)*(random_state.normal(size=(dim, dim)) + 1j*random_state.normal(size=(dim, dim))) q, r = scipy.linalg.qr(z) d = r.diagonal() q *= d/abs(d)        return q


例如,在一次调试过程中,z矩阵为:

array([[ 0.48314207-0.74685063j, -0.32001204+0.28858998j, 0.31048735-1.36176688j, -0.22157554+1.16425953j], [-0.22952827-0.34015267j, 0.47746433+1.04415471j, -0.59934698-0.23617052j, -1.11649142-0.41669992j], [-0.53802896-0.82990912j, -1.21562382+0.63495078j, 0.45721007+0.7721644j , -0.5187136 -1.01859104j], [ 0.22413704-0.40779265j, 1.71092645-0.14994469j,        -0.15958734+0.91498815j, -0.13092838-0.97944035j]])

其中,q, r = scipy.linalg.qr(z)是对z进行矩阵分解。

当运行完线路之后,计算量子体积的代码实现在ignis/verification/quantum_volume/fitters.py中,其中,函数calc_data用来计算heavy ouptutprobability。

计算heavy output概率时,根据理想情况下无噪声的模拟器输出qv_fitter.add_statevectors(ideal_results),来计算得到_heavy_strings,即中间的概率分布是多少。

def _heavy_strings(self, ideal_distribution, ideal_median): """Return the set of heavy output strings.
ideal_distribution = dict of ideal output distribution where keys are bit strings (as strings) and values are probabilities of observing those strings ideal_mean = median probability across all outputs
Return the set of heavy output strings, i.e. those strings whose ideal probability of occurrence exceeds the median. """ return list(filter(lambda x: ideal_distribution[x] > ideal_median,                           list(ideal_distribution.keys())))

计算统计结果,以方便后续展示,包括了用于图形化展示的错误率以及heavy outputs的数值计算。Heavy output的概率存储在变量self._ydata[0][depth_ind]中,根据IBM提出的量子体积,要求该数值大于2/3。其具体的代码实现如下:

def calc_statistics(self): """ Convert the heavy outputs in the different trials into mean and error for plotting
Here we assume the error is due to a binomial distribution """
self._ydata = np.zeros([4, len(self._depths)], dtype=float)
exp_vals = np.zeros(self._ntrials, dtype=float) ideal_vals = np.zeros(self._ntrials, dtype=float)
for depthidx, depth in enumerate(self._depths):
exp_shots = 0
for trialidx in range(self._ntrials): cname = 'qv_depth_%d_trial_%d' % (depth, trialidx) exp_vals[trialidx] = self._heavy_output_counts[cname] exp_shots += self._circ_shots[cname] ideal_vals[trialidx] = self._heavy_output_prob_ideal[cname]
self._ydata[0][depthidx] = np.sum(exp_vals)/np.sum(exp_shots) self._ydata[1][depthidx] = (self._ydata[0][depthidx] * (1.0-self._ydata[0][depthidx]) / self._ntrials)**0.5 self._ydata[2][depthidx] = np.mean(ideal_vals) self._ydata[3][depthidx] = (self._ydata[2][depthidx] * (1.0-self._ydata[2][depthidx])                                        / self._ntrials)**0.5

最终判断计算准确率是否满足要求,对应前面所述的公式,其具体的代码实现为:

def qv_success(self): """Return whether each depth was successful (>2/3 with confidence greater than 97.5) and the confidence
Returns: List of lenth depth with eact element a 3 list with - success True/False - confidence """
success_list = []
for depth_ind, _ in enumerate(self._depths): success_list.append([False, 0.0]) hmean = self._ydata[0][depth_ind] if hmean > 2/3: cfd = 0.5 * (1 + math.erf((hmean - 2/3) / (1e-10 + self._ydata[1][depth_ind])/2**0.5)) success_list[-1][1] = cfd
if cfd > 0.975: success_list[-1][0] = True
        return success_list

三、实例篇

示例代码可参考qiskit源代码中advanced/ignis目录下的7_quantum_volume.ipynb。

实验环境:python 3.6.9,qiskit 0.12.0。

#Import general libraries (needed for functions)import numpy as npimport matplotlib.pyplot as pltfrom IPython import display
#Import Qiskit classes classesimport qiskitfrom qiskit.providers.aer.noise import NoiseModelfrom qiskit.providers.aer.noise.errors.standard_errors import depolarizing_error, thermal_relaxation_error
#Import the qv function.import qiskit.ignis.verification.quantum_volume as qv
#Qubit listqubit_lists = [[0,1,3,5]]
ntrials = 20
qv_circs, qv_circs_nomeas = qv.qv_circuits(qubit_lists, ntrials)
#pass the first trial of the nomeas through the transpiler to illustrate the circuitqv_circs_nomeas[0] = qiskit.compiler.transpile(qv_circs_nomeas[0], basis_gates=['u1','u2','u3','cx'])
print(qv_circs[0][0].qasm())
print("this is the transpiled circuit")
print(qv_circs_nomeas[0][0])
#The Unitary is an identity (with a global phase)backend = qiskit.Aer.get_backend('statevector_simulator')ideal_results = []for trial in range(ntrials): print('Simulating trial %d'%trial) ideal_results.append(qiskit.execute(qv_circs_nomeas[trial], backend=backend, optimization_level=0).result())
qv_fitter = qv.QVFitter(qubit_lists=qubit_lists)qv_fitter.add_statevectors(ideal_results)
noise_model = NoiseModel()p1Q = 0.2p2Q = 0.2noise_model.add_all_qubit_quantum_error(depolarizing_error(p1Q, 1), 'u2')noise_model.add_all_qubit_quantum_error(depolarizing_error(2*p1Q, 1), 'u3')noise_model.add_all_qubit_quantum_error(depolarizing_error(p2Q, 2), 'cx')#noise_model = Noneprint(qv_circs_nomeas[0][0])
backend = qiskit.Aer.get_backend('qasm_simulator')basis_gates = ['u1','u2','u3','cx'] # use U,CX for nowshots = 1024exp_results = []for trial in range(ntrials): print('Running trial %d'%trial) exp_results.append(qiskit.execute(qv_circs[trial], basis_gates=basis_gates, backend=backend, noise_model=noise_model, backend_options={'max_parallel_experiments': 0}).result())
qv_fitter.add_data(exp_results)
plt.figure(figsize=(10, 6))ax = plt.gca()
# Plot the essence by calling plot_rb_dataqv_fitter.plot_qv_data(ax=ax, show_plt=False)
# Add title and labelax.set_title('Quantum Volume for up to %d Qubits \n and %d Trials'%(len(qubit_lists[-1]), ntrials), fontsize=18)
#plt.show()
qv_success_list = qv_fitter.qv_success()qv_list = qv_fitter.ydatafor qidx, qubit_list in enumerate(qubit_lists): if qv_list[0][qidx]>2/3: if qv_success_list[qidx][0]: print("Width/depth %d greater than 2/3 (%f) with confidence %f (successful). Quantum volume %d"% (len(qubit_list),qv_list[0][qidx],qv_success_list[qidx][1],qv_fitter.quantum_volume()[qidx])) else: print("Width/depth %d greater than 2/3 (%f) with confidence %f (unsuccessful)."% (len(qubit_list),qv_list[0][qidx],qv_success_list[qidx][1])) else:        print("Width/depth %d less than 2/3 (unsuccessful)."%len(qubit_list))

在实验中这里我们对量子基础门u2、u3和cx都增加了去极化噪声。实验结果如下。很明显,计算结果不正确。


当把去极化噪声值降低为0.0001,结果如下所示:


实验结果显示错误率能够满足置信度大于0.975,因此,量子体积为16。

四、总结篇

量子计算机基于量子力学原理能够以极大的速度提升和改善量子计算机的处理性能。然而,相较于传统计算机而言,量子计算机仍然处于初级阶段。不同的量子计算机实现方案层出不穷,然而,目前并没有统一的标准来衡量量子计算机不同方面、不同视角的性能指标。

量子体积的概念虽然还存在不少问题,但却是目前较为全面的对量子计算机性能进行综合评价的标准。

Vincent认为,计算机归根结底是一种服务于人类生产生活的工具。量子计算机哪怕性能再优越,依然是服务于人类的一种工具。衡量一个工具的好坏,更多的在于其在某种应用场景中发挥的主要作用。受限于当下量子计算发展的水平,现有的量子计算机仍然难以完整运行一个应用。或许,这就是为什么IBM会选择量子体积作为量子计算机的benchmark。而未来,当量子计算机的规模逐渐增大,可达深度逐渐增加,噪声也越来越小时,相信某些典型的量子应用会逐渐成为量子计算机的benchmark。

参考:

1. Cross A W , BishopL S , Sheldon S , et al. Validating quantum computers using randomized modelcircuits[J]. 2018.

2. Blume-Kohout R , Young K C . A volumetric framework for quantum computer benchmarks[J]. 2019.


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存