# Different interfaces, different performances

**URL:** <https://discuss.pennylane.ai/t/different-interfaces-different-performances/454>\
**Category:** PennyLane Help\
**Created:** [July 7, 2020, 10:58pm UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454 "2020-07-07T22:58:02Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![mamadpierre](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/mamadpierre/32/223_2.png) [@mamadpierre](https://discuss.pennylane.ai/u/mamadpierre)\
**Post date:** [July 7, 2020, 10:58pm UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/1 "2020-07-07T22:58:02Z")

</div>

There is an example presented by PennyLane for `qml.qnn.TorchLayer` which I copy below. If one modifies only the interface line from `@qml.qnode(dev)` to `@qml.qnode(dev, interface='torch')` the convergence behavior drastically changes:

for the case `@qml.qnode(dev)`:

```auto
Average loss over epoch 10: 0.1589
Average loss over epoch 20: 0.1331
Average loss over epoch 30: 0.1321

```

and for the case `@qml.qnode(dev, interface='torch')`:

```auto
Average loss over epoch 100: 0.1709
Average loss over epoch 200: 0.1593
Average loss over epoch 300: 0.1538
Average loss over epoch 400: 0.1505
Average loss over epoch 500: 0.1482
Average loss over epoch 600: 0.1462
Average loss over epoch 700: 0.1448
Average loss over epoch 800: 0.1434
Average loss over epoch 900: 0.1426
Average loss over epoch 1000: 0.1415

```

## I am wondering **what is the reason behind this and further how do we know in general which interface is the most suitable for the problem?**

code:

```auto
import numpy as np
import pennylane as qml
import torch
import sklearn.datasets

n_qubits = 2
dev = qml.device("default.qubit", wires=n_qubits)

@qml.qnode(dev, interface='torch') # the default was @qml.qnode(dev)
def qnode(inputs, weights):
    qml.templates.AngleEmbedding(inputs, wires=range(n_qubits))
    qml.templates.StronglyEntanglingLayers(weights, wires=range(n_qubits))
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

weight_shapes = {"weights": (3, n_qubits, 3)}

qlayer = qml.qnn.TorchLayer(qnode, weight_shapes)

clayer1 = torch.nn.Linear(2, 2)
clayer2 = torch.nn.Linear(2, 2)
softmax = torch.nn.Softmax(dim=1)
model = torch.nn.Sequential(clayer1, qlayer, clayer2, softmax)

samples = 100
x, y = sklearn.datasets.make_moons(samples)
y_hot = np.zeros((samples, 2))
y_hot[np.arange(samples), y] = 1

X = torch.tensor(x).float()
Y = torch.tensor(y_hot).float()

opt = torch.optim.SGD(model.parameters(), lr=0.5)
loss = torch.nn.L1Loss()

epochs = 1000
batch_size = 5
batches = samples // batch_size

data_loader = torch.utils.data.DataLoader(list(zip(X, Y)), batch_size=batch_size,
                                          shuffle=True, drop_last=True)

for epoch in range(epochs):

    running_loss = 0

    for x, y in data_loader:
        opt.zero_grad()
        loss_evaluated = loss(model(x), y)
        loss_evaluated.backward()
        opt.step()
        running_loss += loss_evaluated

    avg_loss = running_loss / batches
    if (epoch+1) % 100 ==0:
        print("Average loss over epoch {}: {:.4f}".format(epoch + 1, avg_loss))

```

---

<div class="post-metadata">

**Author:** ![josh](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/josh/32/100_2.png) [@josh](https://discuss.pennylane.ai/u/josh)\
**Post date:** [July 8, 2020, 10:10am UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/2 "2020-07-08T10:10:44Z")

</div>

Hi @mamadpierre!

Currently, when using the `qml.qnn` module, it is best to always create a bare QNode with no interface, and use this to initialize the `KerasLayer`. That is, simply `@qml.qnode(dev)`.

The behaviour you found (where training differs if `interface=` is passed to the decorator) is a known bug — this has been [fixed in master](https://github.com/XanaduAI/pennylane/pull/707), and will be making it into the next PennyLane release!

---

<div class="post-metadata">

**Author:** ![mamadpierre](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/mamadpierre/32/223_2.png) [@mamadpierre](https://discuss.pennylane.ai/u/mamadpierre)\
**Post date:** [July 8, 2020, 11:03am UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/3 "2020-07-08T11:03:20Z")

</div>

Hi @josh  
Thanks for your prompt response. I understood. Now that you answered my question thoroughly and I already shared the above code, I ask you another one.  
How to use the above code with `device = "cuda"`?  
Please **note** that:

1. I add `device = "cuda"` and modify below two lines:

`x, y = x.to(device), y.to(device)`

`model = torch.nn.Sequential(clayer1, qlayer, clayer2, softmax).to(device)`

But I receive an error.

1. If I omit the `qlayer` from `nn.Sequential`, the classical code **works fine** with cuda.

* * *

Error:

```auto
    line 68, in <module>
    loss_evaluated.backward()
    line 198, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
    line 100, in backward
    allow_unreachable=True) # allow_unreachable flag
RuntimeError: Expected object of device type cuda but got device type cpu for argument 2 'mat2' in call to _th_mm
```

---

<div class="post-metadata">

**Author:** ![josh](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/josh/32/100_2.png) [@josh](https://discuss.pennylane.ai/u/josh)\
**Post date:** [July 8, 2020, 11:56am UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/4 "2020-07-08T11:56:19Z")

</div>

Thanks for reporting this @mamadpierre! I will look into this and get back to you, it looks like the current iteration of `TorchLayer` does not support placing models on the GPU.

For now, I recommend using the CPU with the `TorchLayer`.

---

<div class="post-metadata">

**Author:** ![mamadpierre](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/mamadpierre/32/223_2.png) [@mamadpierre](https://discuss.pennylane.ai/u/mamadpierre)\
**Post date:** [July 8, 2020, 12:50pm UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/5 "2020-07-08T12:50:08Z")

</div>

Thanks for the time and consideration @josh. My guess is the `weights` and `inputs` structures are by default not suitable for `Cuda` which maybe can be modified?

The error has been reported almost at the same time [here](http://discuss.pennylane.ai/t/pennylane-and-pytorch-running-on-gpu/457) as well.

---

<div class="post-metadata">

**Author:** ![Tom\_Bromley](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/tom_bromley/32/129_2.png) [@Tom\_Bromley](https://discuss.pennylane.ai/u/Tom_Bromley)\
**Post date:** [July 8, 2020, 2:30pm UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/6 "2020-07-08T14:30:52Z")

</div>

Hi @mamadpierre!

Thanks for checking this out! We had a quick look and managed to get the following to work without error:

```python
import numpy as np
import pennylane as qml
import torch
import sklearn.datasets
​
n_qubits = 2
dev = qml.device("default.qubit", wires=n_qubits)
​
@qml.qnode(dev) # the default was @qml.qnode(dev)
def qnode(inputs, weights):
    qml.templates.AngleEmbedding(inputs, wires=range(n_qubits))
    qml.templates.StronglyEntanglingLayers(weights, wires=range(n_qubits))
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))
​
weight_shapes = {"weights": (3, n_qubits, 3)}
​
qlayer = qml.qnn.TorchLayer(qnode, weight_shapes)
​
clayer1 = torch.nn.Linear(2, 2)
clayer2 = torch.nn.Linear(2, 2)
softmax = torch.nn.Softmax(dim=1)
​
​
device = "cuda"
model = torch.nn.Sequential(clayer1, qlayer, clayer2, softmax).to(device)
# model = torch.nn.Sequential(clayer1, clayer2, softmax).to(device)
​
samples = 100
x, y = sklearn.datasets.make_moons(samples)
y_hot = np.zeros((samples, 2))
y_hot[np.arange(samples), y] = 1
​
X = torch.tensor(x).float()
Y = torch.tensor(y_hot).float()
X, Y = X.to(device), Y.to(device)
​
model(X[:10])

```

That being said, `TorchLayer` is fairly new so it’s possible that it doesn’t work so well on GPU. For now, it might be best to stick with the CPU version as @josh mentioned.

---

<div class="post-metadata">

**Author:** ![mamadpierre](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/mamadpierre/32/223_2.png) [@mamadpierre](https://discuss.pennylane.ai/u/mamadpierre)\
**Post date:** [July 8, 2020, 4:26pm UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/7 "2020-07-08T16:26:34Z")

</div>

Hi @Tom_Bromley Thanks for the time and quick reply. I copy pasted the provided code and I receive the following error:

```auto
Traceback (most recent call last):
  File "torchQuantumLayer.py", line 70, in <module>
    loss_evaluated = loss(model(x), y)
  File "anaconda3/envs/MnistPytorch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 550, in __call__
    result = self.forward(*input, **kwargs)
  File "anaconda3/envs/MnistPytorch/lib/python3.7/site-packages/torch/nn/modules/container.py", line 100, in forward
    input = module(input)
  File "anaconda3/envs/MnistPytorch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 550, in __call__
    result = self.forward(*input, **kwargs)
  File "anaconda3/envs/MnistPytorch/lib/python3.7/site-packages/torch/nn/modules/linear.py", line 87, in forward
    return F.linear(input, self.weight, self.bias)
  File "anaconda3/envs/MnistPytorch/lib/python3.7/site-packages/torch/nn/functional.py", line 1610, in linear
    ret = torch.addmm(bias, input, weight.t())
RuntimeError: Expected object of device type cuda but got device type cpu for argument #2 'mat1' in call to _th_addmm

```

* * *

Versions:

```auto
Python 3.7.7 (default, May 7 2020, 21:25:33) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
import pennylane
import torch
print(torch. __version__ )
1.5.1
print(pennylane. __version__ )
0.10.0
```

---

<div class="post-metadata">

**Author:** ![Tom\_Bromley](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/tom_bromley/32/129_2.png) [@Tom\_Bromley](https://discuss.pennylane.ai/u/Tom_Bromley)\
**Post date:** [July 9, 2020, 11:14am UTC](https://discuss.pennylane.ai/t/different-interfaces-different-performances/454/8 "2020-07-09T11:14:04Z")

</div>

Hi @mamadpierre,

Thanks for also trying that code! Weird that it behaves differently for both of us. I ended up using an earlier version of Torch as the GPU drivers on my device needed updating, perhaps it was that 🤔 For now we’ll just have to recommend running on CPU, but this has definitely put GPU support on our radar, thanks!
