TensorFlow Quantum(TFQ)是谷歌在 2020 年 3 月 9 日宣布推出一个用于量子机器学习的 Python 框架,它能够将机器学习和量子计算结合在一起。这个框架可以构造量子数据集,原型混合量子模型和经典机器学习模型,支持量子电路模拟以及训练判别与生成量子模型等操作。
TFQ 使用标准 Keras 函数提供与现有 TensorFlow API 兼容的量子电路模拟器和量子计算原语,可以创建量子模型,同时 TFQ 也不断地在加入量子计算和机器学习研究等方面的必要工具。随着功能的不断完善与拓展,越来越多领域的开发者开始利用 TFQ 与 Cirq 进行量子机器学习方面的研究。
2. 量子机器学习背景量子机器学习(QML)和机器学习在传统神经网络/深度学习方法方面有着重要的相似性和不同点。这两种方法可看作是使用了转换的“堆叠层”,而这正是较大模型的构成要素。在这两种情况下,我们通常会为了最小化某些损失函数,将数据用于通知模型参数更新(大部分情况下如此,但并不完全都是通过基于梯度的方法实现)。这两种方法的不同之处在于,QML 模型可以利用量子力学的相关方法来完成,而深度神经网络则不能。我们会将一种由 TFQ 提供技术支持的重要 QML 称作变分量子电路(QVC)。变分量子电路也可以称作量子神经网络(QNN)。
QVC 如下图所示,可分为三个不同的部分:编码器电路、变分电路和测量运算符。编码器电路可以接收自然量子数据,或将传统数据转化为量子数据。编码器电路连接到变分电路,后者由其可学习参数定义。在学习过程中更新的部分即为电路的参数化部分。
3. 量子位校准误差众所周知,量子计算机可以解决传统计算机不能处理的复杂任务,同时在实际使用场景中,拥有量子比特数越多的量子计算机能够处理的问题越复杂。但由于量子态对环境的恒定干扰及其敏感,会导致错误干扰问题,且量子比特越多,错误积累的速度就越快,系统退相干发生的速度也就越快。由于电路的不完善或外部噪声影响,纠缠的量子比特迟早会出错,所以我们需要对这些错误进行捕捉并纠正。
简单来说,为了纠正误差,研究人员将计算机分为逻辑子系统和辅助子系统。逻辑量子位完成计算机的任务,与逻辑量子位纠缠在一起的辅助量子位控制着它们的工作。研究人员定期测量辅助量子位的状态,如果该状态与预期的状态非常不同,则向逻辑子系统发送校正脉冲。
本文将介绍如何利用 TFQ 及 Cirq 框架来处理经典神经网络中量子位校准误差的问题,具体操作步骤如下:
首先我们需要在本地安装 TensorFlow:
pipinstalltensorflow==2.7.0
接着安装 TensorFlow Quantum 模块,为确保正确安装,需输出验证结果。
pipinstalltensorflow-quantum#Updatepackageresourcestoaccountforversionchanges.
importimportlib,pkg_resources
importlib.reload(pkg_resources)
验证结果为:
<module'pkg_resources'from'/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/pkg_resources/__init__.py'>
之后我们需要导入 TensorFlow 和模块依赖项并验证安装情况:
importtensorflowastf
importtensorflow_quantumastfq
importcirq
importsympy
importnumpyasnp
#visualizationtools
%matplotlibinline
importmatplotlib.pyplotasplt
fromcirq.contrib.svgimportSVGCircuit
验证结果:
2022-07-1917:41:31.765071:Ctensorflow/stream_executor/cuda/cuda_driver.cc:271]failedcalltocuInit:CUDA_ERROR_NO_DEVICE:noCUDA-capabledeviceisdetected
到这一步,安装完毕。
3.1 TFQ及Cirq功能简介在正式开始使用 TensorFlow Quantum(TFQ)之前,有必要先介绍一下它及 Cirq 框架的一些基础知识。
3.1.1 Cirq 和参数化量子电路Cirq 是 Google 用于量子计算的 Python 库,使用的是 SymPy 符号来表示自由参数。如下列代码所示:
a,b=sympy.symbols('ab')
在实际使用过程中,我们可以使用 Cirq 来定义电路:包括静态门和参数化门。比如,我们可以使用自定参数创建一个双量子位电路,代码如下:
#Createtwoqubits
q0,q1=cirq.GridQubit.rect(1,2)#Createacircuitonthesequbitsusingtheparametersyoucreatedabove.
circuit=cirq.Circuit(
cirq.rx(a).on(q0),
cirq.ry(b).on(q1),cirq.CNOT(control=q0,target=q1))SVGCircuit(circuit)
findfont:Fontfamily['Arial']notfound.FallingbacktoDejaVuSans.
双量子位电路如下:
如果需要评估电路,我们可以使用 cirq.Simulator 接口。通过传入 cirq.ParamResolver 对象,将电路中的自由参数替换为特定的数字。下面的代码计算了我们参数化电路的原始状态矢量输出:
#Calculateastatevectorwitha=0.5andb=-0.5.
resolver=cirq.ParamResolver({a:0.5,b:-0.5})
output_state_vector=cirq.Simulator().simulate(circuit,resolver).final_state_vector
output_state_vector
array([0.9387913 0.j,-0.23971277 0.j,0. 0.06120872j,0.-0.23971277j],dtype=complex64)
因为状态向量在模拟之外是不能直接访问的(注意上面输出中的复数)。为了达到物理上的真实性,我们必须指定一个测量值,这个测量值将状态向量转换为经典计算机可以理解的实数。Cirq 使用泡利算子的 、 和 的组合来指定测量。作为说明,以下代码在刚刚模拟的状态向量上测量 和 :
z0=cirq.Z(q0)qubit_map={q0:0,q1:1}z0.expectation_from_state_vector(output_state_vector,qubit_map).real
结果为:
0.8775825500488281
z0x1=0.5*z0 cirq.X(q1)z0x1.expectation_from_state_vector(output_state_vector,qubit_map).real
结果为:
-0.04063427448272705
3.1.2 张量量子电路
TensorFlow Quantum (TFQ) 提供了 tfq.convert_to_tensor模块,这是一个将 Cirq 对象转换为张量的函数。它允许你将 Cirq 对象发送到量子层和量子操作中。这个函数可以在 Cirq Circuits 和 Cirq Paulis 的列表或数组上调用,如下所示:
#Rank1tensorcontaining1circuit.
circuit_tensor=tfq.convert_to_tensor([circuit])print(circuit_tensor.shape)
print(circuit_tensor.dtype)
(1,)
<dtype:'string'>
这会将 Cirq 对象编码为tf.string tensors张量,tfq操作根据需要对其进行解码。
#Rank1tensorcontaining2Paulioperators.
pauli_tensor=tfq.convert_to_tensor([z0,z0x1])
pauli_tensor.shape
TensorShape([2])
3.1.3 配料电路模拟
TFQ 提供了用于计算期望值、样本和状态向量的方法。在 TFQ 中,用于计算期望值的最高级别接口是tfq.layer.Expectation层,它是层级中最简单的表示形式,相当于在多个层上模拟参数化电路。但是,TFQ 允许按照 TensorFlow 的语义进行批处理,并且使用高效的 C 代码模拟电路。我们可以利用tf.keras.Layercirq.ParamResolvers来创建一批值来替换我们的参数:ab
batch_vals=np.array(np.random.uniform(0,2*np.pi,(5,2)),dtype=np.float32)
平时我们在 Cirq 中对参数值的电路进行批处理需要执行一个循环:
cirq_results=[]
cirq_simulator=cirq.Simulator()forvalsinbatch_vals:
resolver=cirq.ParamResolver({a:vals[0],b:vals[1]})
final_state_vector=cirq_simulator.simulate(circuit,resolver).final_state_vector
cirq_results.append(
[z0.expectation_from_state_vector(final_state_vector,{
q0:0,
q1:1
}).real])print('cirqbatchresults:\n{}'.format(np.array(cirq_results)))
循环输出的结果为:
cirqbatchresults:
[[-0.66652703]
[0.49764055]
[0.67326665]
[-0.95549959]
[-0.81297827]]
在 TFQ 中简化了相同的操作:
tfq.layers.Expectation()(circuit,
symbol_names=[a,b],
symbol_values=batch_vals,
operators=z0)
结果为:
<tf.Tensor:shape=(5,1),dtype=float32,numpy=
array([[-0.666526],
[0.49764216],
[0.6732664],
[-0.9554999],
[-0.8129788]],dtype=float32)>
3.2 混合量子-经典优化
了解完 TFQ 及 Cirq 的基础知识及功能后,让我们使用 TFQ 构建一个混合量子 - 经典神经网络。我们将训练一个经典的神经网络来控制单个量子位。操作过程中,我们需要控制优化以正确制备处于 叠加状态的量子比特,从而克服模拟的系统校准误差。下图显示了体系结构:01
3.2.1 受控电路定义定义一个可学习的单比特旋转,如上图所示。这将对应于我们的受控电路。
#ParametersthattheclassicalNNwillfeedvaluesinto.
control_params=sympy.symbols('theta_1theta_2theta_3')#Createtheparameterizedcircuit.
qubit=cirq.GridQubit(0,0)
model_circuit=cirq.Circuit(
cirq.rz(control_params[0])(qubit),
cirq.ry(control_params[1])(qubit),
cirq.rx(control_params[2])(qubit))SVGCircuit(model_circuit)
接下来,定义控制器网络:
#Theclassicalneuralnetworklayers.
controller=tf.keras.Sequential([
tf.keras.layers.Dense(10,activation='elu'),
tf.keras.layers.Dense(3)
])
给定一批命令,控制器为受控电路输出的一批控制信号。控制器是随机初始化的,因此这些输出还没有开始发挥它们的作用。
controller(tf.constant([[0.0],[1.0]])).numpy()
输出统计:
array([[0.,0.,0.],
[0.5815686,0.21376055,0.57181627]],dtype=float32)
3.2.3 将控制器连接到电路
使用TFQ将控制器作为单个keras.Model连接到受控电路上。
完成这一步之后,我们首先需要定义模型的输入,具体操作代码如下所示:
#Thisinputisthesimulatedmiscalibrationthatthemodelwilllearntocorrect.
circuits_input=tf.keras.Input(shape=(),
#Thecircuit-tensorhasdtype`tf.string`
dtype=tf.string,
name='circuits_input')#Commandswillbeeither`0`or`1`,specifyingthestatetosetthequbitto.
commands_input=tf.keras.Input(shape=(1,),
dtype=tf.dtypes.float32,
name='commands_input')
接下来对这些输入进行运算,为定义计算做准备。
dense_2=controller(commands_input)#TFQlayerforclassicallycontrolledcircuits.
expectation_layer=tfq.layers.ControlledPQC(model_circuit,
#ObserveZ
operators=cirq.Z(qubit))
expectation=expectation_layer([circuits_input,dense_2])
现在将这个计算打包为tf.keras.Model包:
#ThefullKerasmodelisbuiltfromourlayers.
model=tf.keras.Model(inputs=[circuits_input,commands_input],
outputs=expectation)
将输出模型图与体系架构图进行比较,以验证正确性。需要注意的是,可能需要系统安装了graphviz软件包才能够完成验证。
tf.keras.utils.plot_model(model,show_shapes=True,dpi=70)
此模型接受两个输入:控制器的命令,以及控制器尝试校正其输出的输入电路。
3.2.4 数据集该模型尝试为每个命令输出正确的测量值。这些命令以及正确的值定义如下。
#ThecommandinputvaluestotheclassicalNN.
commands=np.array([[0],[1]],dtype=np.float32)#ThedesiredZexpectationvalueatoutputofquantumcircuit.
expected_outputs=np.array([[1],[-1]],dtype=np.float32)
这并非是这项任务全部的训练数据集。数据集中的每个数据点也需要一个输入电路。
3.2.5 输入电路定义下面的输入电路定义了模型,能够将学习校正的随机误差校准。
random_rotations=np.random.uniform(0,2*np.pi,3)
noisy_preparation=cirq.Circuit(
cirq.rx(random_rotations[0])(qubit),
cirq.ry(random_rotations[1])(qubit),
cirq.rz(random_rotations[2])(qubit)
)
datapoint_circuits=tfq.convert_to_tensor([
noisy_preparation
]*2)#Maketwocopiedofthiscircuit
该电路中有两个副本,每个数据点一个副本。
datapoint_circuits.shape
TensorShape([2])
3.2.6 训练
在定义好输入之后,你就可以测试运行TFQ模型了。方法如下:
model([datapoint_circuits,commands]).numpy()
结果输出为:
array([[0.95853525],
[0.6272128]],dtype=float32)
现在运行一个标准的训练过程,将这些值调整到expected_outputs包中。
optimizer=tf.keras.optimizers.Adam(learning_rate=0.05)
loss=tf.keras.losses.MeanSquaredError()
model.compile(optimizer=optimizer,loss=loss)
history=model.fit(x=[datapoint_circuits,commands],
y=expected_outputs,
epochs=30,
verbose=0)
plt.plot(history.history['loss'])
plt.title("LearningtoControlaQubit")
plt.xlabel("Iterations")
plt.ylabel("ErrorinControl")
plt.show()
具体输出结果也可以用图片形式来展现:
从这个图中可以看出,神经网络已经学会了克服系统性的误差校准。随着不断迭代,误差校准的程度也越越来越好。
3.2.7 验证输出现在我们使用训练好的模型,来纠正量子位校准误差。这里可以使用 Cirq 完成:
defcheck_error(command_values,desired_values):
"""Basedonthevaluein`command_value`seehowwellyoucouldprepare
thefullcircuittohave`desired_value`whentakingexpectationw.r.t.Z."""
params_to_prepare_output=controller(command_values).numpy()
full_circuit=noisy_preparation model_circuit#Testhowwellyoucanprepareastatetogetexpectationtheexpectation
#valuein`desired_values`
forindexin[0,1]:
state=cirq_simulator.simulate(
full_circuit,
{s:vfor(s,v)inzip(control_params,params_to_prepare_output[index])}
).final_state_vector
expt=cirq.Z(qubit).expectation_from_state_vector(state,{qubit:0}).real
print(f'Foradesiredoutput(expectation)of{desired_values[index]}with'
f'noisypreparation,thecontroller\nnetworkfoundthefollowing'
f'valuesfortheta:{params_to_prepare_output[index]}\nWhichgivesan'
f'actualexpectationof:{expt}\n')check_error(commands,expected_outputs)
Foradesiredoutput(expectation)of[1.]withnoisypreparation,thecontroller
networkfoundthefollowingvaluesfortheta:[-0.67884220.3395225-0.59394693]
Whichgivesanactualexpectationof:0.9171845316886902Foradesiredoutput(expectation)of[-1.]withnoisypreparation,thecontroller
networkfoundthefollowingvaluesfortheta:[-5.203663-0.295285763.2887425]
Whichgivesanactualexpectationof:-0.9511058330535889
训练期间损失函数的值提供了该模型学习情况的大致概念。损失函数值越低,上述单元格中的期望值就越接近 。如果你不太关心参数值,则可以使用tfq:desired_values检查上面的输出:
model([datapoint_circuits,commands])
<tf.Tensor:shape=(2,1),dtype=float32,numpy=
array([[0.91718477],
[-0.9511056]],dtype=float32)>
3.3 不同算子的特征状态
对应于 1 和 0 的 特征状态是任意的。你也可以很容易地让 1 对应于 特征状态,让 0 对应于 特征状态。实现这个目的其中的一种方法是为每个命令指定一个不同的测量算子,如下图所示:
使用上述方法之后,你的输入已经增长到了三个对象,包括:电路、命令和运算符。输出仍然是期望值tfq.layers.Expectation。
3.3.1 新模型定义让我们来看一下完成这项任务的模型:
#Defineinputs.
commands_input=tf.keras.layers.Input(shape=(1),
dtype=tf.dtypes.float32,
name='commands_input')
circuits_input=tf.keras.Input(shape=(),
#Thecircuit-tensorhasdtype`tf.string`
dtype=tf.dtypes.string,
name='circuits_input')
operators_input=tf.keras.Input(shape=(1,),
dtype=tf.dtypes.string,
name='operators_input')
下面展示的是控制器网络:
#DefineclassicalNN.
controller=tf.keras.Sequential([
tf.keras.layers.Dense(10,activation='elu'),
tf.keras.layers.Dense(3)
])
使用tfq将电路和控制器合并成一个Keras.Model模型:
dense_2=controller(commands_input)#Sinceyouaren'tusingaPQCorControlledPQCyoumustappend
#yourmodelcircuitontothedatapointcircuittensormanually.
full_circuit=tfq.layers.AddCircuit()(circuits_input,append=model_circuit)
expectation_output=tfq.layers.Expectation()(full_circuit,
symbol_names=control_params,
symbol_values=dense_2,
operators=operators_input)#ContructyourKerasmodel.
two_axis_control_model=tf.keras.Model(
inputs=[circuits_input,commands_input,operators_input],
outputs=[expectation_output])
3.3.2 数据集
定义了新的模型后,在数据集方面可以拿到为每个数据点进行测量的运算符Model_circuit.
#Theoperatorstomeasure,foreachcommand.
operator_data=tfq.convert_to_tensor([[cirq.X(qubit)],[cirq.Z(qubit)]])#ThecommandinputvaluestotheclassicalNN.
commands=np.array([[0],[1]],dtype=np.float32)#Thedesiredexpectationvalueatoutputofquantumcircuit.
expected_outputs=np.array([[1],[-1]],dtype=np.float32)
3.3.3 训练
现在,我们已经有了新的输入和输出,可以使用 keras 再次进行训练。
optimizer=tf.keras.optimizers.Adam(learning_rate=0.05)
loss=tf.keras.losses.MeanSquaredError()two_axis_control_model.compile(optimizer=optimizer,loss=loss)history=two_axis_control_model.fit(
x=[datapoint_circuits,commands,operator_data],
y=expected_outputs,
epochs=30,
verbose=1)
输出的结果为:
Epoch1/30
1/1[==============================]-0s320ms/step-loss:2.4404
Epoch2/30
1/1[==============================]-0s3ms/step-loss:1.8713
Epoch3/30
1/1[==============================]-0s3ms/step-loss:1.1400
Epoch4/30
1/1[==============================]-0s3ms/step-loss:0.5071
Epoch5/30
1/1[==============================]-0s3ms/step-loss:0.1611
Epoch6/30
1/1[==============================]-0s3ms/step-loss:0.0426
Epoch7/30
1/1[==============================]-0s3ms/step-loss:0.0117
Epoch8/30
1/1[==============================]-0s3ms/step-loss:0.0032
Epoch9/30
1/1[==============================]-0s2ms/step-loss:0.0147
Epoch10/30
1/1[==============================]-0s3ms/step-loss:0.0452
Epoch11/30
1/1[==============================]-0s3ms/step-loss:0.0670
Epoch12/30
1/1[==============================]-0s3ms/step-loss:0.0648
Epoch13/30
1/1[==============================]-0s3ms/step-loss:0.0471
Epoch14/30
1/1[==============================]-0s3ms/step-loss:0.0289
Epoch15/30
1/1[==============================]-0s3ms/step-loss:0.0180
Epoch16/30
1/1[==============================]-0s3ms/step-loss:0.0138
Epoch17/30
1/1[==============================]-0s2ms/step-loss:0.0130
Epoch18/30
1/1[==============================]-0s3ms/step-loss:0.0137
Epoch19/30
1/1[==============================]-0s3ms/step-loss:0.0148
Epoch20/30
1/1[==============================]-0s3ms/step-loss:0.0156
Epoch21/30
1/1[==============================]-0s3ms/step-loss:0.0157
Epoch22/30
1/1[==============================]-0s3ms/step-loss:0.0149
Epoch23/30
1/1[==============================]-0s3ms/step-loss:0.0135
Epoch24/30
1/1[==============================]-0s3ms/step-loss:0.0119
Epoch25/30
1/1[==============================]-0s3ms/step-loss:0.0100
Epoch26/30
1/1[==============================]-0s3ms/step-loss:0.0082
Epoch27/30
1/1[==============================]-0s3ms/step-loss:0.0064
Epoch28/30
1/1[==============================]-0s3ms/step-loss:0.0047
Epoch29/30
1/1[==============================]-0s3ms/step-loss:0.0034
Epoch30/30
1/1[==============================]-0s3ms/step-loss:0.0024
plt.plot(history.history['loss'])
plt.title("LearningtoControlaQubit")
plt.xlabel("Iterations")
plt.ylabel("ErrorinControl")
plt.show()
同样的,我们可以通过图片形式来直观展现出训练的结果如何:
可以看到损失函数已降至零。说明训练效果非常不错,完成了对于误差的校准。
另外,它还能够作为独立模型使用。调用控制器,并检查它对每个命令信号的响应。要正确的将这些输出与controllerrandom_rotations的内容进行比较需要以下代码操作来完成。
controller.predict(np.array([0,1]))
输出结果:
array([[3.6335812,1.8470774,0.71675825],
[5.3085413,0.08116499,2.8337662]],dtype=float32)
至此,我们完成了如何利用TFQ来纠正经典神经网络中量子位校准误差的问题。对于TFQ来说,这只是其中能够完成的众多功能中的一个,具体还能够实现哪些功能,那就需要我们不断地去学习了。
参考链接:Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved