量子生成对抗网络
生成对抗网络是由两部分神经网络组成,分别为生成器和判别器。量子生成对抗网络的基本原理与经典的GAN基本相同。
生成对抗网络由GoodFellow等人提出,主要功能是生成伪造的样本。生成器G的输入为一个随机向量z,输出为一个生成样本G(z)。判别器D的输入为一个真实的或生成的样本x,输出为对该样本的判断。当输入真实样本x时,判别器的输出为D(x),接近1。当输入生成样本G(z)时,判别器的输出为D(G(z)),接近0。
GAN的优化目标函数可以表示为:
参数化量子线路
量子生成对抗网络所用的参数化量子线路主要由三部分组成:旋转层、叠加层和纠缠层
旋转层由旋转门Ry(θ) 组成
叠加层使用的是双量子比特门
其中 旋转层由旋转门组成。叠加层使用的是双量子比特门
相比起神经网络,多了一个叠加层,主要是因为量子资源和设备的限制,退相干会导致系统内部的相互作用关系发生变化,影响了系统的纠缠程度,进而影响QGAN中生成器和判别器的功能,而叠加层可以减少这种影响。
量子判别器和量子生成器都采用前述的参数化量子线路
QGAN通过经典计算机和量子计算机之间的迭代切换,找到参数化量子线路的最优参数
QGAN将保真度作为目标函数
,因此用交换测试得到保真度
量子判别器之后量子态为,量子生成器之后量子态为,保真度要尽量接近0
量子判别器之后量子态为
,真实样本为,保真度要尽量接近1
因此
训练量子判别器时要最小化
和
训练量子生成器时要最小化
生成一个带有数字3或9的图片,真实图片由手写数字3和9组成,特征为2维
代码
#qiskit版本>1.0.0
import random
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from qiskit import QuantumRegister, ClassicalRegister,transpile
from qiskit import QuantumCircuit
from qiskit_aer import Aer
from math import pi
from qiskit import *
import tensorflow as tf
from sklearn.decomposition import PCA
import time
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patheffects as PathEffects
#数据准备
test_images,test_labels = tf.keras.datasets.mnist.load_data()
train_images = test_images[0].reshape(60000,784)
train_labels = test_images[1]
labels = test_images[1]
train_images = train_images/255
k=2
pca = PCA(n_components=k)
pca.fit(train_images)
pca_data = pca.transform(train_images)[:10000]
train_labels = train_labels[:10000]
t_pca_data = pca_data.copy()
pca_descaler = [[] for _ in range(k)]
for i in range(k):
if pca_data[:,i].min() < 0:
pca_descaler[i].append(pca_data[:,i].min())
pca_data[:,i] += np.abs(pca_data[:,i].min())
else:
pca_descaler[i].append(pca_data[:,i].min())
pca_data[:,i] -= pca_data[:,i].min()
pca_descaler[i].append(pca_data[:,i].max())
pca_data[:,i] /= pca_data[:,i].max()
pca_data_rot= 2*np.arcsin(np.sqrt(pca_data))
valid_labels = None
valid_labels = train_labels==9
valid_labels = train_labels == 3
pca_data_rot = pca_data_rot[valid_labels]
pca_data = pca_data[valid_labels]
#利用特征重构图像
def descale_points(d_point,scales=pca_descaler,tfrm=pca):
for col in range(d_point.shape[1]):
d_point[:,col] *= scales[col][1]
d_point[:,col] += scales[col][0]
reconstruction = tfrm.inverse_transform(d_point)
return reconstruction
learning_rate=0.01
#初始化判别器和生成器参数
thetaD=[np.random.rand()*np.pi for i in range(4)]
thetaG=[np.random.rand()*np.pi for i in range(4)]
#定义数组分别保存更新后判别器和生成器的参数
thetaD_new=[0,0,0,0]
thetaG_new=[0,0,0,0]
#保存被加载的真数据
data=[0,0]
#定义训练判别器的量子线路
circuit=QuantumCircuit(5,5)
for i in range(1,3):
circuit.ry(thetaD[i-1],i)
circuit.ryy(thetaD[2],1,2)
circuit.cry(thetaD[3],1,2)
for i in range(1,3):
circuit.ry(thetaG[i-1],i+2)
circuit.ryy(thetaG[2],3,4)
circuit.cry(thetaG[3],3,4)
circuit.barrier(0,1,2,3,4)
circuit.h(0)
for i in range(1,3):
circuit.cswap(0,i,i+2)
circuit.h(0)
circuit.measure(0,0)
circuit.draw(output='mpl', plot_barriers=False)
#定义训练生成器的量子线路
circuit1=QuantumCircuit(5,5)
for i in range(1,3):
circuit1.ry(thetaD[i-1],i)
circuit1.ryy(thetaD[2],1,2)
circuit1.cry(thetaD[3],1,2)
circuit1.ry(data[0],3)
circuit1.ry(data[1],4)
circuit1.barrier(0,1,2,3,4)
circuit1.h(0)
for i in range(1,3):
circuit1.cswap(0,i,i+2)
circuit1.h(0)
circuit1.measure(0,0)
circuit1.draw(output='mpl', plot_barriers=False)
#定义生成器线路,便于得到训练后生成的数据
circuit2=QuantumCircuit(2,2)
circuit2.ry(thetaG[0],0)
circuit2.ry(thetaG[1],1)
circuit2.ryy(thetaG[2],0,1)
circuit2.cry(thetaG[3],0,1)
circuit2.measure(0,0)
circuit2.measure(1,1)
circuit2.draw(output='mpl')
value1=0
value2=0
f_diff=0
b_diff=0
backend=Aer.get_backend('qasm_simulator')
for epoch in range(0,50):
print(f'第--{epoch}--次训练')
par_shift = 0.5*np.pi
# 通过circuit线路,使用假数据训练判别器
for i in range(1):
for j in range(0,4):
thetaD[j]+=par_shift
# Set up the backend
backend = Aer.get_backend('qasm_simulator')
transpiled_qc = transpile(circuit, backend)
# Run the transpiled circuit
job_sim1 = backend.run(transpiled_qc, shots=2000)
sim_result1 = job_sim1.result()
measurement_result1 = sim_result1.get_counts(circuit)
value1=2*(measurement_result1['00000']/2000-0.5)
if value1 <= 0.005:
value1 = 0.005
f_diff=-np.log(1-value1)
thetaD[j]-=2*par_shift
backend = Aer.get_backend('qasm_simulator')
transpiled_qc = transpile(circuit, backend)
# Run the transpiled circuit
job_sim1 = backend.run(transpiled_qc, shots=2000)
sim_result1 = job_sim1.result()
measurement_result1 = sim_result1.get_counts(circuit)
value2=2*(measurement_result1['00000']/2000-0.5)
if value2 <= 0.005:
value2 = 0.005
b_diff=-np.log(1-value2)
thetaD[j]+=par_shift
df=0.5*(f_diff-b_diff)
if abs(df)>1:
df = df/abs(df)
thetaD_new[j]=thetaD[j]-learning_rate*df/10
thetaD=thetaD_new
# 使用circuit1线路训练判别器
for index,point in enumerate(pca_data_rot):
data[0] = point[0]
data[1] = point[1]
for j in range(0,4):
thetaD[j]+=par_shift
backend = Aer.get_backend('qasm_simulator')
transpiled_qc1 = transpile(circuit1, backend)
# Run the transpiled circuit
job_sim = backend.run(transpiled_qc1, shots=1000)
sim_result = job_sim.result()
measurement_result = sim_result.get_counts(circuit1)
value1=2*(measurement_result['00000']/1000-0.5)
if value1 <= 0.005:
value1 = 0.005
f_diff=-np.log(value1)
thetaD[j]-=2*par_shift
backend = Aer.get_backend('qasm_simulator')
transpiled_qc1 = transpile(circuit1, backend)
# Run the transpiled circuit
job_sim = backend.run(transpiled_qc1, shots=1000)
sim_result = job_sim.result()
measurement_result = sim_result.get_counts(circuit1)
value2=2*(measurement_result['00000']/1000-0.5)
if value2 <= 0.005:
value2 = 0.005
thetaD[j]+=par_shift
b_diff=-np.log(value2)
df=0.5*(f_diff-b_diff)
thetaD_new[j]=thetaD[j]-learning_rate*df/10
thetaD=thetaD_new
# 通过circuit线路,利用判别器训练生成器
for i in range(len(pca_data_rot)//10):
for j in range(0,4):
thetaG[j]+=par_shift
backend = Aer.get_backend('qasm_simulator')
transpiled_qc = transpile(circuit, backend)
# Run the transpiled circuit
job_sim = backend.run(transpiled_qc, shots=1000)
sim_result = job_sim.result()
measurement_result = sim_result.get_counts(circuit)
value1=2*(measurement_result['00000']/1000-0.5)
if value1 <= 0.005:
value1 = 0.005
f_diff=-np.log(value1)
thetaG[j]-=2*par_shift
backend = Aer.get_backend('qasm_simulator')
transpiled_qc = transpile(circuit, backend)
# Run the transpiled circuit
job_sim = backend.run(transpiled_qc, shots=1000)
sim_result = job_sim.result()
measurement_result = sim_result.get_counts(circuit)
value2=2*(measurement_result['00000']/1000-0.5)
if value2 <= 0.005:
value2 = 0.005
thetaG[j]+=par_shift
b_diff=-np.log(value2)
df=0.5*(f_diff-b_diff)
thetaG_new[j]=thetaG[j]-learning_rate*df*5
thetaG=thetaG_new
data = []
n_results = 2
#使用训练好的生成器生成数据并使用逆PCA生成图像
for _ in range(16):
backend = Aer.get_backend('qasm_simulator')
transpiled_qc2 = transpile(circuit2, backend)
# Run the transpiled circuit
job = backend.run(transpiled_qc2, shots=1000)
results = job.result()
measurement_result2 = results.get_counts(circuit2)
bins = [[0,0] for _ in range(n_results)]
for key,value in measurement_result2.items():
for i in range(n_results):
if key[-i-1]== '1':
bins[i][0] += value
bins[i][1] += value
for i,pair in enumerate(bins):
bins[i]= pair[0]/pair[1]
data.append(bins)
data = np.array(data)
new_info = descale_points(data[:16])
new_info = new_info.reshape(new_info.shape[0],28,28)
print(f"Epoch {epoch} Generated Images")
for i in range(new_info.shape[0]):
plt.subplot(4, 4, i+1)
plt.imshow(new_info[i, :, :], cmap='gray')
plt.axis('off')
plt.show()