quantum-ods / qmlcourse

Курс по квантовому машинному обучению
https://quantum-ods.github.io/qmlcourse/
Creative Commons Attribution 4.0 International
228 stars 32 forks source link

pennylane не поддерживает `@qml.template` #393

Closed vvssttkk closed 2 years ago

vvssttkk commented 2 years ago

в лекции Квантово-классический SVM имеются проблемы с декоратором @qml.template

можно решить понизив версию pennylane, ну или лучше разобраться как сделать на новой же версии

ошибка

Traceback (most recent call last):
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/jupyter_cache/executors/utils.py", line 51, in single_nb_execution
    executenb(
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/nbclient/client.py", line 1093, in execute
    return NotebookClient(nb=nb, resources=resources, km=km, **kwargs).execute()
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/nbclient/util.py", line 84, in wrapped
    return just_run(coro(*args, **kwargs))
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/nbclient/util.py", line 62, in just_run
    return loop.run_until_complete(coro)
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/nbclient/client.py", line 559, in async_execute
    await self.async_execute_cell(
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/nbclient/client.py", line 854, in async_execute_cell
    self._check_raise_for_error(cell, exec_reply)
  File "/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/nbclient/client.py", line 756, in _check_raise_for_error
    raise CellExecutionError.from_cell_and_msg(cell, exec_reply_content)
nbclient.exceptions.CellExecutionError: An error occurred while executing the following cell:
------------------
@qml.template
def var_layer(x):
    qml.Hadamard(wires=0)
    qml.Hadamard(wires=1)

    qml.U1(x[0], wires=0)
    qml.U1(x[1], wires=1)

    qml.Hadamard(wires=0)
    qml.Hadamard(wires=1)

    qml.CNOT(wires=[0, 1])
    qml.U1(np.pi * np.cos(x[0]) * np.cos(x[1]), wires=1)
    qml.CNOT(wires=[0, 1])
------------------

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipykernel_6757/2703634271.py in <module>
----> 1 @qml.template
      2 def var_layer(x):
      3     qml.Hadamard(wires=0)
      4     qml.Hadamard(wires=1)
      5 

/usr/share/miniconda/envs/__setup_conda/lib/python3.8/site-packages/pennylane/__init__.py in __getattr__(name)
    344         return _qchem
    345 
--> 346     raise AttributeError(f"module {__name__} has no attribute {name}")
    347 
    348 

AttributeError: module pennylane has no attribute template
AttributeError: module pennylane has no attribute template
vvssttkk commented 2 years ago

если понизить версию pl, то не будет возможности рисовать схемы, чего не хотелось бы

vvssttkk commented 2 years ago

в #357 поднимали уже эту тему

vvssttkk commented 2 years ago

что имеем, согласно https://pennylane.readthedocs.io/en/stable/development/release_notes.html

переписав на

from pennylane import numpy as np
import pennylane as qml
import matplotlib.pyplot as plt
%config InlineBackend.figure_format = 'retina'
from sklearn.datasets import make_moons
x, y = make_moons(n_samples=50)
y = y * 2 - 1

def normalize(x):
    """Переводит значения в интервал от -1 до 1"""

    min_ = x.min()
    max_ = x.max()
    return 2 * (x - min_) / (max_ - min_) - 1

x[:, 0] = normalize(x[:, 0])
x[:, 1] = normalize(x[:, 1])

plt.figure(figsize=(4, 3))
cb = plt.scatter(x[:, 0], x[:, 1], c=y)
plt.colorbar(cb)
plt.show()
import pennylane.tape

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

def var_layer(x):
    with qml.tape.QuantumTape() as tape:
        qml.Hadamard(wires=0)
        qml.Hadamard(wires=1)

        qml.U1(x[0], wires=0)
        qml.U1(x[1], wires=1)

        qml.Hadamard(wires=0)
        qml.Hadamard(wires=1)

        qml.CNOT(wires=[0, 1])
        qml.U1(np.pi * np.cos(x[0]) * np.cos(x[1]), wires=1)
        qml.CNOT(wires=[0, 1])

@qml.qnode(dev)
def dot_prod(x1, x2):
    var_layer(x1)
    # qml.inv(var_layer(x2))
    qml.adjoint(var_layer(x2))

    return qml.probs(wires=[0, 1])

def q_dot_prod(i, j):
    x1 = (x[i, 0], x[i, 1])
    x2 = (x[j, 0], x[j, 1])
    return dot_prod(x1, x2)[0]

q_dot_prod(1, 0)
# q_dot_prod(0, 1)

получаю ошибку которую не пойму как порешать

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/workspaces/qmlcourse/test.ipynb Cell 6' in <cell line: 33>()
     30     x2 = (x[j, 0], x[j, 1])
     31     return dot_prod(x1, x2)[0]
---> 33 q_dot_prod(1, 0)

/workspaces/qmlcourse/test.ipynb Cell 6' in q_dot_prod(i, j)
     29 x1 = (x[i, 0], x[i, 1])
     30 x2 = (x[j, 0], x[j, 1])
---> 31 return dot_prod(x1, x2)[0]

File /opt/python/3.10.4/lib/python3.10/site-packages/pennylane/qnode.py:566, in QNode.__call__(self, *args, **kwargs)
    563         set_shots(self._original_device, override_shots)(self._update_gradient_fn)()
    565 # construct the tape
--> 566 self.construct(args, kwargs)
    568 cache = self.execute_kwargs.get("cache", False)
    569 using_custom_cache = (
    570     hasattr(cache, "__getitem__")
    571     and hasattr(cache, "__setitem__")
    572     and hasattr(cache, "__delitem__")
    573 )

File /opt/python/3.10.4/lib/python3.10/site-packages/pennylane/qnode.py:483, in QNode.construct(self, args, kwargs)
    480 self._tape = qml.tape.QuantumTape()
    482 with self.tape:
--> 483     self._qfunc_output = self.func(*args, **kwargs)
    484 self._tape._qfunc_output = self._qfunc_output
    486 params = self.tape.get_parameters(trainable_only=False)

/workspaces/qmlcourse/test.ipynb Cell 6' in dot_prod(x1, x2)
     22 var_layer(x1)
     23 # qml.inv(var_layer(x2))
---> 24 qml.adjoint(var_layer(x2))
     26 return qml.probs(wires=[0, 1])

File /opt/python/3.10.4/lib/python3.10/site-packages/pennylane/transforms/adjoint.py:113, in adjoint(fn)
     22 """Create a function that applies the adjoint (inverse) of the provided operation or template.
     23 
     24 This transform can be used to apply the adjoint of an arbitrary sequence of operations.
   (...)
    110     0: ──RX(0.12)──RX(-0.12)─┤  <Z>
    111 """
    112 if not callable(fn):
--> 113     raise ValueError(
    114         f"The object {fn} of type {type(fn)} is not callable. "
    115         "This error might occur if you apply adjoint to a list "
    116         "of operations instead of a function or template."
    117     )
    119 @wraps(fn)
    120 def wrapper(*args, **kwargs):
    121     with stop_recording(), QuantumTape() as tape:

ValueError: The object None of type <class 'NoneType'> is not callable. This error might occur if you apply adjoint to a list of operations instead of a function or template.

@SemyonSinchenko @SergeiShirkin мб вы знаете где накосячил в коде?

SemyonSinchenko commented 2 years ago

Попробуй tape.adjoint() вместо qml.adjoint. Хотя у тебя же функция... Вот не знаю. Надо подумать.

vvssttkk commented 2 years ago

итого,

@qml.qnode(dev)
def dot_prod(x1, x2):
    var_layer(x1)

    # qml.inv(var_layer(x2)) # было изначально в лекции

    qml.adjoint(var_layer(x2)) # измененил и завелось

    return qml.probs(wires=[0, 1])

на выходе получаю

q_dot_prod(0, 1) = tensor(0.69915571, requires_grad=True)
q_dot_prod(1, 0) = tensor(0.68946841, requires_grad=True)

идём дальше и для np.allclose(q_dot_prod(0, 1), q_dot_prod(1, 0)) получаю False; получается что «скалярное произведение» не есть симметричное, хоть и должно, судя по лекции

@SemyonSinchenko @SergeiShirkin что сделал не так?

зы

print(dot_prod.draw()) пока не работает, выдает 'QNode' object has no attribute 'draw'. но это после

Randl commented 2 years ago
from pennylane import numpy as np
import pennylane as qml
import matplotlib.pyplot as plt

from sklearn.datasets import make_moons

x, y = make_moons(n_samples=50)
y = y * 2 - 1

def normalize(x):
    """Переводит значения в интервал от -1 до 1"""
    min_ = x.min()
    max_ = x.max()
    return 2 * (x - min_) / (max_ - min_) - 1

x[:, 0] = normalize(x[:, 0])
x[:, 1] = normalize(x[:, 1])

import pennylane.tape

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

def var_layer(x):
    with qml.tape.QuantumTape() as tape:
        qml.Hadamard(wires=0)
        qml.Hadamard(wires=1)

        qml.U1(x[0], wires=0)
        qml.U1(x[1], wires=1)

        qml.Hadamard(wires=0)
        qml.Hadamard(wires=1)

        qml.CNOT(wires=[0, 1])
        qml.U1(np.pi * np.cos(x[0]) * np.cos(x[1]), wires=1)
        qml.CNOT(wires=[0, 1])

@qml.qnode(dev)
def dot_prod(x1, x2):
    var_layer(x1)
    qml.adjoint(var_layer)(x2) # измененил и завелось
    return qml.probs(wires=[0, 1])

def q_dot_prod(i, j):
    x1 = (x[i, 0], x[i, 1])
    x2 = (x[j, 0], x[j, 1])
    return dot_prod(x1, x2)[0]

print(q_dot_prod(1, 0))
print(q_dot_prod(0, 1))

Вот этот код у меня выдает два одинаковых числа.