4006605680

迈络思交换机,mellanox交换机,迈络思IB网卡,迈络思IB交换机,迈络思线缆,迈络思网卡,无线ap,英伟达,NVIDIA, Mellanox交换机, Mellanox 高速以太网交换机, 低延迟 Mellanox 交换机, 数据中心, Mellanox 交换机, 高性能计算, Mellanox 交换机, 云计算用 Mellanox 交换机, Mellanox 交换机网络带宽
目前位置:首页>>新闻中心

隆重推出用于加速量子超级计算的 NVIDIA CUDA-QX 库

发布时间:2025-01-17 09:28:38


加速量子超级计算将人工智能超级计算的优势与 量子处理器(QPUs) 相结合,为世界上一些最棘手的问题开发解决方案。实现此类设备需要将一个或多个 QPUs 无缝集成到传统的 CPU 和 GPU 超级计算架构中。

任何加速量子超级计算机的基本组成部分都是与之交互的编程模型。这必须经过高度优化,不仅可以运行真正的混合量子经典应用,还可以同时管理对 QPU 硬件的控制。这涉及编排实时量子纠错(QEC)等任务,这使得开发高性能和可扩展的混合应用极具挑战性。

开源 NVIDIA CUDA-Q 平台 正是提供了这样一种编程模型,能够帮助研究人员和开发者解决在实施加速量子超级计算方面的挑战。

在 SC24 上,NVIDIA 宣布推出 CUDA-QX :这是 CUDA-Q 的扩展,由经过优化的库组成,可直接提供 CUDA-Q 强大的编程模型,以应对研究人员在探索有用的量子计算时所面临的关键挑战。

CUDA-QX 为关键量子计算基元提供了优化的内核和 API(图 1)。这降低了研究人员和开发者使用 CUDA-Q 的 GPU 加速的门槛,让您有更多的时间专注于新科学和应用开发,而不是代码优化。通过将 AI 超级计算工具无缝集成到量子研究工作流程中,CUDA-QX 可促进未来量子计算的突破。

A diagram shows CUDA-QX connecting to the CUDA-Q QEC and CUDA-Q Solvers libraries on top of NVIDIA CUDA-Q and then accelerated quantum supercomputing.

图 1、CUDA-QX 架构

本文将介绍前两个 CUDA-QX 库:

  • CUDA-Q QEC: 加速量子错误纠正(QEC)研究。

  • CUDA-Q 求解器: 一组针对特定领域问题(如量子化学)的优化量子求解器。

本文提供了使用 PyTorch 和 cuOpt 的示例,重点介绍了这些库如何快速加速研究和应用开发。

CUDA-Q QEC 

当今的量子处理单元(QPU)与开发有用的量子计算机之间的最大挑战之一是量子比特噪声。实用的容错量子计算采用量子纠错编码(QEC)来识别、跟踪和纠正错误。鉴于量子纠错编码的复杂性以及解码量子纠错编码的严格实时处理要求,这是一项极具挑战性的任务。

CUDA-Q QEC 库支持将加速 QEC 基元无缝集成到 CUDA-Q 工作流程中。现在,您可以使用 CUDA-QX 随附的标准 QEC 代码和解码器,或更换自己的代码和解码器,从而获得敏捷研究所需的灵活性。

这也使 CUDA-Q QEC 成为用来试验如何为 QEC 部署 AI 算法并模拟其大规模性能的理想工具。

工作中的 CUDA-Q QEC:代码容量噪声模型 

一个非常适合 CUDA-Q QEC 库的用例是,在代码容量假设下,预测 QEC 代码和解码器对对应的逻辑错误率。

逻辑错误会对 QEC 代码造成灾难性影响,并导致无法保存量子数据。使用 CUDA-Q QEC 进行模拟有助于了解逻辑错误的频率与各种条件下 QEC 代码和解码器选择的关系。

在使用 CUDA-Q QEC 之前,第一步是安装 CUDA-QX 并导入必要的库。

import numpy as np                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
import cudaq_qec as qec

接下来,选择要学习的 QEC 代码。CUDA-Q QEC 有几个内置选项,例如 Surface 代码和 Steane 代码,但您也可以定义自己的 QEC 代码,并将其插入同一工作流。

steane = qec.get_code("steane")

奇偶校验矩阵由一组稳定器算子定义,这些算子可用于测量错误综合征,从而推断错误位置。您可以使用 CUDA-Q QEC 来提取 Steane 代码的奇偶校验矩阵。

对于 Steane 代码等 CSS 代码,请选择完整代码,或仅选择用于纠正位翻转(X)或相位翻转(Z)错误的奇偶校验矩阵。同样,也可以提取用于确定逻辑量子位状态如何在 Steane 代码中冗余表示的映射。

Hz = steane.get_parity_z()
Hx = steane.get_parity_x()
H = steane.get_parity()
observable  = steane.get_observables_z()

在运行任何分析之前,最后一步是定义解码器,该算法根据随代码进展从奇偶校验测量中获得的错误综合症数据,计算对错误位置的猜测。

