VQNet 安装步骤

VQNet python包安装

我们提供了Linux, Windows, macOS 13+ (arm64) 上的python预编译包供安装,需要 python3.10, python3.11, python3.12

安装命令如下:

pip install pyvqnet --upgrade

如在Linux遇到如下GLBCXX问题:

ImportError: /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /home/whc/miniforge3/envs/py310/lib/python3.10/site-packages/pyvqnet/libs/libvqnet.so)

可更新libstdcxx库,例如:

conda install -c conda-forge "libstdcxx-ng>=12"

对于Windows, Linux系统, pyvqnet软件包自带基于Nvidia CUDA对经典神经网络计算加速功能,依赖于CUDA11.8的特定版本 NVIDIA CUDA 运行时库(随软件包自动安装)。 软件包编译时针对以下 CUDA 架构进行了优化: sm_80 (NVIDIA A100, A30 系列数据中心 GPU) 和 sm_86 (NVIDIA GeForce RTX 30 系列消费级 GPU),请确保使用支持上述架构的 GPU,否则程序可能无法正常运行。

重要

请注意,由于本软件包不区分CPU/GPU版本,在windows下和Linux均依赖NVIDIA CUDA 运行时库,其随软件自动安装,可能会与当前环境下依赖不同版本的其他软件(例如基于cuda12的torch)产生冲突。

相关库版本如下:

"nvidia-cublas-cu11==11.11.3.6",
"nvidia-cuda-runtime-cu11==11.8.89",
"nvidia-nccl-cu11== 2.19.3",
"nvidia-cuda-cupti-cu11==11.8.87",
"nvidia-cuda-nvrtc-cu11==11.8.89",
"nvidia-cufft-cu11==10.9.0.58",
"nvidia-cusolver-cu11==11.4.1.48",
"nvidia-cusparse-cu11==11.7.5.86",
"nvidia-nvtx-cu11==11.8.86",
"nvidia-curand-cu11==10.3.0.86",

VQNet 测试安装成功

import pyvqnet
from pyvqnet.tensor import *
a = arange(1,25).reshape([2, 3, 4])
print(a)

VQNet 测试GPU功能

from pyvqnet import DEV_GPU_0
from pyvqnet.tensor import *
a = ones([4,5],device = DEV_GPU_0)
print(a)

VQNet 的一个简单例子

这里使用VQNet的经典神经网络模块以及量子模块完成一个机器学习模型的整体流程的例子介绍。该例子参考 Data re-uploading for a universal quantum classifier 。 量子机器学习中的量子计算模块一般有如下几个部分:

(1)编码线路(Encoder),用于将经典数据编码到量子数据; (2)可变参数的量子线路(Ansatz),用于训练带参量子门中的参数; (3)测量模块(Measurement),用于检测测量值(也就是某个量子比特的量子态在某些轴上的投影)。

量子计算模块与经典神经网络的运算模块一样是可微分的,是量子经典神经网络混合模型的理论基础。 VQNet支持将量子计算模块与经典计算模块(例如: 卷积,池化,全连接层,激活函数等)一起构成混合机器学习模型,提供多种优化算法优化参数。

../_images/classic-quantum.PNG

在量子计算模块,VQNet支持使用本源量子高效的量子软件计算包 pyqpanda3 进行量子模块构建。 使用pyQPanda3提供的各种常用接口,用户可以快速构建量子计算模块。

接下来的例子我们使用pyQPanda3构建了一个量子计算模块。通过VQNet,该量子计算模块可以直接嵌入到混合机器学习模型中进行量子线路参数训练。 本例使用1个量子比特,使用了多个带参数的旋转门 RZ,`RY`,`RZ` 对输入x进行编码,并使用 probs_measure 函数观测量子比特的概率测量结果作为输出。

import pyqpanda3.core as pq
from pyvqnet.qnn.pq3 import probs_measure
def qdrl_circuit(input,weights):
    qlist = range(1)
    machine = pq.CPUQVM()
    x1 = input.squeeze()
    param1 = weights.squeeze()
    #使用pyqpanda3接口构建量子线路实例
    circult = pq.QCircuit()
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位x1[0]
    circult << pq.RZ(qlist[0], x1[0])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RY门,参数位x1[1]
    circult << pq.RY(qlist[0], x1[1])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位x1[2]
    circult << pq.RZ(qlist[0], x1[2])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位param1[0]
    circult << pq.RZ(qlist[0], param1[0])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RY门,参数位param1[1]
    circult << pq.RY(qlist[0], param1[1])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位param1[2]
    circult << pq.RZ(qlist[0], param1[2])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位x1[0]
    circult << pq.RZ(qlist[0], x1[0])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RY门,参数位x1[1]
    circult << pq.RY(qlist[0], x1[1])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位x1[2]
    circult << pq.RZ(qlist[0], x1[2])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位param1[3]
    circult << pq.RZ(qlist[0], param1[3])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RY门,参数位param1[4]
    circult << pq.RY(qlist[0], param1[4])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位param1[5]
    circult << pq.RZ(qlist[0], param1[5])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位x1[0]
    circult << pq.RZ(qlist[0], x1[0])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RY门,参数位x1[1]
    circult << pq.RY(qlist[0], x1[1])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位x1[2]
    circult << pq.RZ(qlist[0], x1[2])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位param1[6]
    circult << pq.RZ(qlist[0], param1[6])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RY门,参数位param1[7]
    circult << pq.RY(qlist[0], param1[7])
    #使用pyqpanda3接口在第一个量子比特上插入逻辑门RZ门,参数位param1[8]
    circult << pq.RZ(qlist[0], param1[8])
    #构建量子程序
    prog = pq.QProg()
    prog << circult
    #获取概率测量值
    prob = probs_measure(machine ,prog,  qlist)

    return prob

