Parameter broadcasting problem with torch node

Hello, I am experimenting with the parameter broadcasting for quantum circuits in which the quantum circuit is created as a torch layer and I found some weird things happening. Following is the code I am using.

import pennylane as qml
from pennylane import numpy as np
import time as time
import torch
import torch.nn as nn

dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev, interface = 'torch')
def simple_qubit_circuit(theta, inputs):
    qml.RX(inputs, wires=0)
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))
class QNet(nn.Module):
    def __init__(self):
        super().__init__()
        shapes = {
            "theta": (1,)
        }
        self.q = qml.qnn.TorchLayer(simple_qubit_circuit, shapes)
    
    def forward(self, input_value):
        return self.q(input_value)


x_train = np.array([0.2, 0.1, 0.2, 0.14, 0.11, 0.41, 0.55, 0.3, 0.31, 0.6])
x_train = torch.tensor(x_train).reshape(10,1)

# Problem 1
# x_train = torch.rand(10,1)
# x_train = torch.atan(x_train)

model = QNet()
t1 = time.time()
out = model(x_train)
print("time taken for batch operations: ", time.time()-t1)
out2 = []
t2 = time.time()
for x in x_train:
    out2.append(model(x).item())
print("time taken for sequential operations: ", time.time()-t2)

print(out)
print(out2)

Problem 1: If I use a tensor created using torch.rand() method, I get the following error. However, this error is not there when I used a tensor created with a numpy vector. I am not sure why this happens.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_12504\1395714778.py in <cell line: 9>()
      7 model = QNet()
      8 t1 = time.time()
----> 9 out = model(x_train)
     10 print("time taken for batch operations: ", time.time()-t1)
     11 out2 = []

~\Miniconda3\envs\qns\lib\site-packages\torch\nn\modules\module.py in _call_impl(self, *input, **kwargs)
   1192         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1193                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1194             return forward_call(*input, **kwargs)
   1195         # Do not call functions when jit is used
   1196         full_backward_hooks, non_full_backward_hooks = [], []

~\AppData\Local\Temp\ipykernel_12504\4054581433.py in forward(self, input_value)
     15 
     16     def forward(self, input_value):
---> 17         return self.q(input_value)

~\Miniconda3\envs\qns\lib\site-packages\torch\nn\modules\module.py in _call_impl(self, *input, **kwargs)
   1192         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1193                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1194             return forward_call(*input, **kwargs)
   1195         # Do not call functions when jit is used
   1196         full_backward_hooks, non_full_backward_hooks = [], []

~\Miniconda3\envs\qns\lib\site-packages\pennylane\qnn\torch.py in forward(self, inputs)
    307             # recursively call the forward pass on each of the yielded tensors, and then stack the
    308             # outputs back into the correct shape
--> 309             reconstructor = [self.forward(x) for x in torch.unbind(inputs)]
    310             return torch.stack(reconstructor)
    311 

~\Miniconda3\envs\qns\lib\site-packages\pennylane\qnn\torch.py in <listcomp>(.0)
    307             # recursively call the forward pass on each of the yielded tensors, and then stack the
    308             # outputs back into the correct shape
--> 309             reconstructor = [self.forward(x) for x in torch.unbind(inputs)]
    310             return torch.stack(reconstructor)
    311 

~\Miniconda3\envs\qns\lib\site-packages\pennylane\qnn\torch.py in forward(self, inputs)
    311 
    312         # If the input is 1-dimensional, calculate the forward pass as usual
--> 313         return self._evaluate_qnode(inputs)
    314 
    315     def _evaluate_qnode(self, x):

~\Miniconda3\envs\qns\lib\site-packages\pennylane\qnn\torch.py in _evaluate_qnode(self, x)
    326             **{arg: weight.to(x) for arg, weight in self.qnode_weights.items()},
    327         }