您可以根据解码器选择和奇偶校验矩阵构建解码器。您还可以输入自定义解码器,或使用 QEC 库中内置的其中一种现成方法。在本示例中,查找表(Lookup Table,LUT)解码器用于 CUDA-Q QEC 中预定义的 Steane 解码器。

decoder = qec.get_decoder("steane_lut_decoder", Hz)

无噪音结果为 0 位字符串,对应于初始逻辑状态无变化。为了模拟该 QEC 编码器/解码器对的性能,我们使用了一个简单的模型来引入错误。我们对任何给定的数据量子位引入了位翻转误差,概率为 p=0.1

A diagram shows the Steane code procedure performed on the probability of a data qubit bit flip error in the following code example.

图 2. 使用 Steane 代码进行代码容量分析的示意图表示

代码容量程序用于评估 QEC 编码器/解码器对的性能。以下代码示例对此进行了概述,如图 2 所示。该过程会迭代几个镜头,每个镜头对应一个随机噪声数据位字符串。数据位字符串用于计算错误综合征、解码它们,并确定是否发生逻辑状态翻转。

在真实的量子计算中,只有错误综合症是可访问的,因为对数据量子位的任何其他观察都会损害编码的逻辑状态。然而,在此模拟过程中,可以使用更详细的数据进行分析。这可用于评估解码器对逻辑状态翻转的预测是否实际上对应于真实的逻辑翻转。

如果解码器作出了错误的预测,则会发生逻辑错误,并且可以记录下来。解码器与实际数据不匹配的截图百分比是逻辑错误率。

# Probability of a data qubit bit flip error
p = 0.1
 
 
nShots = 10
nLogicalErrors = 0
 
for i in range(nShots):
 
    # Generate noisy data                                                                                                                                                                                                                                                         
    data = qec.generate_random_bit_flips(Hz.shape[1], p)                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                     
    # Calculate which syndromes are flagged                                                                                                                                                                                                                                       
    syndrome = Hz@data % 2                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                    
    # Decode syndromes to determine predicted observables                                                                                                                                                                                                                                                                              
    result = decoder.decode(syndrome)                                                                                                                                                                                                                                             
    data_prediction = np.array(result.result, dtype=np.uint8)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    predicted_observable = observable@data_prediction % 2                                                                                                                                                                                                                             
                                                                                                                                                                                                                               
    # Determine actual observables directly from the data                                                                                                                                                                                                                                                                              
    actual_observable = observable@data % 2                                                                                                                                                                                                                                           
     
    # Add to counter if logical error occurred                                                                                                                                                                                                                                 
    if (predicted_observable != actual_observable):
        nLogicalErrors += 1                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                    
# Print the logical error rate
print(nLogicalErrors/nShots)

为方便起见,您还可以使用单个函数调用生成此代码示例中显式执行的代码容量过程。

syndromes, data = qec.sample_code_capacity(Hz, nShots, p).

代码容量练习的结果非常有用,可以阐明物理错误率对逻辑错误率的影响。

图 3 显示了物理错误率不同的代码容量结果。这种分析可以扩展到电路级噪声模型,以研究子阈值扩展,并确定物理错误率的详细要求,从而提供适合给定应用的逻辑错误率。

A line plot shows the physical error rate against the logical error rate for the Steane code capacity analysis.

图 3. Steane 代码的代码容量结果

对 QEC 代码执行电路级噪声分析最便捷的方法是调用 sample_memory_circuit 函数,并提供 QEC 代码和 噪声模型 。分析也略有变化,必须指定 QEC 轮次数以及每轮生成的采样数或综合征数。

syndromes, data = qec.sample_memory_circuit(steane, numShots, numRounds, noise=noise)

只要您提供足够的映射以生成正确的稳定器电路,sample_memory_circuit 函数即可与自定义 QEC 代码兼容,该过程在后台处理内置代码(如 Steane 代码)。

有关 CUDA-Q QEC 用法的更多信息 (包括 C++ 实现、表面代码示例和完整的电路级噪声建模工作流程),请参阅 CUDA-Q QEC 文档 

CUDA-Q 求解器 

CUDA-Q 求解器库由不透明方法组成,可轻松加速多个标准量子应用,包括变分量子特征求解器(VQE)、ADAPT-VQE 和 QAOA。

虽然求解器在许多量子应用中无处不在,但化学是部署频率最高、前景最好的用例之一。CUDA-Q 求解器目前正与 GE Vernova 高级研究合作,模拟能量材料。

鉴于化学应用的重要性,以下各节将带您浏览一个典型示例,演示 CUDA-Q 求解器在准备具有活跃空间的氮分子(而非氧气分子)ADAPT-VQE 模拟方面的效用。

CUDA-Q 求解器的工作原理:准备具有活跃空间的分子

在 QPU 上执行之前,许多量子算法都需要经典的预处理步骤。这在化学应用中尤其如此,通常需要初步经典计算来准备初始状态。

