QNSPSA error using a dataset

Hi @isaacdevlugt,

I made some progress using Training with QNG optimizer on circuit with data argument and Accelerating VQEs with quantum natural gradient.
I change my code to:

import pennylane as qml 
from pennylane import numpy as np
from sklearn import datasets 

data = datasets.make_classification(n_samples=1000, n_features=52, n_classes=2) 
num_qubits = 8
dev = qml.device("default.qubit", wires=num_qubits)

def ansatz_3(params, X, depth=2):
    '''
    
    '''
    #print(params)
    #amplitudes(X_batch, num_qubits=num_qubits)
    qml.AmplitudeEmbedding(features=X, pad_with=0.,wires=range(num_qubits),normalize=True)
    step = 0
    for _ in range(depth):
        for i in range(num_qubits):
            qml.RY(params[i+step], wires=i)
        for i in range(num_qubits-1):
            qml.CNOT([i,i+1])
        for i in range(num_qubits):
            qml.RY(params[i+step], wires=i)
        step += num_qubits

coeffs = [1 for i in range(num_qubits)]

obs = [qml.PauliZ(i) for i in range(num_qubits)]

H = qml.Hamiltonian(coeffs, obs)

@qml.qnode(dev, interface="autograd")
def cost_fn(params, X):
    ansatz_3(params, X)
    return qml.expval(H)

init_params = np.random.random(40)
max_iterations = 500
step_size = 0.5
conv_tol = 1e-06

opt = qml.QNGOptimizer(step_size, lam=0.001, approx="block-diag")

depth = 2
batch_size = 5*depth #5

X_ = data[0]#np.concatenate([X_new, X_transform.to_numpy()], axis=1) #data_res.to_numpy() X_new
Y_ = data[1] #y
Y_ = Y_ * 2 - 1


params = init_params
prev_energy = cost_fn(params, X_[:batch_size])
qngd_cost = []

for n in range(max_iterations):

    # Update the weights by one optimizer step
    batch_index = np.random.randint(0, len(X_), (batch_size,))
    X_batch = np.array(X_[batch_index], requires_grad=False)
    Y_batch = Y_[batch_index]

    
    params, prev_energy = opt.step_and_cost(cost_fn, params, X_batch)
    qngd_cost.append(prev_energy)

    energy = cost_fn(params, X_batch)
    conv = np.abs(energy - prev_energy)

    if n % 4 == 0:
        print(
            "Iteration = {:},  Energy = {:.8f} Ha".format(n, energy)
        )

    if conv <= conv_tol:
        break

But I got this new error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[6], line 28
     24 X_batch = np.array(X_[batch_index], requires_grad=False)
     25 Y_batch = Y_[batch_index]
---> 28 params, prev_energy = opt.step_and_cost(cost_fn, params, X_batch)
     29 qngd_cost.append(prev_energy)
     31 energy = cost_fn(params, X_batch)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/optimize/qng.py:192, in QNGOptimizer.step_and_cost(self, qnode, grad_fn, recompute_tensor, metric_tensor_fn, *args, **kwargs)
    189 if metric_tensor_fn is None:
    190     metric_tensor_fn = qml.metric_tensor(qnode, approx=self.approx)
--> 192 _metric_tensor = metric_tensor_fn(*args, **kwargs)
    193 # Reshape metric tensor to be square
    194 shape = qml.math.shape(_metric_tensor)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/workflow/qnode.py:1040, in QNode.__call__(self, *args, **kwargs)
   1035     if hybrid:
   1036         argnums = full_transform_program[-1]._kwargs.pop(
   1037             "argnums", None
   1038         )  # pylint: disable=protected-access
