查看原文
其他

QPanda 2教程资源 | VQNET中的​优化算法(梯度下降法)和综合示例QAOA

OriginQ 本源量子 2021-02-13


嗨~周末好啊

上篇为大家推送了

可变量子逻辑门、可变量子线路

今天小编要介绍的是

优化算法(梯度下降法)和综合示例QAOA

跟我们一起来学习吧!



上期回顾


QPanda 2教程资源 | VQNET中的可变量子逻辑门和可变量子线路


    



在上一篇文章中,小编为大家介绍了VQNet中的可变量子逻辑门和可变量子线路。

可变量子逻辑门(VariationalQuantumGate,别名:VQG)。内部维护着一组变量参数以及一组常量参数。在构造VQG的时候只能对其中一组参数进行赋值。若含有一组常量参数,则可以通过VQG生成含确定参数的普通量子逻辑门, 若含有变量参数,则可以动态修改参数值,并生成对应的参数的普通量子逻辑门。

在VQNet中量子操作qop和qop_pmeasure都需要使用可变量子线路作为参数。可变量子线路(VariationalQuantumCircuit,别名VQC)是用来存储含有可变参数的量子线路信息,VQC主要由可变量子逻辑门(VQG)组成。

接下来,小编给大家介绍的是优化算法(梯度下降法)和综合示例QAOA

优化算法(梯度下降法)

本章节将讲解VQNet中优化算法的使用,包括经典梯度下降算法和改进后的梯度下降算法,它们都是在求解机器学习算法的模型参数,即无约束优化问题时,最常采用的方法之一。我们在QPanda::Variational中实现了这些算法,

VanillaGradientDescentOptimizer、MomentumOptimizer、AdaGradOptimizer、RMSPropOptimizer和AdamOptimizer,它们都继承自Optimizer。

接口介绍

我们通过调用梯度下降优化器的minimize接口来生成一个优化器。常见的梯度下降优化器构造方式如下所示。

VanillaGradientDescentOptimizer::minimize(  

    loss,   // 损失函数  

    0.01,   // 学习率  

    1.e-6); // 结束条件  


MomentumOptimizer::minimize(  

    loss,   // 损失函数  

    0.01,   // 学习率  

    0.9);   // 动量系数  

  

AdaGradOptimizer::minimize(  

    loss,   // 损失函数  

    0.01,   // 学习率  

    0.0,    // 累加量起始值  

    1.e-10);// 很小的数值以避免零分母  

  

RMSOptimizer::minimize(  

    loss,   // 损失函数  

    0.01,   // 学习率  

    0.9,    // 历史或即将到来的梯度的贴现因子  

    1.e-10);// 很小的数值以避免零分母  

  

AdamOptimizer::minimize(  

    loss,   // 损失函数  

    0.01,   // 学习率  

    0.9,    // 一阶动量衰减系数  

    0.999,  // 二阶动量衰减系数  

    1.e-10);// 很小的数值以避免零分母

实例

示例代码主要演示对离散点用直线进行拟合,我们定义训练数据X和Y,这两个变量表示离散点的坐标。定义两个可微分的变量w和b,其中w表示斜率b表示y轴截距。定义变量Y下划线表示斜率w乘上变量x加上截距。

接着我们定义损失函数loss。计算变量Y和变量Y下划线之间的均方值。

我们调用梯度下降优化器的minimize接口以损失函数,学习率和结束条件作为参数构造生成一个经典梯度下降优化器。

我们通过优化器的get_variables接口可以获得所有可微分的节点。

我们定义迭代次数为1000。然后调用优化器的run接口执行一次优化操作,其第二个参数表示当前的优化次数,目前只有AdamOptimizer这个优化器使用到了这个参数,其它优化器我们直接给0值即可。

我们可以通过优化器get_loss接口获得当前优化后的损失值。我们通过eval接口可以求得可微分变量的当前值。

#include "Variational/Optimizer.h"  

  

int main()  