大型模拟通常必须使用所谓的活跃空间近似值,以减少在量子计算机上对分子的电子结构进行建模所需的资源。以下示例将引导您在应用 ADAPT-VQE 之前,使用 CUDA-Q 求解器库构建一个活跃空间。

第一步是安装 CUDA-QX 并导入必要的库:

import cudaq, cudaq_solvers as solvers
import numpy as np
from scipy.optimize import minimize

接下来,使用 create_molecule 准备分子。它接受大多数量子化学软件包中可能熟悉的标准输入,例如几何图形、基集、电荷和多重性。

geometry=[('N', (0.0, 0.0, 0.5600)), ('N', (0.0,0.0, -0.5600))]
molecule = solvers.create_molecule(geometry,
                                            'sto-3g',    #basis set
                                            0,           #charge
                                            0,           #multiplicity
                                            nele_cas=2,
                                            norb_cas=3,
                                            ccsd=True,
                                            casci=True,
                                            verbose=True)

要指定活跃空间,请分别使用 nele_cas 和 norb_cas 设置电子和轨道的数量。将 ccsd 或 casci 设置为 True 还可在分子初始化时根据活跃空间经典地计算这些能量。使用 print(molecule.energies) 打印每个计算的能量。

CUDA-Q 求解器为改进不同轨道的主动空间计算提供了更大的灵活性。有关使用 MP2 自然轨道和 CASSCF 轨道的示例的更多信息,请参阅 CUDA-QX 文档 

CUDA-Q 求解器的实际应用:加速 ADAPT-VQE 

自适应微分组装 Pseudo-Trotter VQE(ADAPT-VQE)是一种求解器技术,可根据预定义的算子池迭代构建 ansatz,从而更高效地收敛到预测基态能量(图 4)。借助 CUDA-Q 求解器库,您可以轻松使用并加速 ADAPT-VQE。

The diagram shows the ADAPT-VQE workflow, which iteratively builds an ansatz from an operator pool to more efficiently converge to a ground state energy.

图 4、ADAPT-VQE 程序 (来源: 量化门错误对变分量子特征求解器在量子化学中的影响 )

定义分子后 (请参阅前面的 预处理 部分),只需几个步骤即可生成 ADAPT-VQE 解决方案。首先,从分子中提取电子数和量子位数。

numQubits = molecule.n_orbitals * 2
numElectrons = molecule.n_electrons

接下来,cudaqx.solvers.get_operator_pool 函数从通用 ansatz 中提取所有运算符,并将每个运算符乘以初始参数列表,以形成完整的运算符池 (op_pool_uccsd)。在本例中,我们使用 UCCSD ansatz,但 CUDA-Q 求解器也支持广义单双 ansatz (GSD)。

# Extract operators
operators=solvers.get_operator_pool("uccsd",
                                            num_qubits=numQubits,
                                            num_electrons=numElectrons)
 
# Retrieve number of operators                                           
count=len(operators)
 
# Make a list of initial parameters
init_params=[0.05]*count
print(init_params)
 
# Make final operator pool form operators and parameters
op_pool_uccsd=[1j*coef*op for coef,op in zip(init_params, operators)]

求解前的最后一步是准备一个初始 Hartree-Fock 状态作为后续的 CUDA-Q 核,其中使用位翻转运算来指定活动空间中的占用轨道。

@cudaq.kernel
def initState(q: cudaq.qview):
    for i in range(numElectrons):
        x(q[i])

ADAPT-VQE 求解器会获取初始状态核、使用 molecule.hamiltonian 构建的 Jordan-Wigner Hamiltonian 和一个经典优化器 (在本例中取自 SciPy)。默认情况下,该过程在单个 NVIDIA GPU 上进行模拟,但您也可以轻松切换到物理 QPU 后端。

energy, thetas, ops = solvers.adapt_vqe(initState,
                                                molecule.hamiltonian,
                                                op_pool_uccsd,
                                                optimizer=minimize,
                                                method='L-BFGS-B',
                                                jac='3-point',
                                                tol=1e-7)
print('Adapt-VQE energy: ', energy)
print('Optimum pool operators: ', [op.to_string(False) for op in ops])

CUDA-Q 求解器可轻松加速诸如 ADAPT-VQE 之类的应用程序,还可让您跨多个 QPU 模拟并行计算。您可以使用 GPU 进行模拟。

要模拟跨多个 QPU 运行的计算,请使用 cudaq.set_target(‘nvidia’, mqpu=’True’) 和 cuadq.mpi.initialize 指定 MQPU 目标 。然后可以调用前面描述的相同 ADAPT-VQE 代码,然后再调用 cuadq.mpi.finalize

通过使用这种模拟的多 QPU 方法,16 量子位(8 个轨道中的 6 个电子)昂贵的梯度计算速度提高了 4.5 倍,而无需对代码进行大量修改(图 5)

A line chart shows the time to compute the gradient in seconds is accelerated with multiple NVIDIA H100 GPUs, up to 4.5x faster with six GPUs.

图 5、在多个 GPU 上使用 CUDA-Q 求解器加速 ADAPT-VQE 梯度计算