Loading...

Postulate is the best way to take and share notes for classes, research, and other learning.

More info

A QGAN to generate a single-qubit state

Profile picture of Laura GaoLaura Gao
Apr 4, 2021Last updated Apr 5, 20214 min read

In order to build a QGAN to generate a single qubit state, we need 3 wires. This may sound absurd: why need 3 qubits to generate the state of 1 qubit? That's 3x as much as you need, right? Why can't you just parametize the rotation gates of one qubit and optimize those parameters to match the state that we want? Well, unfortuneately, parametizing the gates on one wire is not enough in the world of Quantum GANs. Here's why:

  • Wire 0: this is the single qubit state that both the real data and the generated data is going to be stored.

  • Wire 1: this is a playground for the generator. The generator will apply some rotation gates onto this wire, and those gates will be parametized by weights of which we can optimize. Furthermore, the generator will entangle wire 0 with wire 1, which allows the parameters of wire 1 to the wire 0 output..

  • Wire 2: this is the output of the discriminator. The expectation value of wire 2 is the only one we will measure, and this expectation value represents the probability of the discriminator classifying wire 2 as real.



In the code, the real-data, generator, and discriminator will each be defined as individual function:







Note: wire = qubit*, for those who may be confused. (*At least in this context it does. In continuous variable quantum computing, wire != qubit.) I use these two words interchangeably. (and so do quantum programming Python libraries: for example, Qiskit uses "qubit" but Pennylane uses "wire.")



We will define 2 circuits:

  • Realdata-discriminator circuit - this circuit will output an expectation value that is proportional to the probability of the discriminator classifying real data as real

  • Generator-discriminator circuit - this circuit will output an expectation value that is proportional to the probability of the discriminator classifying fake data as real

Next, we will write cost functions. We will have 2 separate cost functions: one for the discriminator and one for the generator.

The discriminator is trying to maximize correct guesses and minimize incorrect ones. The accuracy of the discriminator is given by the probability of the discriminator classifying real data as real - the probability of the discriminator classifying fake data as real, and thus, the cost function will be Generator-discriminator circuit output - Realdata-discriminator circuit ouptut.

The generator is trying to maximize how much it can fool the generator, so its accuracy is given by the probability of the discriminator classifying fake data as real, and its cost function would just be the additive inverse of that, aka the Generator-discriminator circuit output.

There's a slight caveat: The circuit output expectation value is not equal to the probability of the discriminator classifying the data as real.

To convert the expectation value that the circuit returns into the probabilty of the discriminator classifying as real, we add 1 to the expectation value and divide the sum by 2. I don't know why this function outputs the probability as I don't understand what exactly the expectation value represents well enough.



Training

After defining the circuits and the cost functions, all that's left to do is to optimize.

Use your optimizer of choice. Define initial parameters for both the generator and discriminator. Both theta vectors are of size 9.

We start off with training the discriminator until it can classify the real data as real with close to 100% accuracy. Then, we train the generator to better fool the discriminator. Alternate back and forth between training these two buddies one at a time, putting the "adversial" in "generative adversial network."



Validation

To see if your GAN has produced the desired single qubit state, print out the bloch sphere vectors that the GAN generates and compare it with the bloch sphere vectors that the real-data circuit generates.

In:

obs = [qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0)] bloch_vector_real = qml.map(real, obs, dev, interface="tf") bloch_vector_generator = qml.map(generator, obs, dev, interface="tf") print("Real Bloch vector: {}".format(bloch_vector_real([phi, theta, omega]))) print("Generator Bloch vector: {}".format(bloch_vector_generator(gen_weights)))

Out:

Real Bloch vector: [-0.2169418 0.45048445 -0.86602525] Generator Bloch vector: [ 0.02237707 0.00048757 -0.00974897]

A gap in my knowledge: I don't fully understand why the above code works.


Comments (loading...)

Sign in to comment

Quantum computing

Working notes from learning QC