--> 328         return self.qnode(**kwargs).type(x.dtype)
    329 
    330     def _init_weights(

~\Miniconda3\envs\qns\lib\site-packages\pennylane\qnode.py in __call__(self, *args, **kwargs)
    845             return res
    846 
--> 847         res = qml.execute(
    848             [self.tape],
    849             device=self.device,

~\Miniconda3\envs\qns\lib\site-packages\pennylane\interfaces\execution.py in execute(tapes, device, gradient_fn, interface, mode, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform)
    722         ) from e
    723 
--> 724     res = _execute(
    725         tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n=1, max_diff=max_diff, mode=_mode
    726     )

~\Miniconda3\envs\qns\lib\site-packages\pennylane\interfaces\torch.py in execute(tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff, mode)
    256         max_diff=max_diff,
    257     )
--> 258     return ExecuteTapes.apply(kwargs, *parameters)
    259 
    260 

~\Miniconda3\envs\qns\lib\site-packages\pennylane\interfaces\torch.py in forward(ctx, kwargs, *parameters)
     85 
     86         with qml.tape.Unwrap(*ctx.tapes):
---> 87             res, ctx.jacs = ctx.execute_fn(ctx.tapes, **ctx.gradient_kwargs)
     88 
     89         # if any input tensor uses the GPU, the output should as well

~\Miniconda3\envs\qns\lib\site-packages\pennylane\interfaces\execution.py in wrapper(tapes, **kwargs)
    204         else:
    205             # execute all unique tapes that do not exist in the cache
--> 206             res = fn(execution_tapes.values(), **kwargs)
    207 
    208         final_res = []

~\Miniconda3\envs\qns\lib\site-packages\pennylane\interfaces\execution.py in fn(tapes, **kwargs)
    129         def fn(tapes: Sequence[QuantumTape], **kwargs):  # pylint: disable=function-redefined
    130             tapes = [expand_fn(tape) for tape in tapes]
--> 131             return original_fn(tapes, **kwargs)
    132 
    133     @wraps(fn)

~\Miniconda3\envs\qns\lib\contextlib.py in inner(*args, **kwds)
     73         def inner(*args, **kwds):
     74             with self._recreate_cm():
---> 75                 return func(*args, **kwds)
     76         return inner
     77 

~\Miniconda3\envs\qns\lib\site-packages\pennylane\_qubit_device.py in batch_execute(self, circuits)
    654 
    655             # TODO: Insert control on value here
--> 656             res = self.execute(circuit)
    657             results.append(res)
    658 

~\Miniconda3\envs\qns\lib\site-packages\pennylane\_qubit_device.py in execute(self, circuit, **kwargs)
    434         # generate computational basis samples
    435         if self.shots is not None or circuit.is_sampled:
--> 436             self._samples = self.generate_samples()
    437 
    438         measurements = circuit.measurements

~\Miniconda3\envs\qns\lib\site-packages\pennylane\_qubit_device.py in generate_samples(self)
   1216         rotated_prob = self.analytic_probability()
   1217 
-> 1218         samples = self.sample_basis_states(number_of_states, rotated_prob)
   1219         return self.states_to_binary(samples, self.num_wires)
   1220 

~\Miniconda3\envs\qns\lib\site-packages\pennylane\_qubit_device.py in sample_basis_states(self, number_of_states, state_probability)
   1244             # np.random.choice does not support broadcasting as needed here.
   1245             return np.array(
-> 1246                 [np.random.choice(basis_states, shots, p=prob) for prob in state_probability]
   1247             )
   1248 

~\Miniconda3\envs\qns\lib\site-packages\pennylane\_qubit_device.py in <listcomp>(.0)
   1244             # np.random.choice does not support broadcasting as needed here.
   1245             return np.array(
-> 1246                 [np.random.choice(basis_states, shots, p=prob) for prob in state_probability]
   1247             )
   1248 

mtrand.pyx in numpy.random.mtrand.RandomState.choice()

ValueError: probabilities do not sum to 1

Problem 2:
The time taken for batch operation is higher compared to the time taken for sequential operations. Is true parameter broadcasting yet not implemented in pennylane for qml.qnn.TorchLayer() ?

Problem 3:
The output tensors calculated using batch operation vs sequential operation for the same input tensor and for the same weight is different which should not be the case. Again not sure what’s wrong here.

Output of qml.about().