本例子中机器学习的任务是对随机生成的数据根据进行二分类,其中下图是该数据样例,零为圆点,半径为1以内红色的二维点为一类,蓝色的点为另一类。

../_images/origin_circle.png

训练测试代码流程

#导入必须的库和函数
from pyvqnet.qnn.pq3.quantumlayer import QuantumLayer
from pyvqnet.optim import adam
from pyvqnet.nn.loss import CategoricalCrossEntropy
from pyvqnet.tensor import QTensor
import numpy as np
from pyvqnet.nn.module import Module

定义模型Model,其中 __init__ 函数定义内部各个神经网络模块以及量子模块,`forward` 函数定义前传函数。QuantumLayer 为封装量子计算的抽象类。 您只需将刚才定义的量子计算函数 qdrl_circuit,待训练参数个数 param_num ,运行后端配置 “cpu” , 量子比特数 qbit_num 输入参数,该类就在 VQNet 中自动计算参数梯度。

#待训练参数个数
param_num = 9
#量子计算模块量子比特数
qbit_num  = 1
#定义一个继承于Module的机器学习模型类
class Model(Module):
    def __init__(self):
        super(Model, self).__init__()
        #使用QuantumLayer类,可以把带训练参数的量子线路纳入VQNet的自动微分的训练流程中
        self.pqc = QuantumLayer(qdrl_circuit,param_num)
    #定义模型前向函数
    def forward(self, x):
        x = self.pqc(x)
        return x

定义一些训练模型需要的函数

# 随机产生待训练数据的函数
def circle(samples:int,  rads =  np.sqrt(2/np.pi)) :
    data_x, data_y = [], []
    for i in range(samples):
        x = 2*np.random.rand(2) - 1
        y = [0,1]
        if np.linalg.norm(x) < rads:
            y = [1,0]
        data_x.append(x)
        data_y.append(y)
    return np.array(data_x,dtype=np.float32), np.array(data_y,np.int64)

# 数据载入函数
def get_minibatch_data(x_data, label, batch_size):
    for i in range(0,x_data.shape[0]-batch_size+1,batch_size):
        idxs = slice(i, i + batch_size)
        yield x_data[idxs], label[idxs]

#计算准确率的函数
def get_score(pred, label):
    pred, label = np.array(pred.data), np.array(label.data)
    pred = np.argmax(pred,axis=1)
    score = np.argmax(label,1)
    score = np.sum(pred == score)
    return score

VQNet遵循机器学习一般的训练测试流程: 迭代进行载入数据,前传计算,损失函数计算,反向计算,更新参数的操作。

#实例化定义的模型
model = Model()
#定义一个优化器,这里用的是Adam
optimizer = adam.Adam(model.parameters(),lr =0.6)
#定义一个损失函数,这里用的交叉熵损失函数
Closs = CategoricalCrossEntropy()

训练模型部分的函数

def train():

    # 随机产生待训练数据
    x_train, y_train = circle(500)
    x_train = np.hstack((x_train, np.zeros((x_train.shape[0], 1),dtype=np.float32)))
    # 定义每个批次训练的数据个数
    batch_size = 32
    # 最大训练迭代次数
    epoch = 10
    print("start training...........")
    for i in range(epoch):
        model.train()
        accuracy = 0
        count = 0
        loss = 0
        for data, label in get_minibatch_data(x_train, y_train,batch_size):
            # 优化器中缓存梯度清零
            optimizer.zero_grad()
            # 模型前向计算
            output = model(data)
            # 损失函数计算
            losss = Closs(label, output)
            # 损失反向传播
            losss.backward()
            # 优化器参数更新
            optimizer._step()
            # 计算准确率等指标
            accuracy += get_score(output,label)

            loss += losss.item()
            count += batch_size

        print(f"epoch:{i}, train_accuracy:{accuracy/count}")
        print(f"epoch:{i}, train_loss:{loss/count}\n")

验证模型部分的函数

def test():

    batch_size = 1
    model.eval()
    print("start eval...................")
    xtest, y_test = circle(500)
    test_accuracy = 0
    count = 0
    x_test = np.hstack((xtest, np.zeros((xtest.shape[0], 1),dtype=np.float32)))

    for test_data, test_label in get_minibatch_data(x_test,y_test, batch_size):

        test_data, test_label = QTensor(test_data),QTensor(test_label)
        output = model(test_data)
        test_accuracy += get_score(output, test_label)
        count += batch_size

    print(f"test_accuracy:{test_accuracy/count}")

训练测试结果图:

start training...........
epoch:0, train_accuracy:0.6145833333333334
epoch:0, train_loss:0.020432369535168013

epoch:1, train_accuracy:0.6854166666666667
epoch:1, train_loss:0.01872217481335004

epoch:2, train_accuracy:0.8104166666666667
epoch:2, train_loss:0.016634768371780715

epoch:3, train_accuracy:0.7479166666666667
epoch:3, train_loss:0.016975031544764835

epoch:4, train_accuracy:0.7875
epoch:4, train_loss:0.016502128106852372

epoch:5, train_accuracy:0.8083333333333333
epoch:5, train_loss:0.0163204787299037

epoch:6, train_accuracy:0.8083333333333333
epoch:6, train_loss:0.01634311651190122

epoch:7, train_loss:0.016330583145221074

epoch:8, train_accuracy:0.8125
epoch:8, train_loss:0.01629052646458149

epoch:9, train_accuracy:0.8083333333333333
epoch:9, train_loss:0.016270687493185203

start eval...................
test_accuracy:0.826
../_images/qdrl_for_simple.png