IBM Qiskit量子机器学习速成(一)

声明:本篇笔记基于IBM Qiskit量子机器学习教程的第一节,中文版译文详见:https://blog.csdn.net/qq_33943772/article/details/129860346?spm=1001.2014.3001.5501

概述

首先导入关键的包

from qiskit import QuantumCircuit
from qiskit.utils import algorithm_globals
from qiskit.circuit import Parameter, ParameterVector
from qiskit.quantum_info import SparsePauliOp
from qiskit_machine_learning.neural_networks import EstimatorQNN, SamplerQNN

尤其注意qiskit_machine_learning包需要额外安装(如果你是Anaconda用户,特别注意需要先激活相应虚拟环境),参考指令如下

pip install qiskit_machine_learning

另外,由于接下来的程序中涉及随机数,我们需要指定全局的随机数种子:

# qiskit_machine_learning需要另外安装
algorithm_globals.random_seed = 42

我们知道,机器学习的本质是确定问题本身的结构后对某些参数进行学习。例如,我们对人的身高和体重之间的关系很感兴趣,我们先假设二者之间存在线性关系 y = k x + b y=kx+b y=kx+b,也就是确定了二者之间的结构,从而对参数 k , b k,b k,b进行学习。而学习过程本身就是对参数的调节,使模型最大程度上符合问题的描述。

一般而言,参数化的量子电路分为三个部分:

  • 数据加载:input
  • 数据处理:weight
  • 测量结果

搭建神经网络

一般而言,我们会用到两种量子神经网络,分别是EstimatorQNN和SamplerQNN。顾名思义,EstimatorQNN是用来“估计”某个算符的期望值的,而SamplerQNN是用来计算量子态的。

例如,我们想估算某个力学量(比如说哈密顿量 H ^ \hat H H^)的期望值,我们就可以构建一个包含该哈密顿量 H ^ \hat H H^的EstimatorQNN。

当我们对量子态的分布更感兴趣时,也就是,我们更感兴趣初始态经过电路的操作后会变成哪几种量子态(最简单的情形是加一个哈达玛门,从而结果是 ∣ 0 > + ∣ 1 > 2 \dfrac{\left|0\right>+\left|1\right>}{\sqrt 2} 2 0+1)。

但是需要注意,在机器学习中,问题必须带有参数!我们可以这样理解SamplerQNN:通过调整电路中的某些参数,使得某些量子态的分布达到极大或极小。

EstimatorQNN的创建

EstimatorQNN创建时只需要以下几个部分:

  • 一个已经写好的参数化电路
  • 力学观测量(可选,如果不特别说明的话,其实计算的就是单位矩阵的期望值)
  • 输入参数(input_params)
  • 权重参数(weight_params)

例如,我们可以通过以下方式创建参数(或参数向量)和参数化电路

params1 = [Parameter("input1"), Parameter("weight1")]
qc1 = QuantumCircuit(1)
qc1.h(0)
qc1.ry(params1[0], 0)
qc1.rx(params1[1], 0)

随后,通过泡利矩阵构造力学量(或可观测量)

observable1 = SparsePauliOp.from_list([("Y" * qc1.num_qubits, 1)])

组合以上部分,直接写入参数,即可得到一个EstimatorQNN

estimator_qnn = EstimatorQNN(
    circuit=qc1,
    observables=observable1,
    input_params=[params1[0]],
    weight_params=[params1[1]]
)

SamplerQNN的创建

SamplerQNN创建时只需要以下几个参数:

  • 一个已经写好的参数化电路
  • 输入参数(input_params)
  • 权重参数(weight_params)

可以看出,SamplerQNN也需要参数化电路(毕竟机器学习就是调节参数),它直接从末态读取结果(二进制字符串或非负整数)。不同的是,SamplerQNN提供interpret方法,你可以重写这个方法,来对结果进行解释。例如,QAOA中将结果解释为划分的区域。但是一旦外部重写interpret方法,必须显式指定
output_shape,因为Qiskit无法自动推断结果。

首先,声明输入和权重参数,并创建参数化电路。

inputs2 = ParameterVector("input", 2)
weights2 = ParameterVector("weight", 4)

qc2 = QuantumCircuit(2)
qc2.ry(inputs2[0], 0)
qc2.ry(inputs2[1], 1)
qc2.cx(0, 1)
qc2.ry(weights2[0], 0)
qc2.ry(weights2[1], 1)
qc2.cx(0, 1)
qc2.ry(weights2[2], 0)
qc2.ry(weights2[3], 1)