qml.about()
Name: PennyLane
Version: 0.28.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: c:\users\aksi01\miniconda3\envs\qns\lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, retworkx, scipy, semantic-version, toml
Required-by: PennyLane-Lightning, PennyLane-qiskit
Platform info:           Windows-10-10.0.19045-SP0
Python version:          3.8.15
Numpy version:           1.22.3
Scipy version:           1.7.3
Installed devices:
- default.gaussian (PennyLane-0.28.0)
- default.mixed (PennyLane-0.28.0)
- default.qubit (PennyLane-0.28.0)
- default.qubit.autograd (PennyLane-0.28.0)
- default.qubit.jax (PennyLane-0.28.0)
- default.qubit.tf (PennyLane-0.28.0)
- default.qubit.torch (PennyLane-0.28.0)
- default.qutrit (PennyLane-0.28.0)
- null.qubit (PennyLane-0.28.0)
- lightning.qubit (PennyLane-Lightning-0.28.1)
- qiskit.aer (PennyLane-qiskit-0.29.0)
- qiskit.basicaer (PennyLane-qiskit-0.29.0)
- qiskit.ibmq (PennyLane-qiskit-0.29.0)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.29.0)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.29.0)

This thread mentions that true broadcasting is not supported in Pennylane version 0.30 within qnn.TorchLayer. (“true parameter broadcasting within qnn.TorchLayer isn’t supported. I.e., you can still “broadcast”, but what happens under the hood is a serial execution, not parallel. So, it looks like broadcasting is happening, but really isn’t.”)

Does this status still prevails or there are ways to perform true broadcasting in the latest versions of pennylane within qnn.TorchLayer?

Hello @imakash !

I’ll return to you in a moment, but would you mind me sending a minimal code? I tried reproducing the problem, but the version you posted above has some problems and I got completely different errors. :sweat_smile:

For instance,

def simple_qubit_circuit(theta, inputs):
    qml.RX(inputs, wires=0)
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))
class QNet(nn.Module):
    def __init__(self):
        super().__init__()
        shapes = {
            "theta": (1,)
        }
        self.q = qml.qnn.TorchLayer(simple_qubit_circuit, shapes)
    
    def forward(self, input_value):
        return self.q(input_value)

This is not passing the correct size input valid for RX.

If you have a minimal working example, that would be nice :slight_smile:

Thanks @ludmilaaasb for the response. Actually, the code I shared is the minimal code. The actual quantum circuit that I am using in my project is way more complicated than the one I shared.

However, it does not give me the error you mentioned. Are you using the same Pennylane version that I am using?

Indeed, I am using the latest version. And I strongly advise you to update yours.

Does this status still prevails or there are ways to perform true broadcasting in the latest versions of pennylane within qnn.TorchLayer?

Yes! The latest version is performing true broadcasting! If you take a look at the release notes, you can see that now we have native support.

Does it help? :slight_smile:

1 Like

Problem 1: If I use a tensor created using torch.rand() method, I get the following error. However, this error is not there when I used a tensor created with a numpy vector. I am not sure why this happens.

So, I did a minor modification on the code and it works fine for me! :slightly_smiling_face:

import pennylane as qml
from pennylane import numpy as np
import time as time
import torch
import torch.nn as nn

dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev, interface = 'torch')
def simple_qubit_circuit(inputs, theta):
    qml.RX(inputs, wires=0)
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))
class QNet(nn.Module):
    def __init__(self):
        super().__init__()
        shapes = {
            "theta": ()
        }
        self.q = qml.qnn.TorchLayer(simple_qubit_circuit, shapes)
    
    def forward(self, input_value):
        return self.q(input_value)

x_train = torch.rand(10)
x_train = torch.atan(x_train)

model = QNet()
t1 = time.time()
out = model(x_train)
print("time taken for batch operations: ", time.time()-t1)
out2 = []
t2 = time.time()
for x in x_train:
    out2.append(model(x).item())
print("time taken for sequential operations: ", time.time()-t2)

print(out)
print(out2)

And the output:

time taken for batch operations:  0.001728057861328125
time taken for sequential operations:  0.00826883316040039
tensor([0.3852, 0.4101, 0.4733, 0.4276, 0.5313, 0.5150, 0.4444, 0.4483, 0.5314,
        0.5327], grad_fn=<ToCopyBackward0>)
