Quantum Machine Learning Part 4

Quantum Generative Adversarial Networks (QGANs)

In the last two articles, we looked at quantum algorithms such as variational quantum eigen solver, quantum classifiers and variational quantum classifier.  In this article, we look at Quantum Generative Adversarial Networks (QGANs).

In classical machine learning, Generative Adversarial Networks (GANs) are tools. A generator is used to create statistics for data.  It tries to mimic the current data set. A discriminator differentiates between the real and fake data. The learning process for generator and discriminator converges. The convergence happens when the generator generates the statistics. At the same time, the discriminator cannot differentiate between the real and the generated data.

The Quantum Generative Adversarial Networks (QGANs) are generative adversarial networks using quantum processors. Seth Lloyd  and Christian Weedbrook first devised the adversarial learning algorithm.This algorithm runs on a quantum computer which has a Quantum register with Qubits.  Qubits exist in 0 and 1 states and can hold both the states. Quantum computers process vectors in very high-dimensional vector spaces. These vectors have information to be processed.

The code below shows a QGAN implementation. QGAN consists of a two quantum circuits. The first quantum circuit serves as a generator while the second quantum circuit takes the role of a discriminator.

Prerequisites:

  1. You need to set up Python3.5 to run the code samples below. You can download from this link.

Problem

import pennylane as qmlPenny
from pennylane import numpy as np
from pennylane.optimize import GradientDescentOptimizer
 
device = qmlPenny.device('default.qubit', wires=3)
 
 
def GetReal(phiValue, thetaValue, omegaValue):
    """Getting the real distribution from the
      sampling"""
 
    
   
    qmlPenny.Rot(phiValue, thetaValue, omegaValue, wires=0)
 
 
def GetGenerator(wireArray):
    """ Getting a generator from a Circuit 
    """
    qmlPenny.RX(wireArray[0], wires=0)
    qmlPenny.RX(wireArray[1], wires=1)
    qmlPenny.RY(wireArray[2], wires=0)
    qmlPenny.RY(wireArray[3], wires=1)
    qmlPenny.RZ(wireArray[4], wires=0)
    qmlPenny.RZ(wireArray[5], wires=1)
    qmlPenny.CNOT(wires=[0,1])
    qmlPenny.RX(wireArray[6], wires=0)
    qmlPenny.RY(wireArray[7], wires=0)
    qmlPenny.RZ(wireArray[8], wires=0)
 
 
def GetDiscriminator(wireArray):
    """Getting the discriminator from the circuit.
    """
    qmlPenny.RX(wireArray[0], wires=0)
    qmlPenny.RX(wireArray[1], wires=2)
    qmlPenny.RY(wireArray[2], wires=0)
    qmlPenny.RY(wireArray[3], wires=2)
    qmlPenny.RZ(wireArray[4], wires=0)
    qmlPenny.RZ(wireArray[5], wires=2)
    qmlPenny.CNOT(wires=[1,2])
    qmlPenny.RX(wireArray[6], wires=2)
    qmlPenny.RY(wireArray[7], wires=2)
    qmlPenny.RZ(wireArray[8], wires=2)
 
 
@qmlPenny.qnode(device)
def GetRealDiscCircuit(phiValue, thetaValue, omegaValue, discriminatorWeights):
    """Getting the Real discriminator from the sampling.
    """
    GetReal(phiValue, thetaValue, omegaValue)
    GetDiscriminator(discriminatorWeights)
    return qmlPenny.expval.PauliZ(2)
 
 
@qmlPenny.qnode(device)
def GetDiscCircuit(generatorWeights, discriminatorWeights):
    """Generate the  discriminator from samples 
    """
    GetGenerator(generatorWeights)
    GetDiscriminator(discriminatorWeights)
    return qmlPenny.expval.PauliZ(2)
 
 
def GetProbabilityRealTrue(discriminatorWeights):
    """Getting the Probability of the discriminator  about the guess on the real data.
    """
    trueDiscriminatorOutput = GetRealDiscCircuit(phiValue, thetaValue, omegaValue, discriminatorWeights)
    probabilityRealTrue = (trueDiscriminatorOutput + 1) / 2
    return probabilityRealTrue
 
 
def GetProbabilityFakeTrue(generatorWeights, discriminatorWeights):
       """Getting the Probability of the discriminator  about the guess on the fake data.
    """
       
    fakeDiscriminatorOutput = GetDiscCircuit(generatorWeights, discriminatorWeights)
    probabilityFakeTrue = (fakeDiscriminatorOutput + 1) / 2
    return probabilityFakeTrue 
 
 
def GetDiscriminatorCost(discriminatorWeights):
    """Getting the discriminator Cost 
    """
    cost = GetProbabilityFakeTrue(generatorWeights, discriminatorWeights) - GetProbabilityRealTrue(discriminatorWeights) 
    return cost
 
 
def GetGeneratorCost(generatorWeights):
    """Getting the generator Cost 
    """
    return -GetProbabilityFakeTrue(generatorWeights, discriminatorWeights)
 
 
phiValue = np.pi / 6
thetaValue = np.pi / 2
omegaValue = np.pi / 7
 
np.random.seed(0)
epsValue = 1e-2
generatorWeights = np.array([np.pi] + [0] * 8) + np.random.normal(scale=epsValue, size=[9])
discriminatorWeights = np.random.normal(size=[9])
 
optimal = GradientDescentOptimizer(0.1)
 
print("Train the discriminator ")
for iteration in range(50):
    discriminator_weights = optimal.step(GetDiscriminatorCost, discriminatorWeights) 
    discriminator_cost = GetDiscriminatorCost(discriminator_weights)
    if iteration % 5 == 0:
        print("Iteration {}: discriminator cost = {}".format(iteration+1, discriminator_cost))
 
print("Probability - discriminator - real data correct: ", GetProbabilityRealTrue(discriminatorWeights))
print("Probability - discriminator - fake data real: ", GetProbabilityFakeTrue(generatorWeights, discriminatorWeights))
 
print("Train the generator.")
 
 
for iteration in range(200):
    generator_weights = optimal.step(GetGeneratorCost, generatorWeights)
    generator_cost = -GetGeneratorCost(generator_weights)
    if iteration % 5 == 0:
        print("Iteration {}: generator cost = {}".format(iteration, generator_cost))
 
print("Probability - discriminator - real data correct: ", GetProbabilityRealTrue(discriminatorWeights))
print("Probability - discriminator -  fake data  real: ", GetProbabilityFakeTrue(generatorWeights, discriminatorWeights))
 
print("Cost value: ", GetDiscriminatorCost(discriminator_weights))

Instructions for Running the Code

pip install pennylane
 
python qgan.py

Output