-> 1040         full_transform_program._set_all_classical_jacobians(
   1041             self, args, kwargs, argnums
   1042         )  # pylint: disable=protected-access
   1043         full_transform_program._set_all_argnums(
   1044             self, args, kwargs, argnums
   1045         )  # pylint: disable=protected-access
   1047 # pylint: disable=unexpected-keyword-arg

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/core/transform_program.py:420, in TransformProgram._set_all_classical_jacobians(self, qnode, args, kwargs, argnums)
    416     raise qml.QuantumFunctionError(
    417         "argnum does not work with the Jax interface. You should use argnums instead."
    418     )
    419 sub_program = TransformProgram(self[0:index])
--> 420 classical_jacobian = jacobian(
    421     classical_preprocessing, sub_program, argnums, *args, **kwargs
    422 )
    423 qnode.construct(args, kwargs)
    424 tapes, _ = sub_program((qnode.tape,))

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/core/transform_program.py:376, in TransformProgram._set_all_classical_jacobians.<locals>.jacobian(classical_function, program, argnums, *args, **kwargs)
    373 classical_function = partial(classical_function, program)
    375 if qnode.interface == "autograd":
--> 376     jac = qml.jacobian(classical_function, argnum=argnums)(*args, **kwargs)
    378 if qnode.interface == "tf":
    379     import tensorflow as tf  # pylint: disable=import-outside-toplevel

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/_grad.py:455, in jacobian.<locals>._jacobian_function(*args, **kwargs)
    449 if not _argnum:
    450     warnings.warn(
    451         "Attempted to differentiate a function with no trainable parameters. "
    452         "If this is unintended, please add trainable parameters via the "
    453         "'requires_grad' attribute or 'argnum' keyword."
    454     )
--> 455 jac = tuple(_jacobian(func, arg)(*args, **kwargs) for arg in _argnum)
    457 return jac[0] if unpack else jac

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/_grad.py:455, in <genexpr>(.0)
    449 if not _argnum:
    450     warnings.warn(
    451         "Attempted to differentiate a function with no trainable parameters. "
    452         "If this is unintended, please add trainable parameters via the "
    453         "'requires_grad' attribute or 'argnum' keyword."
    454     )
--> 455 jac = tuple(_jacobian(func, arg)(*args, **kwargs) for arg in _argnum)
    457 return jac[0] if unpack else jac

File ~/PinQ2_py/lib/python3.9/site-packages/autograd/wrap_util.py:20, in unary_to_nary.<locals>.nary_operator.<locals>.nary_f(*args, **kwargs)
     18 else:
     19     x = tuple(args[i] for i in argnum)
---> 20 return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)

File ~/PinQ2_py/lib/python3.9/site-packages/autograd/differential_operators.py:60, in jacobian(fun, x)
     50 @unary_to_nary
     51 def jacobian(fun, x):
     52     """
     53     Returns a function which computes the Jacobian of `fun` with respect to
     54     positional argument number `argnum`, which must be a scalar or array. Unlike
   (...)
     58     (out1, out2, ...) then the Jacobian has shape (out1, out2, ..., in1, in2, ...).
     59     """
---> 60     vjp, ans = _make_vjp(fun, x)
     61     ans_vspace = vspace(ans)
     62     jacobian_shape = ans_vspace.shape + vspace(x).shape

File ~/PinQ2_py/lib/python3.9/site-packages/autograd/core.py:10, in make_vjp(fun, x)
      8 def make_vjp(fun, x):
      9     start_node = VJPNode.new_root()
---> 10     end_value, end_node =  trace(start_node, fun, x)
     11     if end_node is None:
     12         def vjp(g): return vspace(x).zeros()

File ~/PinQ2_py/lib/python3.9/site-packages/autograd/tracer.py:10, in trace(start_node, fun, x)
      8 with trace_stack.new_trace() as t:
      9     start_box = new_box(x, t, start_node)
---> 10     end_box = fun(start_box)
     11     if isbox(end_box) and end_box._trace == start_box._trace:
     12         return end_box._value, end_box._node