[0.3851933479309082, 0.41005653142929077, 0.4732654094696045, 0.42755088210105896, 0.5312792658805847, 0.5150039792060852, 0.4443522095680237, 0.4482826292514801, 0.5314198732376099, 0.5326558351516724]

Problem 3:
The output tensors calculated using batch operation vs sequential operation for the same input tensor and for the same weight is different which should not be the case. Again not sure what’s wrong here

They look the same for me. So I think the solution is just basically updating for the lastest version and it should be fine! :grin:

Hey @ludmilaaasb , thanks for your response. I updated my pennylane version and used the same code you shared. However, I am getting the following error:

ValueError: RX: wrong number(s) of dimensions in parameters. Parameters with ndims (2,) passed, (0,) expected.

I am not sure why I am getting this error when I am using the same pennylane version. Here is the output of qml.about()

qml.about()
Name: PennyLane
Version: 0.31.1
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/PennyLaneAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: c:\users\aksi01\appdata\roaming\python\python38\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
Required-by: PennyLane-Lightning, PennyLane-qiskit
Platform info:           Windows-10-10.0.19045-SP0
Python version:          3.8.15
Numpy version:           1.23.5
Scipy version:           1.10.1
Installed devices:
- default.gaussian (PennyLane-0.31.1)
- default.mixed (PennyLane-0.31.1)
- default.qubit (PennyLane-0.31.1)
- default.qubit.autograd (PennyLane-0.31.1)
- default.qubit.jax (PennyLane-0.31.1)
- default.qubit.tf (PennyLane-0.31.1)
- default.qubit.torch (PennyLane-0.31.1)
- default.qutrit (PennyLane-0.31.1)
- null.qubit (PennyLane-0.31.1)
- lightning.qubit (PennyLane-Lightning-0.31.0)
- qiskit.aer (PennyLane-qiskit-0.29.0)
- qiskit.basicaer (PennyLane-qiskit-0.29.0)
- qiskit.ibmq (PennyLane-qiskit-0.29.0)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.29.0)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.29.0)

Hmm, that’s strange :thinking:

I am not sure why I am getting this error when I am using the same pennylane version.

Would mind sharing how are you setting x_train? Check x_train.ndim(). If it returns 2, then you are going to get the error

ValueError: RX: wrong number(s) of dimensions in parameters. Parameters with ndims (2,) passed, (0,) expected.

It is complaining about the dimension of the parameters. RX is expecting a number and it is receiving a tensor with shape (2,), that’s why you got the error.

Hello @ludmilaaasb ,

I am reposting the entire code that I am using. The updated pennylane version is behaving very weirdly sometimes.

import pennylane as qml
from pennylane import numpy as np
import time as time
import torch
import torch.nn as nn

dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev, interface = 'torch')
def simple_qubit_circuit(inputs, theta):
    qml.RX(inputs, wires=0)
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))
class QNet(nn.Module):
    def __init__(self):
        super().__init__()
        quantum_weights = np.random.normal(0, np.pi)
        self.quantum_weights = nn.parameter.Parameter(torch.tensor(quantum_weights,\
                                    dtype=torch.float32,requires_grad=True))
        shapes = {
            "theta": 1
        }
        self.q = qml.qnn.TorchLayer(simple_qubit_circuit, shapes)
    
    def forward(self, input_value):
        return self.q(input_value)

# x_train = np.array([0.2, 0.1, 0.2, 0.14, 0.11, 0.41, 0.55, 0.3, 0.31, 0.6])
# x_train = torch.tensor(x_train).reshape(10,1)

x_train = torch.rand(10)
x_train = torch.atan(x_train)
model = QNet()
t1 = time.time()
out = model(x_train)
print("time taken for batch operations: ", time.time()-t1)
out2 = []
t2 = time.time()
for x in x_train:
    out2.append(model(x).item())
print("time taken for sequential operations: ", time.time()-t2)

print(out)
print(out2)

I am getting the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_22300\3277396942.py in <cell line: 9>()
      7 model = QNet()
      8 t1 = time.time()
----> 9 out = model(x_train)
     10 print("time taken for batch operations: ", time.time()-t1)
     11 out2 = []