{  

    using namespace QPanda::Variational;  

  

    MatrixXd train_x(17, 1);  

    MatrixXd train_y(17, 1);  

  

    train_x(0, 0) = 3.3;        train_x(1, 0) = 4.4;         train_x(2, 0) = 5.5;

    train_x(3, 0) = 6.71;      train_x(4, 0) = 6.93;        train_x(5, 0) = 4.168;

    train_x(6, 0) = 9.779;    train_x(7, 0) = 6.182;      train_x(8, 0) = 7.59; 

    train_x(9, 0) = 2.167;    train_x(10, 0) = 7.042;    train_x(11, 0) = 10.791;

    train_x(12, 0) = 5.313;  train_x(13, 0) = 7.997;    train_x(14, 0) = 5.654;

    train_x(15, 0) = 9.27;    train_x(16, 0) = 3.1;        train_y(0, 0) = 1.7;

    train_y(1, 0) = 2.76;      train_y(2, 0) = 2.09;       train_y(3, 0) = 3.19; 

    train_y(4, 0) = 1.694;    train_y(5, 0) = 1.573;     train_y(6, 0) = 3.366;   

    train_y(7, 0) = 2.596;    train_y(8, 0) = 2.53;       train_y(9, 0) = 1.221;

    train_y(10, 0) = 2.827;  train_y(11, 0) = 3.465;   train_y(12, 0) = 1.65;  

    train_y(13, 0) = 2.904;  train_y(14, 0) = 2.42;     train_y(15, 0) = 2.94; 

    train_y(16, 0) = 1.3;  

  

    var X(train_x);  

    var Y(train_y);  

  

    var W(1.0, true);  

    var b(1.0, true);  

  

    var Y_ = W * X + b;  

    auto loss = sum(poly(Y - Y_, 2) / train_x.rows());  

    auto optimizer = VanillaGradientDescentOptimizer::minimize(loss, 0.01, 1.e-6);  

  

    auto leaves = optimizer->get_variables();  

    for (size_t i = 0u; i < 1000; i++)  

    {  

        optimizer->run(leaves);  

        std::cout << "i: " << i << "\t" << optimizer->get_loss()  

            << "\t W:" << QPanda::Variational::eval(W, true)  

            << "\t b:" << QPanda::Variational::eval(b, true)  

            << std::endl;  

    }  

  

    return 0;  

}  


我们将散列点和拟合的直线进行绘图。

综合示例QAOA

QAOA是众所周知的量子经典混合算法。对于n对象的MAX-CUT问题,需要n个量子位来对结果进行编码,其中测量结果(二进制串)表示问题的切割配置。

我们通过VQNet可以有效地实现MAX-CUT问题的QAOA算法。VQNet中QAOA的流程图如下所示。

我们给定一个MAX-CUT的问题如下。

首先,我们输入MAX-CUT问题的图形信息,并构造相应的问题哈密顿量。

PauliOperator getHamiltonian()  

{  

    PauliOperator::PauliMap pauli_map{  

        {"Z0 Z4", 0.73},{"Z2 Z5", 0.88},  

        {"Z0 Z5", 0.33},{"Z2 Z6", 0.58},  

        {"Z0 Z6", 0.50},{"Z3 Z5", 0.67},  

        {"Z1 Z4", 0.69},{"Z3 Z6", 0.43},  

        {"Z1 Z5", 0.36}  

    };  

  

    return PauliOperator(pauli_map);  

}  

然后,使用哈密顿量和待优化的变量参数x,构建QAOA的vqc。QOP的输入参数是问题哈密顿量、VQC、一组量子比特和量子运行环境。QOP的输出是问题哈密顿量的期望。在这个问题中,损失函数是问题哈密顿量的期望,因此需要最小化QOP的输出。我们通过使用梯度下降优化器MomentumOptimizer来优化vqc中的变量x。

#include "Core/QPanda.h"  

#include "Operator/PauliOperator.h"  

#include "Variational/var.h"  

#include "Variational/expression.h"  

#include "Variational/utils.h"  

#include "Variational/Optimizer.h"  

#include <fstream>  

  

using namespace std;  

using namespace QPanda;  

using namespace QPanda::Variational;  

  

VQC parity_check_circuit(QVec &qubit_vec)  

{  

    VQC circuit;  

    for (auto i = 0; i < qubit_vec.size() - 1; i++)  

    {  

        circuit.insert( VQG_CNOT(  

            qubit_vec[i],  

            qubit_vec[qubit_vec.size() - 1]));  

    }  

  

    return circuit;  

}  

  

VQC simulateZTerm(  

    QVec &qubit_vec,  

    var coef,  

    var t)  

