torch_openreml.covariance.Operator¶
- class torch_openreml.covariance.Operator(*args, **kwargs)[source]¶
Bases:
MatrixAbstract base class for composite covariance matrix operators.
An operator combines one or more
Matrixinstances and optional fixedtorch.Tensoroperands into a single covariance matrix. Parameters and gradients are namespaced by operand — a parameter"sigma^2"belonging to operand"residual"is exposed as"residual/sigma^2"in the combinedparam_names.Operands may be passed as positional arguments, as keyword arguments, or as a single dictionary. Mixing positional and keyword arguments is not permitted. Positional operands are assigned names
"op_0","op_1", etc.At least one operand must be a
Matrixinstance. Pure-tensor operands are treated as fixed matrices with no free parameters.Every operand is built on a single dtype and device, resolved once for the whole composite:
the input parameters (
free_params);the free-parameter defaults of the
Matrixoperands, or all parameter defaults when no operand has a free parameter;the default dtype and device of Torch.
In case 2 the dtype and the device must be equal across all
Matrixoperands, including any nested inside nested operators, or aValueErroris raised.Matrixoperands follow the resolved dtype and device through the parameter tensor they receive, and fixed tensor operands are cast to it.Initialize the operator from positional or keyword operands.
- Parameters:
*args – Operands as positional arguments, each a
Matrixortorch.Tensor. A single dict argument is also accepted and treated as a named operand mapping.**kwargs – Operands as keyword arguments, mapping operand names to
Matrixortorch.Tensorinstances. Operand names must be non-empty and must not contain"/".
- Raises:
Example
import torch from torch_openreml.covariance import Sum, ScalarMatrix x = Sum(ScalarMatrix(2), ScalarMatrix(2)) x
Sum( operands={ 'op_0': ScalarMatrix(shape=(2, 2), param_specs={'sigma^2': {'fixed': False, 'default': tensor([0.]), 'trans': TransformExpPow2()}}), 'op_1': ScalarMatrix(shape=(2, 2), param_specs={'sigma^2': {'fixed': False, 'default': tensor([0.]), 'trans': TransformExpPow2()}}) } )x = Sum(A = ScalarMatrix(2), B = ScalarMatrix(2)) x
Sum( operands={ 'A': ScalarMatrix(shape=(2, 2), param_specs={'sigma^2': {'fixed': False, 'default': tensor([0.]), 'trans': TransformExpPow2()}}), 'B': ScalarMatrix(shape=(2, 2), param_specs={'sigma^2': {'fixed': False, 'default': tensor([0.]), 'trans': TransformExpPow2()}}) } )x.param_names
['A/sigma^2', 'B/sigma^2']
x(torch.zeros(2))
tensor([[2., 0.], [0., 2.]])x({"A/sigma^2": torch.zeros(1), "B/sigma^2": torch.zeros(1)})
tensor([[2., 0.], [0., 2.]])Methods
__call__([free_params])Construct the matrix from a flat parameter tensor.
auto_grad([free_params])Compute the Jacobian of
build()with respect to free parameters using automatic differentiation.build_operands([free_params])Evaluate each operand at the current free parameters.
build_params([free_params, include_fixed, ...])Construct the full parameter tensor by delegating to each operand.
Disable intermediate caching on this operator and its operands.
Enable intermediate caching on this operator and its operands.
get_default_dtype_device()Get the dtype and the device of the parameter defaults.
get_intermediates(params)Retrieve cached intermediate computation results if still valid.
grad([free_params])Compute the Jacobian of
__call__()with respect to trainable parameters.grad_tree([free_params])Compute the gradient of this operator and of every nested operand, returning each keyed by its path.
inverse([free_params])Construct the matrix and return its inverse.
manual_grad([free_params])Compute the Jacobian of
__call__()with respect to free parameters using a closed-form analytic expression.operands_grad([free_params])Compute the Jacobian of each operand with respect to its parameters.
operands_inverse([free_params])Compute the inverse of each operand at the current free parameters.
Clear the intermediate caches of this operator and its operands.
resolve_dim(n)Resolve a matrix dimension from an integer or a vector of levels.
set_intermediates(params, intermediates)Cache intermediate computation results keyed by the parameter values.
set_param_specs(key, *[, fixed, default, trans])Update the fields of one or more parameter specifications in place.
trans_grad([free_params])Compute the element-wise derivative of the free parameter transforms.
tree([free_params])Evaluate this operator and every nested operand, returning each result keyed by its path.
Attributes
fixed_param_defaultsFixed parameter defaults.
fixed_param_indexIndex of fixed parameters.
fixed_param_namesFixed parameter names.
fixed_param_transTransforms for fixed parameters.
free_param_defaultsFree parameter defaults.
free_param_indexIndex of free parameters.
free_param_namesFree parameter names.
free_param_transTransforms for free parameters.
num_fixed_paramsTotal number of fixed parameters.
num_free_paramsTotal number of free parameters.
num_paramsTotal number of parameters.
Mapping from operand names to operand matrices or tensors.
param_defaultsParameter defaults.
param_namesParameter names.
Parameter specifications, returned as stored rather than copied.
param_transParameter transforms.
Key-value pairs used to build the string representation.
shapeOutput matrix shape.
grad_modeGradient computation mode.
jacobian_methodJacobian method used by
auto_grad(), one of"jacrev","jacfwd", or"jacobian".jacobian_chunk_sizeNumber of outputs held per batch when
auto_grad()differentiates with"jacrev", orNoneto compute the Jacobian in a single batch.cacheWhether intermediate computation results are cached, toggled by
enable_cache()anddisable_cache().- build_params(free_params=None, include_fixed=True, trans=True, out_format='tensor')[source]¶
Construct the full parameter tensor by delegating to each operand.
Splits
free_paramsinto per-operand slices according to each operand’snum_free_params, callsbuild_params()on eachMatrixoperand, and concatenates the results. Fixed tensor operands are skipped.- Parameters:
free_params (torch.Tensor or dict) – Flat 1D tensor of free parameters or a dictionary mapping parameter names to tensors. If omitted, default values are used. Default:
None.include_fixed (bool, optional) – Whether to include fixed parameters in the output. Passed through to each operand’s
build_params(). Default:True.trans (bool, optional) – Whether to apply parameter transforms to the output. Passed through to each operand’s
build_params(). Default:True.out_format (str, optional) – Output format. One of
"tensor"or"dict". Default:"tensor".
- Returns:
Concatenated parameter tensor of length
num_params(ornum_free_paramswheninclude_fixed=False), or a dictionary mapping namespaced parameter names to value tensors.- Return type:
torch.Tensor or dict
- Raises:
TypeError – If
free_paramsis not a Torch tensor.ValueError – If
free_paramsis not a 1D tensor or has the wrong length, or iffree_paramsis a dict with missing or unexpected keys.ValueError – If
out_formatis not"tensor"or"dict".
import torch from torch_openreml.covariance import Sum, ScalarMatrix x = Sum(ScalarMatrix(2), ScalarMatrix(2)) free_params = torch.tensor([0.0, 0.5]) x.build_params(free_params)
tensor([1.0000, 2.7183])
x.build_params()
tensor([1., 1.])
x.build_params(free_params, trans=False)
tensor([0.0000, 0.5000])
x.build_params(free_params, out_format="dict")
{'op_0/sigma^2': tensor([1.]), 'op_1/sigma^2': tensor([2.7183])}
- build_operands(free_params=None)[source]¶
Evaluate each operand at the current free parameters.
Splits
free_paramsinto per-operand slices and calls eachMatrixoperand to produce its matrix. Fixed tensor operands are cast to the dtype and the device offree_params.- Parameters:
free_params (torch.Tensor or dict) – Flat 1D joint parameter tensor or parameter dictionary of length
num_free_params. If omitted, default values are used. Default:None.- Returns:
Evaluated operand matrices in the same order as
operands.- Return type:
list of torch.Tensor
Example
import torch from torch_openreml.covariance import Sum, ScalarMatrix x = Sum(ScalarMatrix(2), ScalarMatrix(2)) v_groups = x.build_operands(torch.tensor([1.0, 2.0])) print(v_groups[0]) print(v_groups[1])
tensor([[7.3891, 0.0000], [0.0000, 7.3891]]) tensor([[54.5982, 0.0000], [ 0.0000, 54.5982]])
- tree(free_params=None)[source]¶
Evaluate this operator and every nested operand, returning each result keyed by its path.
Descends the operand structure, calling
tree()on nestedOperatoroperands. Paths join the operand names leading to a node with"/", and"/"is the root. Both dictionaries returned share one key set:resultsmaps each path to the matrix the node evaluated to;free_params_by_pathmaps each path to the free parameter slice the node received, or toNonefor fixed tensor operands.
The root result is the same matrix
__call__()returns.- Parameters:
free_params (torch.Tensor or dict) – Flat 1D joint parameter tensor or parameter dictionary of length
num_free_params. If omitted, default values are used. Default:None.- Returns:
(results, free_params_by_path), whereresultsmaps paths to evaluated matrices andfree_params_by_pathmaps the same paths to the free parameter slices the corresponding operands received.- Return type:
tuple
- Raises:
TypeError – If
free_paramsis not a Torch tensor.ValueError – If
free_paramsis not a 1D tensor or has the wrong length, or iffree_paramsis a dict with missing or unexpected keys.
Note
Only nested
Operatoroperands are descended into. Every otherMatrixappears as a leaf, includingAdapterwith its adaptee.Note
Cost: a node’s own result comes from its
__call__()while its operands are evaluated separately, so every node below the root is entered twice — once while its parent composes its result, once by the descent. The root is entered once. An operator that caches intermediates serves the second entry from its cache and re-evaluates nothing below it; one that does not cache propagates the re-evaluation down. A preceding__call__()therefore lowers the leaf count under caching operators and changes no value.Example
import torch from torch_openreml.covariance import BlockDiagonal, DiagonalMatrix, ScalarMatrix, Sum op = Sum(inner=BlockDiagonal(DiagonalMatrix(2), ScalarMatrix(2)), extra=ScalarMatrix(4)) results, free_params_by_path = op.tree(torch.tensor([0.0, 0.5, 1.0, 0.5]))
results{'/': tensor([[ 3.7183, 0.0000, 0.0000, 0.0000], [ 0.0000, 5.4366, 0.0000, 0.0000], [ 0.0000, 0.0000, 10.1073, 0.0000], [ 0.0000, 0.0000, 0.0000, 10.1073]]), 'inner': tensor([[1.0000, 0.0000, 0.0000, 0.0000], [0.0000, 2.7183, 0.0000, 0.0000], [0.0000, 0.0000, 7.3891, 0.0000], [0.0000, 0.0000, 0.0000, 7.3891]]), 'inner/op_0': tensor([[1.0000, 0.0000], [0.0000, 2.7183]]), 'inner/op_1': tensor([[7.3891, 0.0000], [0.0000, 7.3891]]), 'extra': tensor([[2.7183, 0.0000, 0.0000, 0.0000], [0.0000, 2.7183, 0.0000, 0.0000], [0.0000, 0.0000, 2.7183, 0.0000], [0.0000, 0.0000, 0.0000, 2.7183]])}results["inner/op_0"]
tensor([[1.0000, 0.0000], [0.0000, 2.7183]])free_params_by_path["inner"]
tensor([0.0000, 0.5000, 1.0000])
- grad_tree(free_params=None)[source]¶
Compute the gradient of this operator and of every nested operand, returning each keyed by its path.
Descends the operand structure, calling
grad_tree()on nestedOperatoroperands. Paths join the operand names leading to a node with"/", and"/"is the root — the same keystree()produces, in the same order. Both dictionaries returned share one key set:gradsmaps each path to the(grad, grad_names)pairgrad()returns for that node, or to(None, [])when the node has no free parameters;free_params_by_pathmaps each path to the free parameter slice the node received, or toNonefor fixed tensor operands.
Each node’s
gradhas shape(num_free_params, *shape)for that node’s own free parameters and its own matrix shape, so a nested node’s Jacobian is not embedded in its parent’s shape. The root entry is the same pairgrad()returns for the whole composite.grad_namesare namespaced from the node that produced them, asgrad()returns them: at the root they are the composite’s full names, and below it joining the path to a name with"/"gives the name the root exposes infree_param_names.- Parameters:
free_params (torch.Tensor or dict) – Flat 1D joint parameter tensor or parameter dictionary of length
num_free_params. If omitted, default values are used. Default:None.- Returns:
(grads, free_params_by_path), wheregradsmaps paths to(grad, grad_names)pairs andfree_params_by_pathmaps the same paths to the free parameter slices the corresponding operands received.- Return type:
tuple
- Raises:
TypeError – If
free_paramsis not a Torch tensor.ValueError – If
free_paramsis not a 1D tensor or has the wrong length, or iffree_paramsis a dict with missing or unexpected keys.
Note
Only nested
Operatoroperands are descended into. Every otherMatrixappears as a leaf, includingAdapterwith its adaptee.Note
Cost: every Jacobian is computed independently, so a node at depth
dis evaluatedd + 1times — once for the root’s Jacobian and once for each intermediate ancestor’s, plus once for its own entry. No Jacobian is cached, so a precedinggrad()changes nothing. Viewing a deep composite in full is correspondingly expensive.Note
A node’s Jacobian is in that node’s own shape, so the tree does not show how a child’s Jacobian is placed into its parent’s — how
BlockDiagonalpads it into a block, for instance. Only the root entry carries the composite’s full shape.Example
import torch from torch_openreml.covariance import BlockDiagonal, DiagonalMatrix, ScalarMatrix, Sum op = Sum(inner=BlockDiagonal(DiagonalMatrix(2), ScalarMatrix(2)), extra=ScalarMatrix(4)) grads, free_params_by_path = op.grad_tree(torch.tensor([0.0, 0.5, 1.0, 0.5]))
grads["inner/op_0"]
(tensor([[[2.0000, 0.0000], [0.0000, 0.0000]], [[0.0000, 0.0000], [0.0000, 5.4366]]]), ['sigma^2_0', 'sigma^2_1'])grads["inner"][1]
['op_0/sigma^2_0', 'op_0/sigma^2_1', 'op_1/sigma^2']
- operands_grad(free_params=None)[source]¶
Compute the Jacobian of each operand with respect to its parameters.
Splits
free_paramsinto per-operand slices, callsgrad()on eachMatrixoperand, and prefixes the returned names with the operand name. Fixed tensor operands contributeNoneand an empty name list.- Parameters:
params (torch.Tensor or dict) – Flat 1D joint parameter tensor or parameter dictionary of length
num_params. If omitted, default values are used. Default:None.- Returns:
(grad_groups, grad_name_groups), wheregrad_groupsis a list of per-operand Jacobian tensors orNonefor fixed operands, andgrad_name_groupsis a list of corresponding namespaced parameter name lists.- Return type:
tuple
Example
import torch from torch_openreml.covariance import Sum, ScalarMatrix x = Sum(ScalarMatrix(2), ScalarMatrix(2)) grad_groups, grad_name_groups = x.operands_grad(torch.tensor([1.0, 2.0])) print(grad_groups[0]) print(grad_groups[1]) print(grad_name_groups[0]) print(grad_name_groups[1])
tensor([[[14.7781, 0.0000], [ 0.0000, 14.7781]]]) tensor([[[109.1963, 0.0000], [ 0.0000, 109.1963]]]) ['op_0/sigma^2'] ['op_1/sigma^2']
- operands_inverse(free_params=None)[source]¶
Compute the inverse of each operand at the current free parameters.
Splits
free_paramsinto per-operand slices, callsinverse()on eachMatrixoperand, and casts and inverts each fixed tensor operand. AMatrixoperand is never built here, so an analytic inverse — or a nested operator’s own structured inverse — is used instead of inverting the operand densely.- Parameters:
free_params (torch.Tensor or dict) – Flat 1D parameter tensor or parameter dictionary. If omitted, default values are used. Default:
None.- Returns:
Each operand’s inverse, in the order of
operands.- Return type:
list of torch.Tensor
- Raises:
TypeError – If
free_paramsis not a Torch tensor.ValueError – If
free_paramsis not a 1D tensor or has the wrong length, or iffree_paramsis a dict with missing or unexpected keys.
Example
import torch from torch_openreml.covariance import ScalarMatrix, Sum x = Sum(ScalarMatrix(2), ScalarMatrix(2)) inverses = x.operands_inverse(torch.tensor([1.0, 2.0])) print(inverses[0]) print(inverses[1])
tensor([[0.1353, 0.0000], [0.0000, 0.1353]]) tensor([[0.0183, 0.0000], [0.0000, 0.0183]])
- reset_intermediates()[source]¶
Clear the intermediate caches of this operator and its operands.
Extends
reset_intermediates(), which clears this operator’s own cache, by recursively clearing the cache of everyMatrixoperand. Nested operators continue the descent through this same override, so resetting a node resets everything below it.
- enable_cache()[source]¶
Enable intermediate caching on this operator and its operands.
Extends
enable_cache(), which enables caching on this operator, by recursively enabling it on everyMatrixoperand. Nested operators continue the descent through this same override, so enabling a node enables everything below it.
- disable_cache()[source]¶
Disable intermediate caching on this operator and its operands.
Extends
disable_cache(), which disables caching on this operator and clears its cache, by recursively disabling caching on everyMatrixoperand and clearing their caches. Nested operators continue the descent through this same override, so disabling a node disables everything below it.
- property operands¶
Mapping from operand names to operand matrices or tensors.
- Type:
dict
- property param_specs¶
Parameter specifications, returned as stored rather than copied.
A specification edited in place (for example setting
"fixed"toTrue) therefore takes effect on the next call.- Type:
dict
- property repr_dict¶
Key-value pairs used to build the string representation.
- Type:
dict