Signatures¶
At the heart of the package is the signatory.signature()
function.
Note
It comes with quite a lot of optional arguments, but most of them won’t need to be used for most use cases. See Simple example for a straightforward look at how to use it.
- signatory.signature(path: torch.Tensor, depth: int, stream: bool = False, basepoint: Union[bool, torch.Tensor] = False, inverse: bool = False, initial: Optional[torch.Tensor] = None, scalar_term: bool = False) torch.Tensor ¶
Applies the signature transform to a stream of data.
The input
path
is expected to be a three-dimensional tensor, with dimensions \((N, L, C)\), where \(N\) is the batch size, \(L\) is the length of the input sequence, and \(C\) denotes the number of channels. Thus each batch element is interpreted as a stream of data \((x_1, \ldots, x_L)\), where each \(x_i \in \mathbb{R}^C\).Let \(f = (f_1, \ldots, f_C) \colon [0, 1] \to \mathbb{R}^C\), be the unique continuous piecewise linear path such that \(f(\tfrac{i - 1}{N - 1}) = x_i\). Then and the signature transform of depth
depth
is computed, defined by\[\mathrm{Sig}(\text{path}) = \left(\left( \,\underset{0 < t_1 < \cdots < t_k < 1}{\int\cdots\int} \prod_{j = 1}^k \frac{\mathrm d f_{i_j}}{\mathrm dt}(t_j) \mathrm dt_1 \cdots \mathrm dt_k \right)_{\!\!1 \leq i_1, \ldots, i_k \leq C}\right)_{\!\!1\leq k \leq \text{depth}}.\]This gives a tensor of shape
\[(N, C + C^2 + \cdots + C^\text{depth}).\]- Parameters
path (
torch.Tensor
) – The batch of input paths to apply the signature transform to.depth (int) – The depth to truncate the signature at.
stream (bool, optional) – Defaults to False. If False then the usual signature transform of the whole path is computed. If True then the signatures of all paths \((x_1, \ldots, x_j)\), for \(j=2, \ldots, L\), are returned. (Or \(j=1, \ldots, L\) is
basepoint
is passed, see below.)basepoint (bool or
torch.Tensor
, optional) – Defaults to False. Ifbasepoint
is True then an additional point \(x_0 = 0 \in \mathbb{R}^C\) is prepended to the path before the signature transform is applied. (If this is False then the signature transform is invariant to translations of the path, which may or may not be desirable. Setting this to True removes this invariance.) Alternatively it may be atorch.Tensor
specifying the value of \(x_0\), in which case it should have shape \((N, C)\).inverse (bool, optional) – Defaults to False. If True then it is in fact the inverse signature that is computed. (Signatures form a group under the operation of the tensor product; the inverse is defined with respect to this operation.) From a machine learning perspective it does not particularly matter whether the signature or the inverse signature is computed - both represent essentially the same information as each other.
initial (None or
torch.Tensor
, optional) – Defaults to None. If it is atorch.Tensor
then it must be of size \((N, C + C^2 + ... + C^\text{depth})\), corresponding to the signature of another path. Then this signature is pre-tensor-multiplied on to the signature ofpath
. For a more thorough explanation, see this example.scalar_term (bool, optional) – Defaults to False. If True then the first channel of the computed signature will be filled with the constant 1 (in accordance with the usual mathematical definition). If False then this channel is omitted (in accordance with useful machine learning practice).
- Returns
A
torch.Tensor
. Given an inputtorch.Tensor
of shape \((N, L, C)\), and input argumentsdepth
,basepoint
,stream
, then the return value is, in pseudocode:if stream: if basepoint is True or isinstance(basepoint, torch.Tensor): return torch.Tensor of shape (N, L, C + C^2 + ... + C^depth) else: return torch.Tensor of shape (N, L - 1, C + C^2 + ... + C^depth) else: return torch.Tensor of shape (N, C + C^2 + ... + C^depth)
Note that the number of output channels may be calculated via the convenience function
signatory.signature_channels()
.
- class signatory.Signature(depth: int, stream: bool = False, inverse: bool = False, scalar_term: bool = False, **kwargs)¶
torch.nn.Module
wrapper around thesignatory.signature()
function.- Parameters
depth (int) – as
signatory.signature()
.stream (bool, optional) – as
signatory.signature()
.inverse (bool, optional) – as
signatory.signature()
.scalar_term (bool, optional) – as
signatory.signature()
.
- forward(path: torch.Tensor, basepoint: Union[bool, torch.Tensor] = False, initial: Optional[torch.Tensor] = None) torch.Tensor ¶
The forward operation.
- Parameters
path (
torch.Tensor
) – Assignatory.signature()
.basepoint (bool or
torch.Tensor
, optional) – Assignatory.signature()
.initial (None or
torch.Tensor
, optional) – Assignatory.signature()
.
- Returns
- signatory.signature_channels(channels: int, depth: int, scalar_term: bool = False) int ¶
Computes the number of output channels from a signature call. Specifically, it computes
\[\text{channels} + \text{channels}^2 + \cdots + \text{channels}^\text{depth}.\]- Parameters
channels (int) – The number of channels in the input; that is, the dimension of the space that the input path resides in.
depth (int) – The depth of the signature that is being computed.
scalar_term (bool, optional) – Defaults to False. Whether to include the constant ‘1’ scalar that may be included.
- Returns
An int specifying the number of channels in the signature of the path.
- signatory.extract_signature_term(sigtensor: torch.Tensor, channels: int, depth: int, scalar_term: bool = False) torch.Tensor ¶
Extracts a particular term from a signature.
The signature to depth \(d\) of a batch of paths in \(\mathbb{R}^\text{C}\) is a tensor with \(C + C^2 + \cdots + C^d\) channels. (See
signatory.signature()
.) This function extracts thedepth
term of that, returning a tensor with just \(C^\text{depth}\) channels.- Parameters
sigtensor (
torch.Tensor
) – The signature to extract the term from. Should be a result from thesignatory.signature()
function.channels (int) – The number of input channels \(C\).
depth (int) – The depth of the term to be extracted from the signature.
scalar_term (bool, optional) – Whether the signature was called with scalar_term=True or not.
- Returns
The
torch.Tensor
corresponding to thedepth
term of the signature.
- signatory.signature_combine(sigtensor1: torch.Tensor, sigtensor2: torch.Tensor, input_channels: int, depth: int, inverse: bool = False, scalar_term: bool = False) torch.Tensor ¶
Combines two signatures into a single signature.
Usage is most clear by example. See Combining signatures.
See also
signatory.multi_signature_combine()
for a more general version.- Parameters
sigtensor1 (
torch.Tensor
) – The signature of a path, as returned bysignatory.signature()
. This should be a two-dimensional tensor.sigtensor2 (
torch.Tensor
) – The signature of a second path, as returned bysignatory.signature()
, with the same shape assigtensor1
. Note that when the signature of the second path was created, it should have been called withbasepoint
set to the final value of the path that createdsigtensor1
. (See Combining signatures.)input_channels (int) – The number of channels in the two paths that were used to compute
sigtensor1
andsigtensor2
. This must be the same for bothsigtensor1
andsigtensor2
.depth (int) – The depth that
sigtensor1
andsigtensor2
have been calculated to. This must be the same for bothsigtensor1
andsigtensor2
.inverse (bool, optional) – Defaults to False. Whether
sigtensor1
andsigtensor2
were created withinverse=True
. This must be the same for bothsigtensor1
andsigtensor2
.scalar_term (bool, optional) – Defaults to False. Whether
sigtensor1
andsigtensor2
were created withscalar_term=True
. This must the same for bothsigtensor1
andsigtensor2
.
- Returns
Let
path1
be the path whose signature issigtensor1
. Letpath2
be the path whose signature issigtensor2
. Then this function returns the signature of the concatenation ofpath1
andpath2
along their stream dimension.
Danger
There is a subtle bug which can occur when using this function incautiously. Make sure that
sigtensor2
is created with an appropriatebasepoint
, see Combining signatures.If this is not done then the return value of this function will be essentially meaningless numbers.
- signatory.multi_signature_combine(sigtensors: List[torch.Tensor], input_channels: int, depth: int, inverse: bool = False, scalar_term: bool = False) torch.Tensor ¶
Combines multiple signatures into a single signature.
See also
signatory.signature_combine()
for a simpler version.- Parameters
sigtensors (list of
torch.Tensor
) – Signature of multiple paths, all of the same shape. They should all be two-dimensional tensors.input_channels (int) – As
signatory.signature_combine()
.depth (int) – As
signatory.signature_combine()
.inverse (bool, optional) – As
signatory.signature_combine()
.scalar_term (bool, optional) – As
signatory.signature_combine()
.
- Returns
Let
sigtensors
be a list of tensors, call them \(\text{sigtensor}_i\) for \(i = 0, 1, \ldots, k\). Let \(\text{path}_i\) be the path whose signature is \(\text{sigtensor}_i\). Then this function returns the signature of the concatenation of \(\text{path}_i\) along their stream dimension.
Danger
Make sure that each element of
sigtensors
is created with an appropriatebasepoint
, as withsignatory.signature_combine()
.