~\Miniconda3\envs\qns\lib\site-packages\torch\nn\modules\module.py in _call_impl(self, *input, **kwargs)
   1192         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1193                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1194             return forward_call(*input, **kwargs)
   1195         # Do not call functions when jit is used
   1196         full_backward_hooks, non_full_backward_hooks = [], []

~\AppData\Local\Temp\ipykernel_22300\1881420835.py in forward(self, input_value)
     23 
     24     def forward(self, input_value):
---> 25         return self.q(input_value)

~\Miniconda3\envs\qns\lib\site-packages\torch\nn\modules\module.py in _call_impl(self, *input, **kwargs)
   1192         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1193                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1194             return forward_call(*input, **kwargs)
   1195         # Do not call functions when jit is used
   1196         full_backward_hooks, non_full_backward_hooks = [], []

~\AppData\Roaming\Python\Python38\site-packages\pennylane\qnn\torch.py in forward(self, inputs)
    406         else:
    407             # calculate the forward pass as usual
--> 408             results = self._evaluate_qnode(inputs)
    409 
    410         # reshape to the correct number of batch dims

~\AppData\Roaming\Python\Python38\site-packages\pennylane\qnn\torch.py in _evaluate_qnode(self, x)
    427             **{arg: weight.to(x) for arg, weight in self.qnode_weights.items()},
    428         }
--> 429         res = self.qnode(**kwargs)
    430 
    431         if isinstance(res, torch.Tensor):

~\AppData\Roaming\Python\Python38\site-packages\pennylane\qnode.py in __call__(self, *args, **kwargs)
    948                 self.execute_kwargs.pop("mode")
    949             # pylint: disable=unexpected-keyword-arg