进而创建SamplerQNN:

sampler_qnn = SamplerQNN(circuit=qc2,
                         input_params=inputs2,
                         weight_params=weights2)

前向传播神经网络(运行神经网络)

IBM Qiskit量子机器学习速成(一)_第1张图片

当我们搭建好神经网络后,就需要执行神经网络了。一般来说,我们首先需要给定输入值和权重的初始值(注意,关键在于权重)。随后我们就可以获得运行的结果了。前向传播神经网络需要使用神经网络对象的forward方法

初始化参数

出于演示的目的,我们此处随机地设定输入值和权重值。

estimator_qnn_input = algorithm_globals.random.random(estimator_qnn.num_inputs)
estimator_qnn_weights = algorithm_globals.random.random(estimator_qnn.num_weights)
sampler_qnn_input = algorithm_globals.random.random(sampler_qnn.num_inputs)
sampler_qnn_weights = algorithm_globals.random.random(sampler_qnn.num_weights)

数据的输入分为非分批输入(non-batched input)和分批输入(batched input)

非分批输入

非分批输入即直接输入全部参数,属于最简单、最直接的输入方式。当然,在数据集过大的情况下,这种输入方式不利于神经网络的训练。

estimator_qnn_forward = estimator_qnn.forward(estimator_qnn_input, estimator_qnn_weights)
print(
    f"Forward pass result for EstimatorQNN: {estimator_qnn_forward}. \nShape: {estimator_qnn_forward.shape}"
)

sampler_qnn_forward = sampler_qnn.forward(sampler_qnn_input, sampler_qnn_weights)
print(
    f"Forward pass result for SamplerQNN: {sampler_qnn_forward}.  \nShape: {sampler_qnn_forward.shape}"
)
分批输入

分批输入即将数据集先裁剪成适当大小(例如6x6、32x32大小的数据矩阵),再输入神经网络。

estimator_qnn_forward_batched = estimator_qnn.forward(
    [estimator_qnn_input, estimator_qnn_input], estimator_qnn_weights
)
print(
    f"Forward pass result for EstimatorQNN: {estimator_qnn_forward_batched}.  \nShape: {estimator_qnn_forward_batched.shape}"
)

sampler_qnn_forward_batched = sampler_qnn.forward(
    [sampler_qnn_input, sampler_qnn_input], sampler_qnn_weights
)
print(
    f"Forward pass result for SamplerQNN: {sampler_qnn_forward_batched}.  \nShape: {sampler_qnn_forward_batched.shape}"
)

反向传递(优化神经网络/训练神经网络)

反向传递会根据神经网络前向传播的结果,来优化权重参数。反向传递需要使用神经网络对象的backward方法

estimator_qnn_input_grad, estimator_qnn_weight_grad = estimator_qnn.backward(
    estimator_qnn_input, estimator_qnn_weights
)
print(
    f"Input gradients for EstimatorQNN: {estimator_qnn_input_grad}.  \nShape: {estimator_qnn_input_grad}"
)
print(
    f"Weight gradients for EstimatorQNN: {estimator_qnn_weight_grad}.  \nShape: {estimator_qnn_weight_grad.shape}"
)

sampler_qnn_input_grad, sampler_qnn_weight_grad = sampler_qnn.backward(
    sampler_qnn_input, sampler_qnn_weights
)
print(
    f"Input gradients for SamplerQNN: {sampler_qnn_input_grad}.  \nShape: {sampler_qnn_input_grad}"
)
print(
    f"Weight gradients for SamplerQNN: {sampler_qnn_weight_grad}.  \nShape: {sampler_qnn_weight_grad.shape}"
)

总结

  • 声明参数(Parameter或ParameterVector)并创建参数化电路
  • 传入EstimatorQNN或SamplerQNN,一般格式:xxxQNN(circuit, inputs, weights)
    (Estimator可能需要额外导入力学量矩阵)
  • 前向传递:xxxQNN.forward(inputs, weights) 分为无批次或有批次(有批次时直接将inputs换为多个数据组的列表,[input_list1, input_list2…])
  • 反向传播:xxxQNN.backward(inputs, weights)

你可能感兴趣的:(机器学习,人工智能,python,神经网络)