Hi, I’m trying to train a QCBM-style quantum circuit model. Being a QCBM circuit the circuit requires no inputs (for my purposes there are no embedding layers). However, TorchLayer requires the qnode to have inputs as a parameter. Therefore currently just to add a batch dimension ive used qml.batch_input and an embedding layer.
Is the correct approach to use qml.batch_params? For a given batch (lets say 16) i would like the 16 batch circuits to execute individually resulting in different bitstrings (due to ‘qml.sample()’). During loss calculation/backprop to update the weights of the qnode.
Overall I essentially want the same behaviour currently but without having to use ‘inputs’ .
pi = math.pi
class Binary_Generator(nn.Module):
def __init__(
self,
) -> None:
super(Binary_Generator, self).__init__()
self.n_qubits = 16
self.depth = 4
self.device = qml.device('default.qubit', wires = self.n_qubits, shots = 1)
q_weight_shapes = {"q_weights_y": (self.depth * self.n_qubits),
"q_weights_z": (self.depth * self.n_qubits)}
init_method = {"q_weights_y": lambda x : torch.nn.init.uniform_(x, -pi, pi),
"q_weights_z": lambda x : torch.nn.init.uniform_(x, -pi, pi)}
self.q_generator = qml.QNode(self._circuit, self.device, interface="torch")
batch_q_circuit = qml.batch_input(self.q_generator, argnum = 0)
self.batch_q_generator = TorchLayer(batch_q_circuit, q_weight_shapes, init_method = init_method)
def __str__(self):
return f"QuantumGenerator({self.n_qubits}) "
def _embed_features(self, features):
wires = range(self.n_qubits)
AngleEmbedding(features, wires=wires, rotation="X")
def _circuit(self, inputs, q_weights_y, q_weights_z):
"""Builds the circuit to be fed to the connector as a QML node"""
self._embed_features(inputs)
q_weights_y = q_weights_y.reshape(self.depth, self.n_qubits)
q_weights_z = q_weights_z.reshape(self.depth, self.n_qubits)
# Repeated layer
for i in range(self.depth):
for y in range(self.n_qubits):
qml.RY(q_weights_y[i][y], wires = y)
qml.RZ(q_weights_z[i][y], wires = y)
for y in range(self.n_qubits - 1):
qml.CNOT(wires=[y, y + 1])
return qml.sample()
def forward(self, inputs: Tensor):
return self.batch_q_generator(inputs)