File ~/PinQ2_py/lib/python3.9/site-packages/autograd/wrap_util.py:15, in unary_to_nary.<locals>.nary_operator.<locals>.nary_f.<locals>.unary_f(x)
     13 else:
     14     subargs = subvals(args, zip(argnum, x))
---> 15 return fun(*subargs, **kwargs)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/core/transform_program.py:355, in TransformProgram._set_all_classical_jacobians.<locals>.classical_preprocessing(program, *args, **kwargs)
    353 qnode.construct(args, kwargs)
    354 tape = qnode.qtape
--> 355 tapes, _ = program((tape,))
    356 res = tuple(qml.math.stack(tape.get_parameters(trainable_only=True)) for tape in tapes)
    357 if len(tapes) == 1:

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/core/transform_program.py:477, in TransformProgram.__call__(self, tapes)
    475 if self._argnums is not None and self._argnums[i] is not None:
    476     tape.trainable_params = self._argnums[i][j]
--> 477 new_tapes, fn = transform(tape, *targs, **tkwargs)
    478 execution_tapes.extend(new_tapes)
    480 fns.append(fn)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/gradients/metric_tensor.py:82, in _expand_metric_tensor(tape, argnum, approx, allow_nonunitary, aux_wire, device_wires)
     80 if not allow_nonunitary and approx is None:
     81     return [qml.transforms.expand_nonunitary_gen(tape)], lambda x: x[0]
---> 82 return [qml.transforms.expand_multipar(tape)], lambda x: x[0]

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/tape_expand.py:102, in create_expand_fn.<locals>.expand_fn(tape, depth, **kwargs)
    100     tape = tape.expand(depth=depth)
    101 elif not all(stop_at(op) for op in tape.operations):
--> 102     tape = tape.expand(depth=depth, stop_at=stop_at)
    103 else:
    104     return tape

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/tape/qscript.py:912, in QuantumScript.expand(self, depth, stop_at, expand_measurements)
    867 def expand(self, depth=1, stop_at=None, expand_measurements=False):
    868     """Expand all operations to a specific depth.
    869 
    870     Args:
   (...)
    910     RY(0.2, wires=['a'])]
    911     """
--> 912     new_script = qml.tape.tape.expand_tape(
    913         self, depth=depth, stop_at=stop_at, expand_measurements=expand_measurements
    914     )
    915     new_script._update()
    916     return new_script

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/tape/tape.py:213, in expand_tape(tape, depth, stop_at, expand_measurements)
    210         continue
    212 # recursively expand out the newly created tape
--> 213 expanded_tape = expand_tape(obj, stop_at=stop_at, depth=depth - 1)
    215 new_ops.extend(expanded_tape.operations)
    216 new_measurements.extend(expanded_tape.measurements)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/tape/tape.py:213, in expand_tape(tape, depth, stop_at, expand_measurements)
    210         continue
    212 # recursively expand out the newly created tape
--> 213 expanded_tape = expand_tape(obj, stop_at=stop_at, depth=depth - 1)
    215 new_ops.extend(expanded_tape.operations)
    216 new_measurements.extend(expanded_tape.measurements)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/tape/tape.py:198, in expand_tape(tape, depth, stop_at, expand_measurements)
    196 if obj.has_decomposition:
    197     with QueuingManager.stop_recording():
--> 198         obj = QuantumScript(obj.decomposition(), _update=False)
    199 else:
    200     new_queue.append(obj)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/operation.py:1292, in Operator.decomposition(self)
   1280 def decomposition(self):
   1281     r"""Representation of the operator as a product of other operators.
   1282 
   1283     .. math:: O = O_1 O_2 \dots O_n
   (...)
   1290         list[Operator]: decomposition of the operator
   1291     """
-> 1292     return self.compute_decomposition(
   1293         *self.parameters, wires=self.wires, **self.hyperparameters
   1294     )

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/templates/state_preparations/mottonen.py:346, in MottonenStatePreparation.compute_decomposition(state_vector, wires)
    321 r"""Representation of the operator as a product of other operators.
    322 
    323 .. math:: O = O_1 O_2 \dots O_n.
   (...)
    343 CNOT(wires=['a', 'b'])]
    344 """
    345 if len(qml.math.shape(state_vector)) > 1:
