import abc
import numpy as np
import torch
from torch import nn
[docs]class ClassicalModel(nn.Module):
"""
Alias for PyTorch's nn.Module.
"""
@abc.abstractmethod
def forward(self, x: torch.Tensor, *args) -> torch.Tensor:
"""
Forward pass of the model.
:param x: Input data to the model.
:type x: torch.Tensor
:return: Output data of the model.
:rtype: torch.Tensor
"""
[docs]class QuantumModel:
"""
One of three components of MainModel.
It contains function that is trained on numpy arrays and backward prop has to be provided by hand.
"""
[docs] def clip(self, x: torch.Tensor, *args) -> torch.Tensor:
"""The only function in QuantumModel (QM) that operates on tensors.
It **should not** be dependent on any trainable weights.
Rather it can be thought of as a scaling on inputs to QM based on the actual encoding quantum model/device uses (such as amplitude, qsample, etc.).
Main Model will call it before QM's forward function.
It enables easy backprop through the model.
By default it's a linear activation function.
:param x: Raw input to QuantumModel
:type x: torch.Tensor
:return: Input to QuantumModel that `forward` function will accept.
:rtype: torch.Tensor
"""
return x
@abc.abstractmethod
def forward(self, x: np.ndarray, *args) -> np.ndarray:
"""Forward pass of the model.
:param x: Input data to the model.
:type x: np.ndarray
:return: Output data of the model.
:rtype: np.ndarray
"""
@abc.abstractmethod
def backward(self, prev_gradient: np.ndarray) -> np.ndarray:
"""Backward pass of the model.
:param prev_gradient: Gradient from the model after this one.
(i.e. the one that receives output of this models `forward` method)
:type prev_gradient: np.ndarray
:return: Output data of the model.
:rtype: np.ndarray
"""
def __call__(self, x: np.ndarray, *args) -> np.ndarray:
return self.forward(x, *args)