Source code for qailab.torch.qlayer
1""" Module with QLayer """
2import math
3
4import torch
5from torch import Tensor, nn
6
7from qiskit import QuantumCircuit, transpile
8from qiskit.circuit.library.generalized_gates.isometry import Isometry
9
10from quantum_launcher import QuantumLauncher
11from quantum_launcher.routines.qiskit_routines import QiskitBackend
12
13from qailab.circuit.utils import filter_params
14from qailab.qlauncher import CircuitProblem, ForwardPass, BackwardPass
15from qailab.torch.autograd import ExpVQCFunction
16Isometry.__init__.__defaults__ = (1e-6,) # FIXME: If anyone has any idea, feel free
17
18
[docs]
19class QLayer(nn.Module):
20 """
21 Base quantum layer class.
22
23 This layer will output 2^num_measured_qubits features,
24 which represent the distribution of measurements from the underlying quantum circuit.
25
26 The bitstring order is [0, 1, 2, ..., 2^num_measured_qubits-1]
27 """
28 theta_trainable: Tensor
29
30 def __init__(
31 self,
32 circuit: QuantumCircuit,
33 *,
34 backend: QiskitBackend | None = None,
35 shots: int = 1024,
36 ) -> None:
37 super().__init__()
38
39 self.theta_trainable = nn.Parameter(
40 torch.empty((len(filter_params(circuit, 'weight')), 1))
41 )
42
43 self.reset_parameters()
44
45 if backend is None:
46 backend = QiskitBackend('local_simulator')
47
48 self.circuit = transpile(circuit, backend.sampler.backend) if hasattr(backend.sampler, 'backend') else circuit
49 self.circuit_pr = CircuitProblem(self.circuit)
50
51 # Helper variables for hybrid networks
52 self.in_features = len(filter_params(circuit, 'input'))
53 self.out_features = 2**self.circuit.num_clbits
54
55 self.launcher_forward = QuantumLauncher(
56 self.circuit_pr,
57 ForwardPass(shots=shots),
58 backend
59 )
60 self.launcher_backward = QuantumLauncher(
61 self.circuit_pr,
62 BackwardPass('param_shift', shots=shots),
63 backend
64 )
65
[docs]
66 def reset_parameters(self) -> None:
67 """ Parameter reset """
68 nn.init.uniform_(self.theta_trainable, 0, 2 * math.pi)
69
72
[docs]
73 def forward(self, input_tensor: Tensor) -> Tensor:
74 """Forward run"""
75 out = ExpVQCFunction.apply(
76 input_tensor,
77 self.theta_trainable[:, 0],
78 self.launcher_forward,
79 self.launcher_backward
80 )
81 if not isinstance(out, torch.Tensor):
82 raise ValueError("Function did not return tensor output")
83 return out