I have a GAN with a quantum generator using pennylane for the generator.
I use tensorflow (tf.GradientTape) to train the model.
I want to use default.tensor so I can make use of mps. The problem is that when running the circuit on default.tensor the function tape.gradient takes incredibly long while using default.qubit does not take as long. I was wondering what the optimal parameters are for the default.tensor device as I don’t think backpropagation works for instance.
I am now using: "default.tensor",, method="mps" and interface='tf', diff_method="parameter-shift".
Also the qml.qnn.KerasLayer does not seem to work with default.tensor and thus I have the QNode wrapped in custom layer i.e. class QuantumLayer(tf.keras.layers.Layer): etc.
default.tensor does not currently support differentiation.
If you need differentiation then default.qubit might be best. If you want to find other ways of using default.tensor you can check out our demos that use default.tensor or the documentation for default.tensor.
diff_method="parameter-shift" is the slowest method.
Should you choose to change the device, it’s generally best not to set the diff_method. If you don’t set it then PennyLane will automatically choose the best diff_method for the device you’re using.
qnn.KerasLayer will be deprecated soon.
I would recommend using PyTorch instead if possible. The demo on TorchLayers can be helpful here.
If possible, upgrade your version of PennyLane.
While this is probably not the cause for the issues you’re seeing, it’s always best to use the latest PennyLane version. At the moment the latest stable version is v0.40. You can always check what’s the latest version at the top of the pennylane.ai homepage. You can upgrade the version with pip install pennylane --upgrade.
You’re totally right. default.tensor doesn’t natively support differentiation with backprop and adjoint, which are more performant. But PennyLane does support other methods such as parameter-shift on all devices including default.tensor.
One way you can test the cause for the slowdown is to set diff_method="parameter-shift" when using default.qubit. If you get a big slowdown then this will be an indication that the diff_method might be the main cause.
Please let us know what you find with this test! You can try using tools like timeit to find execution times or a profiler such as snakeviz to get a deeper look into the slower processes. Let me know if you need an example on how to use timeit.
When using default.qubit the code is fine with parameter-shift (though it is obviously slower then using best). It is just when changing to default.tensor that it slows down massively.
So it would seem the issue is with changing the device on the Qnode. However, the slow down occurs when I am training the generator(or discriminator) in my GAN where I call the Qnode for creating a fake sample for the discriminator.
The tf.GradientTape method has to propagate through the generator, even though the generator’s weights aren’t being updated or any gradients calculated, which only happens later. So what I am thinking is that if the generator’s computational graph is complex or inefficient (maybe because mps involves more steps), this is the bottleneck. Not necessarily computing the gradients but just tracking the operations in the quantum circuit itself.
I hope this makes sense and I was clear enough with my explanation.
Thank you.
Thanks for sharing these insights @Lucas ! They’re very useful.
Are you able to share some code that we could use to investigate the issue further?
For example, if you based you code on the PennyLane demo on Quantum GANs, what parts of the code did you change? If you can share an example that we can reproduce then we may be able to identify the cause of the slowdown.