--> 346     raise ValueError(
    347         "Broadcasting with MottonenStatePreparation is not supported. Please use the "
    348         "qml.transforms.broadcast_expand transform to use broadcasting with "
    349         "MottonenStatePreparation."
    350     )
    352 a = qml.math.abs(state_vector)
    353 omega = qml.math.angle(state_vector)

ValueError: Broadcasting with MottonenStatePreparation is not supported. Please use the qml.transforms.broadcast_expand transform to use broadcasting with MottonenStatePreparation.

Looking at the forum, the error seems to be due to the fact the qml.MottonenStatePreparation has no broadcasting implemented: Parameter broadcast bug

But how to fix it? Because I don’t use qml.MottonenStatePrepration or is it used in qml.AmplitudeEmbedding?

Update:
When I changed AmplitudeEmbedding to AngleEmbedding and reduced the dataset with 8 variables to match 8 qubits, the error of broadcast disappeared, but I got a new one :joy:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[38], line 29
     25 X_batch = np.array(X_[batch_index], requires_grad=False)
     26 Y_batch = Y_[batch_index]
---> 29 params, prev_energy = opt.step_and_cost(cost_fn, params, X_batch)
     30 qngd_cost.append(prev_energy)
     32 energy = cost_fn(params, X_batch)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/optimize/qng.py:192, in QNGOptimizer.step_and_cost(self, qnode, grad_fn, recompute_tensor, metric_tensor_fn, *args, **kwargs)
    189 if metric_tensor_fn is None:
    190     metric_tensor_fn = qml.metric_tensor(qnode, approx=self.approx)
--> 192 _metric_tensor = metric_tensor_fn(*args, **kwargs)
    193 # Reshape metric tensor to be square
    194 shape = qml.math.shape(_metric_tensor)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/workflow/qnode.py:1048, in QNode.__call__(self, *args, **kwargs)
   1043         full_transform_program._set_all_argnums(
   1044             self, args, kwargs, argnums
   1045         )  # pylint: disable=protected-access
   1047 # pylint: disable=unexpected-keyword-arg
-> 1048 res = qml.execute(
   1049     (self._tape,),
   1050     device=self.device,
   1051     gradient_fn=self.gradient_fn,
   1052     interface=self.interface,
   1053     transform_program=full_transform_program,
   1054     config=config,
   1055     gradient_kwargs=self.gradient_kwargs,
   1056     override_shots=override_shots,
   1057     **self.execute_kwargs,
   1058 )
   1060 res = res[0]
   1062 # convert result to the interface in case the qfunc has no parameters

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/workflow/execution.py:685, in execute(tapes, device, gradient_fn, interface, transform_program, config, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform, device_vjp)
    683 if no_interface_boundary_required:
    684     results = inner_execute(tapes)
--> 685     return post_processing(results)
    687 _grad_on_execution = False
    689 if (
    690     device_vjp
    691     and "lightning" in getattr(device, "short_name", "")
    692     and interface in jpc_interfaces
    693 ):

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/core/transform_program.py:86, in _apply_postprocessing_stack(results, postprocessing_stack)
     63 """Applies the postprocessing and cotransform postprocessing functions in a Last-In-First-Out LIFO manner.
     64 
     65 Args:
   (...)
     83 
     84 """
     85 for postprocessing in reversed(postprocessing_stack):
---> 86     results = postprocessing(results)
     87 return results

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/core/transform_program.py:56, in _batch_postprocessing(results, individual_fns, slices)
     30 def _batch_postprocessing(
     31     results: ResultBatch, individual_fns: List[PostProcessingFn], slices: List[slice]
     32 ) -> ResultBatch:
     33     """Broadcast individual post processing functions onto their respective tapes.
     34 
     35     Args:
   (...)
     54 
     55     """
