新聞中心

隆重推出用於加速量子超級計算的 NVIDIA CUDA-QX 庫 NEWS DETAIL

當前位置:首頁 > 新聞中心
資訊分類 · 新聞中心 發佈時間 · 2025-01-17


加速量子超級計算將人工智慧超級計算的優勢與 量子處理器(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 梯度計算