{  

    VQC circuit;  

    if (0 == qubit_vec.size())  

    {  

        return circuit;  

    }  

    else if (1 == qubit_vec.size())  

    {  

        circuit.insert(VQG_RZ(qubit_vec[0], coef * t*-1));  

    }  

    else  

    {  

        circuit.insert(parity_check_circuit(qubit_vec));  

        circuit.insert(VQG_RZ(qubit_vec[qubit_vec.size() - 1], coef * t*-1));  

        circuit.insert(parity_check_circuit(qubit_vec));  

    }  

  

    return circuit;  

}  

  

VQC simulatePauliZHamiltonian(  

    QVec& qubit_vec,  

    const QPanda::QHamiltonian & hamiltonian,  

    var t)  

{  

    VQC circuit;  

  

    for (auto j = 0; j < hamiltonian.size(); j++)  

    {  

        QVec tmp_vec;  

        auto item = hamiltonian[j];  

        auto map = item.first;  

  

        for (auto iter = map.begin(); iter != map.end(); iter++)  

        {  

            if ('Z' != iter->second)  

            {  

                QCERR("Bad pauliZ Hamiltonian");  

                throw std::string("Bad pauliZ Hamiltonian.");  

            }  

  

            tmp_vec.push_back(qubit_vec[iter->first]);  

        }  

  

        if (!tmp_vec.empty())  

        {  

            circuit.insert(simulateZTerm(tmp_vec, item.second, t));  

        }  

    }  

  

    return circuit;  

}  

  

int main()  

{  

    PauliOperator op = getHamiltonian();  

  

    QuantumMachine *machine = initQuantumMachine();  

    QVec qlist;  

    for (int i = 0; i < op.getMaxIndex(); ++i)  

        qlist.push_back(machine->allocateQubit());  

  

    VQC vqc;  

    for_each(qlist.begin(), qlist.end(), [&vqc](Qubit* qbit)  

    {  

        vqc.insert(VQG_H(qbit));  

    });  

  

    int qaoa_step = 4;  

  

    var x(MatrixXd::Random(2 * qaoa_step, 1), true);  

  

    for (auto i = 0u; i < 2*qaoa_step; i+=2)  

    {  

        vqc.insert(simulatePauliZHamiltonian(qlist, op.toHamiltonian(), x[i + 1]));  

        for (auto _q : qlist) {  

            vqc.insert(VQG_RX(_q, x[i]));  

        }  

    }  

  

    var loss = qop(vqc, op, machine, qlist);  

    auto optimizer = MomentumOptimizer::minimize(loss, 0.02, 0.9);  

  

    auto leaves = optimizer->get_variables();  

    constexpr size_t iterations = 100;  

    for (auto i = 0u; i < iterations; i++)  

    {  

        optimizer->run(leaves);  

        std::cout << " iter: " << i << " loss : " << optimizer->get_loss() << std::endl;  

    }  

  

    QProg prog;  

    QCircuit circuit = vqc.feed();  

    prog << circuit;  

  

    directlyRun(prog);  

    auto result = quickMeasure(qlist, 100);  

  

    for (auto i:result)  

    {  

        std::cout << i.first << " : " << i.second << " ";  

    }  

  

    return 0;  

}  

我们将测量的结果绘制出柱状图,可以看到'0001111'和'1110000'这两个比特串测量得到的概率最大,也正是我们这个问题的解。


★以上即为QPanda 2优化算法(梯度下降法)和综合示例QAOA部分的详细内容介绍。

★感兴趣的欢迎加入"QPanda 2开发交流群"。(关注“本源量子”公众号,回复“加群”,联系小编即可)

★PC端学习量子计算请登录learn-quantum.com 

★掌上学习请下载"本源溯知APP"

★如有疑问可上量子互动论坛,与行业大神进行交流讨论。


获取更多QPanda 2教程资源,请点击“阅读原文”。


往期精彩回顾

量子程序序列化以及解析量子程序的二进制文件

逻辑门以及量子程序时钟周期统计

量子门的有效性及判断方法

量子比特的测量方法:量子测量和概率测量

QPanda 2最常用的量子计算模型——量子线路

嗨玩本源QPanda 2,从量子逻辑门实例开始学起!

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

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