---> 56     return tuple(fn(results[sl]) for fn, sl in zip(individual_fns, slices))

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/transforms/core/transform_program.py:56, in <genexpr>(.0)
     30 def _batch_postprocessing(
     31     results: ResultBatch, individual_fns: List[PostProcessingFn], slices: List[slice]
     32 ) -> ResultBatch:
     33     """Broadcast individual post processing functions onto their respective tapes.
     34 
     35     Args:
   (...)
     54 
     55     """
---> 56     return tuple(fn(results[sl]) for fn, sl in zip(individual_fns, slices))

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/gradients/metric_tensor.py:504, in _metric_tensor_cov_matrix.<locals>.processing_fn(probs)
    502 scale = qml.math.convert_like(qml.math.outer(coeffs, coeffs), p)
    503 scale = qml.math.cast_like(scale, p)
--> 504 g = scale * qml.math.cov_matrix(p, obs, wires=tape.wires, diag_approx=diag_approx)
    505 for i, in_argnum in enumerate(params_in_argnum):
    506     # fill in rows and columns of zeros where a parameter was not in argnum
    507     if not in_argnum:

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/math/quantum.py:102, in cov_matrix(prob, obs, wires, diag_approx)
    100 eigvals = cast(o.eigvals(), dtype=float64)
    101 w = o.wires.labels if wires is None else wires.indices(o.wires)
--> 102 p = marginal_prob(prob, w)
    104 res = dot(eigvals**2, p) - (dot(eigvals, p)) ** 2
    105 variances.append(res)

File ~/PinQ2_py/lib/python3.9/site-packages/pennylane/math/quantum.py:169, in marginal_prob(prob, axis)
    166     return prob
    168 inactive_wires = tuple(set(range(num_wires)) - set(axis))
--> 169 prob = np.reshape(prob, [2] * num_wires)
    170 prob = np.sum(prob, axis=inactive_wires)
    171 return np.flatten(prob)

File ~/PinQ2_py/lib/python3.9/site-packages/autoray/autoray.py:79, in do(fn, like, *args, **kwargs)
     30 """Do function named ``fn`` on ``(*args, **kwargs)``, peforming single
     31 dispatch to retrieve ``fn`` based on whichever library defines the class of
     32 the ``args[0]``, or the ``like`` keyword argument if specified.
   (...)
     76     <tf.Tensor: id=91, shape=(3, 3), dtype=float32>
     77 """
     78 backend = choose_backend(fn, *args, like=like, **kwargs)
---> 79 return get_lib_fn(backend, fn)(*args, **kwargs)

File <__array_function__ internals>:180, in reshape(*args, **kwargs)

File ~/PinQ2_py/lib/python3.9/site-packages/numpy/core/fromnumeric.py:298, in reshape(a, newshape, order)
    198 @array_function_dispatch(_reshape_dispatcher)
    199 def reshape(a, newshape, order='C'):
    200     """
    201     Gives a new shape to an array without changing its data.
    202 
   (...)
    296            [5, 6]])
    297     """
--> 298     return _wrapfunc(a, 'reshape', newshape, order=order)

File ~/PinQ2_py/lib/python3.9/site-packages/numpy/core/fromnumeric.py:57, in _wrapfunc(obj, method, *args, **kwds)
     54     return _wrapit(obj, method, *args, **kwds)
     56 try:
---> 57     return bound(*args, **kwds)
     58 except TypeError:
     59     # A TypeError occurs if the object does have such a method in its
     60     # class, but its signature is not identical to that of NumPy's. This
   (...)
     64     # Call _wrapit from within the except clause to ensure a potential
     65     # exception has a traceback chain.
     66     return _wrapit(obj, method, *args, **kwds)

ValueError: cannot reshape array of size 2560 into shape (2,2,2,2,2,2,2,2,2,2,2)
Click to add a cell.