I am able to get your code running by replacing the np.mean(result) with np.mean(np.array(result)). For the autodifferentiation of np.mean to work, the input should (as far as I can tell) always be a NumPy array.
The full code is below:
import pennylane as qml
from pennylane import numpy as np
n_qubits = 4 # 4 actions for lunar lander
device = qml.device("default.qubit", wires=n_qubits)
@qml.qnode(device)
def qcircuit(weights, input = None):
qml.templates.AngleEmbedding(input, wires=range(n_qubits))
qml.templates.StronglyEntanglingLayers(weights, wires=range(n_qubits))
return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_qubits)]
def softmax(x):
return [np.exp(i) / np.sum(np.exp(i)) for i in x]
def one_hot(labels, num_labels):
one_hot_diag_matix = np.identity(num_labels)
return [one_hot_diag_matix[i] for i in labels]
def cross_entropy_loss(dist, labels, num_labels):
p = softmax(dist)
one_hot_labels = one_hot(labels,num_labels)
results = []
for pd,l in zip(p,one_hot_labels):
results.append(-np.sum([l[i]*np.log(pd[i]) for i in range(num_labels)]))
return np.mean(np.array(results))
def cost(weights, labels, inputs):
predictions = [qcircuit(weights, input=i) for i in inputs]
return cross_entropy_loss(predictions, labels, inputs.shape[1])
max_steps = 60
opt = qml.AdamOptimizer(0.3)
nlayers = 1
np.random.seed(42)
inputs = np.random.random((10,4))
output = np.random.choice([0,1],10)
weights = qml.init.strong_ent_layers_normal(n_layers=nlayers, n_wires=n_qubits)
for step in range(max_steps):
weights, cost_value = opt.step_and_cost(lambda w: cost(w,output,inputs), weights)
print("{}\n{}".format(step,weights))
print("Cost at step {} ---> {}".format(step, cost_value))
Let me know if this works!
Note that I also made an additional change; I replaced opt.step with opt.step_and_cost(), which will avoid the overhead of computing the cost function twice. This is a new feature of PennyLane v0.13, released last week.