Closed DuckTigger closed 2 years ago
Hi @DuckTigger! In the train()
function, as you are computing the gradients of a Keras model, I believe you want the tf.GradientTape()
context manager.
qml.tape.QubitParamShiftTape
is an internal part of PennyLane unrelated to TensorFlow gradients, that is due to soon be removed from PennyLane 🙂
Below I've modified your functions to take this into account, which will allow the gradients to be returned:
def loss_fn(Y, y_pred):
return tf.reduce_mean(Y - y_pred)
def test_gen():
return tf.zeros([2, len(qubits)], dtype=tf.float64)
@qml.qnode(device, interface='tf', diff_method='parameter-shift')
def circuit(inputs, params):
qml.BasisEmbedding(inputs, list(range(n_qubits)))
for i, w in enumerate(range(n_qubits)):
qml.RX(params[i], wires=w)
return [qml.expval(qml.PauliZ(w)) for w in range(len(qubits))]
def train():
tf.keras.backend.set_floatx('float64')
weight_shapes = {"params": n_qubits}
qlayer = qml.qnn.KerasLayer(circuit, weight_shapes, output_dim=n_qubits)
model = tf.keras.models.Sequential([qlayer])
for epoch in range(10):
X, Y = test_gen()
with tf.GradientTape() as tape:
pred_y = model(X, training=True)
cost_val = loss_fn(Y, pred_y)
grad = tape.gradient(cost_val, model.trainable_weights[0])
print(cost_val, grad)
Hi Josh, thanks for the speedy reply!
I moved to using ParamShift from tensorflow gradients as I'm trying to use sampling in my model - this is fundamental, so I can't use expval.
When I try this code with sampling I get gradients == None
, which is why I moved to using QubitParamShiftTape
(and pennylane) in the first place.
Being a keras model is not fundamental to me, but sampling is.
I get the same issue when removing all references to tensorflow:
import cirq
import pennylane as qml
import numpy as np
qubits = cirq.GridQubit.rect(2, 2)
n_qubits = 4
shots = 1000
device = qml.device('cirq.simulator', wires=n_qubits, shots=shots)
def ansatz(val, params):
qml.BasisEmbedding(val, list(range(n_qubits)))
for i, w in enumerate(range(n_qubits)):
qml.RX(params[i], wires=w)
def loss_fn(Y, y_pred):
y_pred = np.reshape(y_pred, (shots, n_qubits))
return np.mean(Y - y_pred)
def test_gen():
while True:
yield [0 for _ in range(len(qubits))], [0 for _ in range(len(qubits))]
def create_model():
@qml.qnode(device, diff_method='parameter-shift')
def model(inputs, params):
ansatz(inputs, params)
measurement = [qml.sample(qml.PauliZ(w)) for w in range(len(qubits))]
return measurement
return model
def train():
model = create_model()
initial_params = np.random.normal(size=(n_qubits,))
for epoch in range(10):
X, Y = next(test_gen())
with qml.tape.QubitParamShiftTape() as tape:
pred_y = model(X, initial_params)
cost_val = loss_fn(Y, pred_y)
grads = tape.jacobian(device, initial_params)
print(grads)
if __name__ == '__main__':
train()
Being a keras model is not fundamental to me, but sampling is.
In that case @DuckTigger you can use single shot expectation values 🙂 These are expectation values computed with a 'single shot', so they:
To do this, you can set
shots=[(1, 1000)]
This means 'use 1000 shots, 1 shot per expectation'. I tested this single change in the code in my comment above, and it seems to work well.
Just checked and it works - Amazing, thanks very much for your time!
Expected behavior
Using
qml.tape.QubitParamShiftTape()
as the gradient tape I expect to get results for the gradients of parameters.Actual behavior
The code runs into an
AttributeError
from line 118 ofpennylane/tape/qubit_param_shift.py
:AttributeError: 'JacobianTape' object has no attribute 'grad_method'
Line 118 is calling
op.grad_method
whereop
is an instance ofJacobianTape
Additional information
Reproducible at all times.
Source code
Tracebacks
System information
Existing GitHub issues