--> 950             res = qml.execute(
    951                 [self.tape],
    952                 device=self.device,

~\AppData\Roaming\Python\Python38\site-packages\pennylane\interfaces\execution.py in execute(tapes, device, gradient_fn, interface, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform)
    640             _execute = _get_jax_execute_fn(interface, tapes)
    641 
--> 642         res = _execute(
    643             tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n=1, max_diff=max_diff
    644         )

~\AppData\Roaming\Python\Python38\site-packages\pennylane\interfaces\torch.py in execute(tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
    496     }
    497 
--> 498     return ExecuteTapes.apply(kwargs, *parameters)
    499 
    500 

~\AppData\Roaming\Python\Python38\site-packages\pennylane\interfaces\torch.py in new_apply(*inp)
    260         # Inputs already flat
    261         out_struct_holder = []
--> 262         flat_out = orig_apply(out_struct_holder, *inp)
    263         return pytree.tree_unflatten(flat_out, out_struct_holder[0])
    264 

~\AppData\Roaming\Python\Python38\site-packages\pennylane\interfaces\torch.py in new_forward(ctx, out_struct_holder, *inp)
    264 
    265     def new_forward(ctx, out_struct_holder, *inp):
--> 266         out = orig_fw(ctx, *inp)
    267         flat_out, out_struct = pytree.tree_flatten(out)
    268         ctx._out_struct = out_struct

~\AppData\Roaming\Python\Python38\site-packages\pennylane\interfaces\torch.py in forward(ctx, kwargs, *parameters)
    341 
    342         unwrapped_tapes = tuple(convert_to_numpy_parameters(t) for t in ctx.tapes)
--> 343         res, ctx.jacs = ctx.execute_fn(unwrapped_tapes, **ctx.gradient_kwargs)
    344 
    345         # if any input tensor uses the GPU, the output should as well

~\AppData\Roaming\Python\Python38\site-packages\pennylane\interfaces\execution.py in wrapper(tapes, **kwargs)
    285             # execute all unique tapes that do not exist in the cache
    286             # convert to list as new device interface returns a tuple
--> 287             res = list(fn(execution_tapes.values(), **kwargs))
    288 
    289         final_res = []

~\AppData\Roaming\Python\Python38\site-packages\pennylane\interfaces\execution.py in fn(tapes, **kwargs)
    208         def fn(tapes: Sequence[QuantumTape], **kwargs):  # pylint: disable=function-redefined
    209             tapes = [expand_fn(tape) for tape in tapes]
--> 210             return original_fn(tapes, **kwargs)
    211 
    212     @wraps(fn)

~\Miniconda3\envs\qns\lib\contextlib.py in inner(*args, **kwds)
     73         def inner(*args, **kwds):
     74             with self._recreate_cm():
---> 75                 return func(*args, **kwds)
     76         return inner
     77 

~\AppData\Roaming\Python\Python38\site-packages\pennylane\_qubit_device.py in batch_execute(self, circuits)
    601             self.reset()
    602 
--> 603             res = self.execute(circuit)
    604             results.append(res)
    605 

~\AppData\Roaming\Python\Python38\site-packages\pennylane\_qubit_device.py in execute(self, circuit, **kwargs)
    322         # generate computational basis samples
    323         if self.shots is not None or circuit.is_sampled:
--> 324             self._samples = self.generate_samples()
    325 
    326         # compute the required statistics

~\AppData\Roaming\Python\Python38\site-packages\pennylane\_qubit_device.py in generate_samples(self)
   1158         rotated_prob = self.analytic_probability()
   1159 
-> 1160         samples = self.sample_basis_states(number_of_states, rotated_prob)
   1161         return self.states_to_binary(samples, self.num_wires)
   1162 

~\AppData\Roaming\Python\Python38\site-packages\pennylane\_qubit_device.py in sample_basis_states(self, number_of_states, state_probability)
   1186             # np.random.choice does not support broadcasting as needed here.
   1187             return np.array(
-> 1188                 [np.random.choice(basis_states, shots, p=prob) for prob in state_probability]
   1189             )
   1190 

~\AppData\Roaming\Python\Python38\site-packages\pennylane\_qubit_device.py in <listcomp>(.0)
   1186             # np.random.choice does not support broadcasting as needed here.
   1187             return np.array(
-> 1188                 [np.random.choice(basis_states, shots, p=prob) for prob in state_probability]
   1189             )
   1190 

mtrand.pyx in numpy.random.mtrand.RandomState.choice()

ValueError: probabilities do not sum to 1

It looks like that this is a bug with Pennylane which @Maria_Schuld had pointed in this post.

Indeed, that was happening in the previous versions of Pennylane. But as Maria pointed out in the same post:

And we will be glad to help to fix the issue! But I couldn’t reproduce the error with the code you sent. It runs with no errors here. Are you sure the code is running in the correct environment with the latest version of Pennylane installed?

Hello @ludmilaaasb - Yes, I am using the same environment where I have the new PL version installed. Can you check if there is a discrepancy in between the versions of other dependencies such as numpy?

Your versions of Pennylane and Numpy are ok. Would you mind sharing your torch version and a minimal, self-contained working version of your code to reproduce the error? It’s difficult to help without having the correct code to work on.

For instance, you can safely remove time, the printing statements, commented/unusead lines in general, and reduce the complexity of QNode… If you are having struggles to do that, I strongly recommend this video. It has some tips for how to make a post with proper code snippets and errors, so we can help you better!

Hello @ludmilaaasb
My torch version is 1.13.1+cpu.

Following is the minimal working version of my code:

import pennylane as qml
import numpy as np
import torch
import torch.nn as nn
dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev, interface = 'torch')
def simple_qubit_circuit(inputs, theta):
    qml.RX(inputs, wires=0)
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))
class QNet(nn.Module):
    def __init__(self):
        super().__init__()
        shapes = {
            "theta": 1
        }
        self.q = qml.qnn.TorchLayer(simple_qubit_circuit, shapes)
    
    def forward(self, input_value):
        return self.q(input_value)

x_train = np.array([0.2, 0.1, 0.2, 0.14, 0.11, 0.41, 0.55, 0.3, 0.31, 0.6])
x_train = torch.tensor(x_train)
model = QNet()
out = model(x_train)

The issue arises only when I replace x_train with the following:

x_train = torch.rand(10)
x_train = torch.atan(x_train)

Hmmm, the latest stable version of torch is 2.0.1. Try updating it and see if the error persists.

Update: I created a clean environment using torch=1.13.1 and the latest version of pennylane and tested your code with

x_train = torch.rand(10)
x_train = torch.atan(x_train)

No issues were found. So, maybe you could try running it in a google colab notebook or making a clean install of your packages in a new environment.

I hope this will help! :slight_smile:

1 Like