omnibias.torch.architectures.joint_operator
PyTorch activation derivatives, trainable operator layers, network jets, and direct differential-operator contractions.
import omnibias.torch.architectures.joint_operatorModule contract & mathematical conventions
Joint operator-predictor learning for tabular scientific regression.
The model is a first practical step toward the "Omnibias as scientific AutoML/foundation tool" direction: build a named bank of differentiable operators, learn sparse gates over that bank, and train the predictor head in the same optimization loop.
Shared formulas do not imply universal floating-point identity. Verify dtype, shape, derivative-order support, and the stated numerical assumptions for the path you use.
FittedJointOperatorRegressor
omnibias.torch.architectures.FittedJointOperatorRegressorSource ↗class FittedJointOperatorRegressorDataclass constructor fields; inherited fields, if any, are declared by the base class. A field(...) expression describes a default factory or field options, not a literal argument default.
A fitted joint operator model plus normalization state.
Parameters
| Name | Type & default | Contract |
|---|---|---|
modeldataclass field | JointOperatorRegressorRequired | See the operation contract and implementation below. |
x_meandataclass field | NDArray[np.float32]Required | See the operation contract and implementation below. |
x_scaledataclass field | NDArray[np.float32]Required | See the operation contract and implementation below. |
y_meandataclass field | floatRequired | See the operation contract and implementation below. |
y_scaledataclass field | floatRequired | See the operation contract and implementation below. |
historydataclass field | dict[str, list[float]]Required | See the operation contract and implementation below. |
Executed regression · joint operator fit accepts sample weights
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_accepts_sample_weights() -> None:
x, y = _synthetic(n=500)
weights = np.ones(350, dtype=np.float32)
weights[y[:350] < np.median(y[:350])] = 2.0
fitted = fit_joint_operator_regressor(
x[:350],
y[:350],
x[350:],
y[350:],
seed=1,
epochs=80,
patience=30,
train_sample_weight=weights,
val_sample_weight=np.ones(150, dtype=np.float32),
model_kwargs={"ombu_channels": 0, "stochastic_gates": False},
)
pred = fitted.predict(x[350:])
assert np.isfinite(pred).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_fit_accepts_sample_weights" -qRegression example · joint operator fit accepts asymmetric loss
This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_accepts_asymmetric_loss() -> None:
x, y = _synthetic(n=420)
fitted = fit_joint_operator_regressor(
x[:300],
y[:300],
x[300:],
y[300:],
seed=2,
epochs=60,
patience=25,
asymmetric_weight=1e-3,
model_kwargs={"ombu_channels": 0, "stochastic_gates": False},
)
assert "val_asymmetric" in fitted.history
assert np.isfinite(fitted.history["val_asymmetric"]).all()python -m pytest packages/omnibias-torch/tests/test_joint_operator.py -k test_joint_operator_fit_accepts_asymmetric_loss -qFields & methods
modelfield
model: JointOperatorRegressorDeclared JointOperatorRegressor field on FittedJointOperatorRegressor. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
Regression example · joint operator fit is robust to float64 default dtype
This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_is_robust_to_float64_default_dtype() -> None:
"""A process-wide ``float64`` default must not desync the float32 model
from its float32 inputs.
Regression for the ``addmv ... Float, Double, Float`` crash in the ridge
polish (and the matching nn.Linear mismatch on the OMBU bank path) that
triggered when a user ran under ``torch.set_default_dtype(torch.float64)``.
The autouse conftest fixture restores the default after this test.
"""
torch.set_default_dtype(torch.float64)
x, y = _synthetic(n=240)
fitted = fit_joint_operator_regressor(
x[:160],
y[:160],
x[160:],
y[160:],
seed=0,
epochs=40,
patience=20,
model_kwargs={"ombu_channels": 2, "stochastic_gates": False},
)
assert fitted.model.readout.weight.dtype == torch.float32
assert fitted.model.gate_logits.dtype == torch.float32
pred = fitted.predict(x[160:])
assert np.isfinite(pred).all()python -m pytest packages/omnibias-torch/tests/test_joint_operator.py -k test_joint_operator_fit_is_robust_to_float64_default_dtype -qx_meanfield
x_mean: NDArray[np.float32]Declared NDArray[np.float32] field on FittedJointOperatorRegressor. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗x_scalefield
x_scale: NDArray[np.float32]Declared NDArray[np.float32] field on FittedJointOperatorRegressor. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗y_meanfield
y_mean: floatDeclared float field on FittedJointOperatorRegressor. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗y_scalefield
y_scale: floatDeclared float field on FittedJointOperatorRegressor. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗historyfield
history: dict[str, list[float]]Declared dict[str, list[float]] field on FittedJointOperatorRegressor. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
Regression example · joint operator fit accepts asymmetric loss
This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_accepts_asymmetric_loss() -> None:
x, y = _synthetic(n=420)
fitted = fit_joint_operator_regressor(
x[:300],
y[:300],
x[300:],
y[300:],
seed=2,
epochs=60,
patience=25,
asymmetric_weight=1e-3,
model_kwargs={"ombu_channels": 0, "stochastic_gates": False},
)
assert "val_asymmetric" in fitted.history
assert np.isfinite(fitted.history["val_asymmetric"]).all()python -m pytest packages/omnibias-torch/tests/test_joint_operator.py -k test_joint_operator_fit_accepts_asymmetric_loss -qpredictmethod
predict(self, x: NDArray[Any]) -> NDArray[np.float32]See the class contract above and the exact method implementation below.
Parameters
| Name | Type & default | Contract |
|---|---|---|
xpositional-or-keyword | NDArray[Any]Required | See the operation contract and implementation below. |
Returns: NDArray[np.float32]
Executed regression · joint operator fit accepts sample weights
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_accepts_sample_weights() -> None:
x, y = _synthetic(n=500)
weights = np.ones(350, dtype=np.float32)
weights[y[:350] < np.median(y[:350])] = 2.0
fitted = fit_joint_operator_regressor(
x[:350],
y[:350],
x[350:],
y[350:],
seed=1,
epochs=80,
patience=30,
train_sample_weight=weights,
val_sample_weight=np.ones(150, dtype=np.float32),
model_kwargs={"ombu_channels": 0, "stochastic_gates": False},
)
pred = fitted.predict(x[350:])
assert np.isfinite(pred).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_fit_accepts_sample_weights" -qMethod implementation
def predict(self, x: NDArray[Any]) -> NDArray[np.float32]:
self.model.eval()
# Place the input on the model's device so predict works after the
# model has been moved to a GPU (CPU-safe no-op otherwise). The
# ``torch.empty(0)`` default keeps a parameterless model on CPU.
device = next(self.model.parameters(), torch.empty(0)).device
xs = (np.asarray(x, dtype=np.float32) - self.x_mean) / self.x_scale
with torch.no_grad():
xt = torch.as_tensor(xs, dtype=torch.float32, device=device)
pred_z: NDArray[np.float32] = self.model(xt).cpu().numpy()
return pred_z * self.y_scale + self.y_meanselected_operatorsmethod
selected_operators(self, *, threshold: float=0.2, top_k: int | None=None) -> list[dict[str, Any]]See the class contract above and the exact method implementation below.
Parameters
| Name | Type & default | Contract |
|---|---|---|
thresholdkeyword-only | floatDefault: 0.2 | See the operation contract and implementation below. |
top_kkeyword-only | int | NoneDefault: None | See the operation contract and implementation below. |
Returns: list[dict[str, Any]]
Executed regression · joint operator fit recovers synthetic law primitives
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_recovers_synthetic_law_primitives() -> None:
x, y = _synthetic()
x_train, y_train = x[:500], y[:500]
x_val, y_val = x[500:], y[500:]
fitted = fit_joint_operator_regressor(
x_train,
y_train,
x_val,
y_val,
seed=0,
epochs=260,
patience=80,
sparsity_weight=2e-3,
model_kwargs={
"ombu_channels": 0,
"stochastic_gates": False,
"initial_gate_logit": 0.0,
},
)
pred = fitted.predict(x_val)
rmse = float(np.sqrt(np.mean((pred - y_val) ** 2)))
selected_names = {row["name"] for row in fitted.selected_operators(top_k=12)}
assert rmse < 0.25
assert "x1^2" in selected_names
assert "x2*x3" in selected_names
assert "sin(x4)" in selected_namespython -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_fit_recovers_synthetic_law_primitives" -qMethod implementation
def selected_operators(self, *, threshold: float = 0.2, top_k: int | None = None) -> list[dict[str, Any]]:
return self.model.selected_operators(threshold=threshold, top_k=top_k)Read the implementation
class FittedJointOperatorRegressor:
"""A fitted joint operator model plus normalization state."""
model: JointOperatorRegressor
x_mean: NDArray[np.float32]
x_scale: NDArray[np.float32]
y_mean: float
y_scale: float
history: dict[str, list[float]]
def predict(self, x: NDArray[Any]) -> NDArray[np.float32]:
self.model.eval()
# Place the input on the model's device so predict works after the
# model has been moved to a GPU (CPU-safe no-op otherwise). The
# ``torch.empty(0)`` default keeps a parameterless model on CPU.
device = next(self.model.parameters(), torch.empty(0)).device
xs = (np.asarray(x, dtype=np.float32) - self.x_mean) / self.x_scale
with torch.no_grad():
xt = torch.as_tensor(xs, dtype=torch.float32, device=device)
pred_z: NDArray[np.float32] = self.model(xt).cpu().numpy()
return pred_z * self.y_scale + self.y_mean
def selected_operators(self, *, threshold: float = 0.2, top_k: int | None = None) -> list[dict[str, Any]]:
return self.model.selected_operators(threshold=threshold, top_k=top_k)Other public import paths
omnibias.torch.architectures.FittedJointOperatorRegressoromnibias.torch.architectures.joint_operator.FittedJointOperatorRegressor
JointOperatorRegressor
omnibias.torch.architectures.JointOperatorRegressorSource ↗class JointOperatorRegressor(nn.Module)Differentiable operator bank with trainable selection gates.
The model intentionally starts simple: named deterministic operators provide interpretability, optional trainable OMBU derivative channels add latent operator capacity, and a sparse linear head keeps selected operators exportable.
Parameters
| Name | Type & default | Contract |
|---|---|---|
in_featurespositional-or-keyword | intRequired | See the operation contract and implementation below. |
include_rawkeyword-only | boolDefault: True | See the operation contract and implementation below. |
include_unarykeyword-only | boolDefault: True | See the operation contract and implementation below. |
include_pairwisekeyword-only | boolDefault: True | See the operation contract and implementation below. |
include_nestedkeyword-only | boolDefault: True | See the operation contract and implementation below. |
max_pairwisekeyword-only | intDefault: 128 | See the operation contract and implementation below. |
ombu_channelskeyword-only | intDefault: 0 | See the operation contract and implementation below. |
ombu_basekeyword-only | str | ActivationSpec[Tensor]Default: 'tanh' | See the operation contract and implementation below. |
gate_temperaturekeyword-only | floatDefault: 1.0 | See the operation contract and implementation below. |
stochastic_gateskeyword-only | boolDefault: True | See the operation contract and implementation below. |
initial_gate_logitkeyword-only | floatDefault: -0.25 | See the operation contract and implementation below. |
Executed regression · joint operator complexity loss is differentiable
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_complexity_loss_is_differentiable" -qRegression example · joint operator bank contains scientific primitives
This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_bank_contains_scientific_primitives() -> None:
model = JointOperatorRegressor(4, ombu_channels=2, stochastic_gates=False)
names = [item.name for item in model.operator_metadata]
assert "x1^2" in names
assert "x2*x3" in names
assert "sin(x4)" in names
assert "tanh(x1^2)" in names
assert "ombu_grad_0" in names
bank = model.operator_bank(torch.randn(5, 4))
assert bank.shape == (5, model.n_operators)python -m pytest packages/omnibias-torch/tests/test_joint_operator.py -k test_joint_operator_bank_contains_scientific_primitives -qFields & methods
__init__method
__init__(self, in_features: int, *, include_raw: bool=True, include_unary: bool=True, include_pairwise: bool=True, include_nested: bool=True, max_pairwise: int=128, ombu_channels: int=0, ombu_base: str | ActivationSpec[Tensor]='tanh', gate_temperature: float=1.0, stochastic_gates: bool=True, initial_gate_logit: float=-0.25) -> NoneSee the class contract above and the exact method implementation below.
Parameters
| Name | Type & default | Contract |
|---|---|---|
in_featurespositional-or-keyword | intRequired | See the operation contract and implementation below. |
include_rawkeyword-only | boolDefault: True | See the operation contract and implementation below. |
include_unarykeyword-only | boolDefault: True | See the operation contract and implementation below. |
include_pairwisekeyword-only | boolDefault: True | See the operation contract and implementation below. |
include_nestedkeyword-only | boolDefault: True | See the operation contract and implementation below. |
max_pairwisekeyword-only | intDefault: 128 | See the operation contract and implementation below. |
ombu_channelskeyword-only | intDefault: 0 | See the operation contract and implementation below. |
ombu_basekeyword-only | str | ActivationSpec[Tensor]Default: 'tanh' | See the operation contract and implementation below. |
gate_temperaturekeyword-only | floatDefault: 1.0 | See the operation contract and implementation below. |
stochastic_gateskeyword-only | boolDefault: True | See the operation contract and implementation below. |
initial_gate_logitkeyword-only | floatDefault: -0.25 | See the operation contract and implementation below. |
Returns: None
Validation & failure cases
- When
in_features < 1, raisesValueError(f'in_features must be >= 1, got {in_features}'). - When
max_pairwise < 0, raisesValueError(f'max_pairwise must be >= 0, got {max_pairwise}'). - When
ombu_channels < 0, raisesValueError(f'ombu_channels must be >= 0, got {ombu_channels}'). - When
gate_temperature <= 0, raisesValueError(f'gate_temperature must be > 0, got {gate_temperature}'). - When
not self.operator_metadata, raisesValueError('operator bank is empty'). - When
self.ombu_spec.fastpath is None, raisesTypeError('ombu_base must provide a derivative fastpath for joint derivative operators').
Executed regression · joint operator complexity loss is differentiable
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_complexity_loss_is_differentiable" -qMethod implementation
def __init__(
self,
in_features: int,
*,
include_raw: bool = True,
include_unary: bool = True,
include_pairwise: bool = True,
include_nested: bool = True,
max_pairwise: int = 128,
ombu_channels: int = 0,
ombu_base: str | ActivationSpec[Tensor] = "tanh",
gate_temperature: float = 1.0,
stochastic_gates: bool = True,
initial_gate_logit: float = -0.25,
) -> None:
super().__init__()
if in_features < 1:
raise ValueError(f"in_features must be >= 1, got {in_features}")
if max_pairwise < 0:
raise ValueError(f"max_pairwise must be >= 0, got {max_pairwise}")
if ombu_channels < 0:
raise ValueError(f"ombu_channels must be >= 0, got {ombu_channels}")
if gate_temperature <= 0:
raise ValueError(f"gate_temperature must be > 0, got {gate_temperature}")
self.in_features = in_features
self.include_raw = include_raw
self.include_unary = include_unary
self.include_pairwise = include_pairwise
self.include_nested = include_nested
self.max_pairwise = max_pairwise
self.ombu_channels = ombu_channels
self.gate_temperature = gate_temperature
self.stochastic_gates = stochastic_gates
self.operator_metadata = _build_operator_metadata(
in_features,
include_raw=include_raw,
include_unary=include_unary,
include_pairwise=include_pairwise,
include_nested=include_nested,
max_pairwise=max_pairwise,
ombu_channels=ombu_channels,
)
if not self.operator_metadata:
raise ValueError("operator bank is empty")
self.ombu_projection: nn.Linear | None
self.ombu_spec: ActivationSpec[Tensor] | None
if ombu_channels:
self.ombu_projection = nn.Linear(in_features, ombu_channels)
self.ombu_spec = ombu_base if isinstance(ombu_base, ActivationSpec) else get_activation(ombu_base)
if self.ombu_spec.fastpath is None:
raise TypeError("ombu_base must provide a derivative fastpath for joint derivative operators")
try:
self.ombu_spec.fastpath(torch.zeros(1), 2)
except NotImplementedError as exc:
raise TypeError("ombu_base must support derivative orders 1 and 2") from exc
else:
self.ombu_projection = None
self.ombu_spec = None
n_ops = len(self.operator_metadata)
self.gate_logits = nn.Parameter(torch.full((n_ops,), float(initial_gate_logit)))
self.readout = nn.Linear(n_ops, 1)
complexity = torch.tensor([item.complexity for item in self.operator_metadata], dtype=torch.float32)
self.operator_complexity: Tensor
self.selection_readout_weight: Tensor
self.register_buffer("operator_complexity", complexity)
self.register_buffer("selection_readout_weight", torch.zeros(n_ops), persistent=False)n_operatorsproperty
n_operators(self) -> intSee the class contract above and the exact method implementation below.
Returns: int
Executed regression · joint operator bank contains scientific primitives
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_bank_contains_scientific_primitives() -> None:
model = JointOperatorRegressor(4, ombu_channels=2, stochastic_gates=False)
names = [item.name for item in model.operator_metadata]
assert "x1^2" in names
assert "x2*x3" in names
assert "sin(x4)" in names
assert "tanh(x1^2)" in names
assert "ombu_grad_0" in names
bank = model.operator_bank(torch.randn(5, 4))
assert bank.shape == (5, model.n_operators)python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_bank_contains_scientific_primitives" -qMethod implementation
def n_operators(self) -> int:
return len(self.operator_metadata)gate_probabilitiesmethod
gate_probabilities(self) -> TensorSee the class contract above and the exact method implementation below.
Returns: Tensor
Executed regression · joint operator complexity loss is differentiable
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_complexity_loss_is_differentiable" -qMethod implementation
def gate_probabilities(self) -> Tensor:
return torch.sigmoid(self.gate_logits / self.gate_temperature)gatesmethod
gates(self) -> TensorSee the class contract above and the exact method implementation below.
Returns: Tensor
Executed regression · joint operator complexity loss is differentiable
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_complexity_loss_is_differentiable" -qMethod implementation
def gates(self) -> Tensor:
if self.training and self.stochastic_gates:
u = torch.rand_like(self.gate_logits).clamp_(1e-6, 1.0 - 1e-6)
logistic_noise = torch.log(u) - torch.log1p(-u)
return torch.sigmoid((self.gate_logits + logistic_noise) / self.gate_temperature)
return self.gate_probabilities()operator_bankmethod
operator_bank(self, x: Tensor) -> TensorSee the class contract above and the exact method implementation below.
Parameters
| Name | Type & default | Contract |
|---|---|---|
xpositional-or-keyword | TensorRequired | See the operation contract and implementation below. |
Returns: Tensor
Validation & failure cases
- When
x.ndim != 2 or x.shape[1] != self.in_features, raisesValueError(f'x must have shape (batch, {self.in_features}), got {tuple(x.shape)}').
Executed regression · joint operator complexity loss is differentiable
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_complexity_loss_is_differentiable" -qMethod implementation
def operator_bank(self, x: Tensor) -> Tensor:
if x.ndim != 2 or x.shape[1] != self.in_features:
raise ValueError(f"x must have shape (batch, {self.in_features}), got {tuple(x.shape)}")
cols: list[Tensor] = []
if self.include_raw:
cols.extend([x[:, j] for j in range(self.in_features)])
if self.include_unary:
for j in range(self.in_features):
col = x[:, j]
cols.extend(
[
col.square(),
torch.tanh(col),
torch.sin(col),
torch.cos(col),
torch.log1p(col.abs()),
1.0 / (1.0 + col.abs()),
torch.exp(col.clamp(-3.0, 3.0)),
]
)
if self.include_pairwise and self.max_pairwise:
for idx, (j, k) in enumerate(combinations(range(self.in_features), 2)):
if idx >= self.max_pairwise:
break
cols.append(x[:, j] * x[:, k])
if self.include_nested:
for j in range(self.in_features):
col = x[:, j]
square = col.square()
cols.extend([torch.tanh(square), torch.sin(square), torch.log1p(square)])
if self.ombu_projection is not None and self.ombu_spec is not None:
z = self.ombu_projection(x)
fp = self.ombu_spec.fastpath
assert fp is not None
cols.extend([self.ombu_spec.forward(z[:, h]) for h in range(self.ombu_channels)])
cols.extend([fp(z[:, h], 1) for h in range(self.ombu_channels)])
cols.extend([fp(z[:, h], 2) for h in range(self.ombu_channels)])
return torch.stack(cols, dim=1)forwardmethod
forward(self, x: Tensor) -> TensorSee the class contract above and the exact method implementation below.
Parameters
| Name | Type & default | Contract |
|---|---|---|
xpositional-or-keyword | TensorRequired | See the operation contract and implementation below. |
Returns: Tensor
Executed regression · joint operator complexity loss is differentiable
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_complexity_loss_is_differentiable" -qMethod implementation
def forward(self, x: Tensor) -> Tensor:
bank = self.operator_bank(x)
gated = bank * self.gates()
out: Tensor = self.readout(gated).squeeze(-1)
return outcomplexity_lossmethod
complexity_loss(self) -> TensorSee the class contract above and the exact method implementation below.
Returns: Tensor
Executed regression · joint operator complexity loss is differentiable
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_complexity_loss_is_differentiable" -qMethod implementation
def complexity_loss(self) -> Tensor:
probs = self.gate_probabilities()
return (probs * self.operator_complexity).mean()active_operator_countmethod
active_operator_count(self, threshold: float=0.2) -> intSee the class contract above and the exact method implementation below.
Parameters
| Name | Type & default | Contract |
|---|---|---|
thresholdpositional-or-keyword | floatDefault: 0.2 | See the operation contract and implementation below. |
Returns: int
Method implementation
def active_operator_count(self, threshold: float = 0.2) -> int:
return int((self.gate_probabilities().detach() >= threshold).sum().item())selected_operatorsmethod
selected_operators(self, *, threshold: float=0.2, top_k: int | None=None) -> list[dict[str, Any]]See the class contract above and the exact method implementation below.
Parameters
| Name | Type & default | Contract |
|---|---|---|
thresholdkeyword-only | floatDefault: 0.2 | See the operation contract and implementation below. |
top_kkeyword-only | int | NoneDefault: None | See the operation contract and implementation below. |
Returns: list[dict[str, Any]]
Executed regression · joint operator fit recovers synthetic law primitives
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_recovers_synthetic_law_primitives() -> None:
x, y = _synthetic()
x_train, y_train = x[:500], y[:500]
x_val, y_val = x[500:], y[500:]
fitted = fit_joint_operator_regressor(
x_train,
y_train,
x_val,
y_val,
seed=0,
epochs=260,
patience=80,
sparsity_weight=2e-3,
model_kwargs={
"ombu_channels": 0,
"stochastic_gates": False,
"initial_gate_logit": 0.0,
},
)
pred = fitted.predict(x_val)
rmse = float(np.sqrt(np.mean((pred - y_val) ** 2)))
selected_names = {row["name"] for row in fitted.selected_operators(top_k=12)}
assert rmse < 0.25
assert "x1^2" in selected_names
assert "x2*x3" in selected_names
assert "sin(x4)" in selected_namespython -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_fit_recovers_synthetic_law_primitives" -qMethod implementation
def selected_operators(self, *, threshold: float = 0.2, top_k: int | None = None) -> list[dict[str, Any]]:
with torch.no_grad():
probs = self.gate_probabilities().detach().cpu()
weights = self.readout.weight.detach().squeeze(0).cpu()
selection_weights = self.selection_readout_weight.detach().cpu()
if torch.count_nonzero(selection_weights) == 0:
selection_weights = weights
contribution = (probs * weights.abs()).numpy()
selection_score = (
probs
* selection_weights.abs()
* torch.tensor([item.interpretability for item in self.operator_metadata])
/ torch.sqrt(self.operator_complexity.detach().cpu())
).numpy()
rows = []
for idx, meta in enumerate(self.operator_metadata):
if probs[idx].item() >= threshold:
rows.append(
_selected_payload(
idx,
meta,
probs[idx].item(),
weights[idx].item(),
contribution[idx],
selection_score[idx],
selection_weights[idx].item(),
)
)
if top_k is not None:
ranked = np.argsort(-selection_score)[:top_k]
by_idx = {row["index"]: row for row in rows}
for idx in ranked:
if int(idx) not in by_idx:
meta = self.operator_metadata[int(idx)]
rows.append(
_selected_payload(
int(idx),
meta,
probs[int(idx)].item(),
weights[int(idx)].item(),
contribution[int(idx)],
selection_score[int(idx)],
selection_weights[int(idx)].item(),
)
)
rows = sorted(rows, key=lambda row: row["selection_score"], reverse=True)[:top_k]
else:
rows = sorted(rows, key=lambda row: row["selection_score"], reverse=True)
return rowsin_featuresattribute
in_features: int = in_featuresPublic instance attribute assigned by __init__. The source assignment is in_features = in_features; it describes instance state, not a literal constructor default.
include_rawattribute
include_raw: bool = include_rawPublic instance attribute assigned by __init__. The source assignment is include_raw = include_raw; it describes instance state, not a literal constructor default.
include_unaryattribute
include_unary: bool = include_unaryPublic instance attribute assigned by __init__. The source assignment is include_unary = include_unary; it describes instance state, not a literal constructor default.
include_pairwiseattribute
include_pairwise: bool = include_pairwisePublic instance attribute assigned by __init__. The source assignment is include_pairwise = include_pairwise; it describes instance state, not a literal constructor default.
include_nestedattribute
include_nested: bool = include_nestedPublic instance attribute assigned by __init__. The source assignment is include_nested = include_nested; it describes instance state, not a literal constructor default.
max_pairwiseattribute
max_pairwise: int = max_pairwisePublic instance attribute assigned by __init__. The source assignment is max_pairwise = max_pairwise; it describes instance state, not a literal constructor default.
ombu_channelsattribute
ombu_channels: int = ombu_channelsPublic instance attribute assigned by __init__. The source assignment is ombu_channels = ombu_channels; it describes instance state, not a literal constructor default.
gate_temperatureattribute
gate_temperature: float = gate_temperaturePublic instance attribute assigned by __init__. The source assignment is gate_temperature = gate_temperature; it describes instance state, not a literal constructor default.
stochastic_gatesattribute
stochastic_gates: bool = stochastic_gatesPublic instance attribute assigned by __init__. The source assignment is stochastic_gates = stochastic_gates; it describes instance state, not a literal constructor default.
operator_metadataattribute
operator_metadata = _build_operator_metadata(in_features, include_raw=include_raw, include_unary=include_unary, include_pairwise=include_pairwise, include_nested=include_nested, max_pairwise=max_pairwise, ombu_channels=ombu_channels)Public instance attribute assigned by __init__. The source assignment is operator_metadata = _build_operator_metadata(in_features, include_raw=include_raw, include_unary=include_unary, include_pairwise=include_pairwise, include_nested=include_nested, max_pairwise=max_pairwise, ombu_channels=ombu_channels); it describes instance state, not a literal constructor default.
Regression example · joint operator bank contains scientific primitives
This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_bank_contains_scientific_primitives() -> None:
model = JointOperatorRegressor(4, ombu_channels=2, stochastic_gates=False)
names = [item.name for item in model.operator_metadata]
assert "x1^2" in names
assert "x2*x3" in names
assert "sin(x4)" in names
assert "tanh(x1^2)" in names
assert "ombu_grad_0" in names
bank = model.operator_bank(torch.randn(5, 4))
assert bank.shape == (5, model.n_operators)python -m pytest packages/omnibias-torch/tests/test_joint_operator.py -k test_joint_operator_bank_contains_scientific_primitives -qombu_projectionattribute
ombu_projection: nn.Linear | NonePublic instance attribute assigned by __init__. The source assignment is ombu_projection = null; it describes instance state, not a literal constructor default.
ombu_specattribute
ombu_spec: ActivationSpec[Tensor] | NonePublic instance attribute assigned by __init__. The source assignment is ombu_spec = null; it describes instance state, not a literal constructor default.
gate_logitsattribute
gate_logits = nn.Parameter(torch.full((n_ops,), float(initial_gate_logit)))Public instance attribute assigned by __init__. The source assignment is gate_logits = nn.Parameter(torch.full((n_ops,), float(initial_gate_logit))); it describes instance state, not a literal constructor default.
Regression example · joint operator complexity loss is differentiable
This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_complexity_loss_is_differentiable() -> None:
model = JointOperatorRegressor(3, ombu_channels=1, stochastic_gates=True)
x = torch.randn(16, 3)
y = torch.randn(16)
pred = model(x)
loss = torch.mean((pred - y) ** 2) + 1e-3 * model.complexity_loss()
loss.backward()
assert model.gate_logits.grad is not None
assert torch.isfinite(model.gate_logits.grad).all()python -m pytest packages/omnibias-torch/tests/test_joint_operator.py -k test_joint_operator_complexity_loss_is_differentiable -qreadoutattribute
readout = nn.Linear(n_ops, 1)Public instance attribute assigned by __init__. The source assignment is readout = nn.Linear(n_ops, 1); it describes instance state, not a literal constructor default.
operator_complexityattribute
operator_complexity: TensorPublic instance attribute assigned by __init__. The source assignment is operator_complexity = null; it describes instance state, not a literal constructor default.
selection_readout_weightattribute
selection_readout_weight: TensorPublic instance attribute assigned by __init__. The source assignment is selection_readout_weight = null; it describes instance state, not a literal constructor default.
Read the implementation
class JointOperatorRegressor(nn.Module):
"""Differentiable operator bank with trainable selection gates.
The model intentionally starts simple: named deterministic operators
provide interpretability, optional trainable OMBU derivative channels add
latent operator capacity, and a sparse linear head keeps selected operators
exportable.
"""
def __init__(
self,
in_features: int,
*,
include_raw: bool = True,
include_unary: bool = True,
include_pairwise: bool = True,
include_nested: bool = True,
max_pairwise: int = 128,
ombu_channels: int = 0,
ombu_base: str | ActivationSpec[Tensor] = "tanh",
gate_temperature: float = 1.0,
stochastic_gates: bool = True,
initial_gate_logit: float = -0.25,
) -> None:
super().__init__()
if in_features < 1:
raise ValueError(f"in_features must be >= 1, got {in_features}")
if max_pairwise < 0:
raise ValueError(f"max_pairwise must be >= 0, got {max_pairwise}")
if ombu_channels < 0:
raise ValueError(f"ombu_channels must be >= 0, got {ombu_channels}")
if gate_temperature <= 0:
raise ValueError(f"gate_temperature must be > 0, got {gate_temperature}")
self.in_features = in_features
self.include_raw = include_raw
self.include_unary = include_unary
self.include_pairwise = include_pairwise
self.include_nested = include_nested
self.max_pairwise = max_pairwise
self.ombu_channels = ombu_channels
self.gate_temperature = gate_temperature
self.stochastic_gates = stochastic_gates
self.operator_metadata = _build_operator_metadata(
in_features,
include_raw=include_raw,
include_unary=include_unary,
include_pairwise=include_pairwise,
include_nested=include_nested,
max_pairwise=max_pairwise,
ombu_channels=ombu_channels,
)
if not self.operator_metadata:
raise ValueError("operator bank is empty")
self.ombu_projection: nn.Linear | None
self.ombu_spec: ActivationSpec[Tensor] | None
if ombu_channels:
self.ombu_projection = nn.Linear(in_features, ombu_channels)
self.ombu_spec = ombu_base if isinstance(ombu_base, ActivationSpec) else get_activation(ombu_base)
if self.ombu_spec.fastpath is None:
raise TypeError("ombu_base must provide a derivative fastpath for joint derivative operators")
try:
self.ombu_spec.fastpath(torch.zeros(1), 2)
except NotImplementedError as exc:
raise TypeError("ombu_base must support derivative orders 1 and 2") from exc
else:
self.ombu_projection = None
self.ombu_spec = None
n_ops = len(self.operator_metadata)
self.gate_logits = nn.Parameter(torch.full((n_ops,), float(initial_gate_logit)))
self.readout = nn.Linear(n_ops, 1)
complexity = torch.tensor([item.complexity for item in self.operator_metadata], dtype=torch.float32)
self.operator_complexity: Tensor
self.selection_readout_weight: Tensor
self.register_buffer("operator_complexity", complexity)
self.register_buffer("selection_readout_weight", torch.zeros(n_ops), persistent=False)
@property
def n_operators(self) -> int:
return len(self.operator_metadata)
def gate_probabilities(self) -> Tensor:
return torch.sigmoid(self.gate_logits / self.gate_temperature)
def gates(self) -> Tensor:
if self.training and self.stochastic_gates:
u = torch.rand_like(self.gate_logits).clamp_(1e-6, 1.0 - 1e-6)
logistic_noise = torch.log(u) - torch.log1p(-u)
return torch.sigmoid((self.gate_logits + logistic_noise) / self.gate_temperature)
return self.gate_probabilities()
def operator_bank(self, x: Tensor) -> Tensor:
if x.ndim != 2 or x.shape[1] != self.in_features:
raise ValueError(f"x must have shape (batch, {self.in_features}), got {tuple(x.shape)}")
cols: list[Tensor] = []
if self.include_raw:
cols.extend([x[:, j] for j in range(self.in_features)])
if self.include_unary:
for j in range(self.in_features):
col = x[:, j]
cols.extend(
[
col.square(),
torch.tanh(col),
torch.sin(col),
torch.cos(col),
torch.log1p(col.abs()),
1.0 / (1.0 + col.abs()),
torch.exp(col.clamp(-3.0, 3.0)),
]
)
if self.include_pairwise and self.max_pairwise:
for idx, (j, k) in enumerate(combinations(range(self.in_features), 2)):
if idx >= self.max_pairwise:
break
cols.append(x[:, j] * x[:, k])
if self.include_nested:
for j in range(self.in_features):
col = x[:, j]
square = col.square()
cols.extend([torch.tanh(square), torch.sin(square), torch.log1p(square)])
if self.ombu_projection is not None and self.ombu_spec is not None:
z = self.ombu_projection(x)
fp = self.ombu_spec.fastpath
assert fp is not None
cols.extend([self.ombu_spec.forward(z[:, h]) for h in range(self.ombu_channels)])
cols.extend([fp(z[:, h], 1) for h in range(self.ombu_channels)])
cols.extend([fp(z[:, h], 2) for h in range(self.ombu_channels)])
return torch.stack(cols, dim=1)
def forward(self, x: Tensor) -> Tensor:
bank = self.operator_bank(x)
gated = bank * self.gates()
out: Tensor = self.readout(gated).squeeze(-1)
return out
def complexity_loss(self) -> Tensor:
probs = self.gate_probabilities()
return (probs * self.operator_complexity).mean()
def active_operator_count(self, threshold: float = 0.2) -> int:
return int((self.gate_probabilities().detach() >= threshold).sum().item())
def selected_operators(self, *, threshold: float = 0.2, top_k: int | None = None) -> list[dict[str, Any]]:
with torch.no_grad():
probs = self.gate_probabilities().detach().cpu()
weights = self.readout.weight.detach().squeeze(0).cpu()
selection_weights = self.selection_readout_weight.detach().cpu()
if torch.count_nonzero(selection_weights) == 0:
selection_weights = weights
contribution = (probs * weights.abs()).numpy()
selection_score = (
probs
* selection_weights.abs()
* torch.tensor([item.interpretability for item in self.operator_metadata])
/ torch.sqrt(self.operator_complexity.detach().cpu())
).numpy()
rows = []
for idx, meta in enumerate(self.operator_metadata):
if probs[idx].item() >= threshold:
rows.append(
_selected_payload(
idx,
meta,
probs[idx].item(),
weights[idx].item(),
contribution[idx],
selection_score[idx],
selection_weights[idx].item(),
)
)
if top_k is not None:
ranked = np.argsort(-selection_score)[:top_k]
by_idx = {row["index"]: row for row in rows}
for idx in ranked:
if int(idx) not in by_idx:
meta = self.operator_metadata[int(idx)]
rows.append(
_selected_payload(
int(idx),
meta,
probs[int(idx)].item(),
weights[int(idx)].item(),
contribution[int(idx)],
selection_score[int(idx)],
selection_weights[int(idx)].item(),
)
)
rows = sorted(rows, key=lambda row: row["selection_score"], reverse=True)[:top_k]
else:
rows = sorted(rows, key=lambda row: row["selection_score"], reverse=True)
return rowsOther public import paths
omnibias.torch.architectures.JointOperatorRegressoromnibias.torch.architectures.joint_operator.JointOperatorRegressor
OperatorMetadata
omnibias.torch.architectures.OperatorMetadataSource ↗class OperatorMetadataDataclass constructor fields; inherited fields, if any, are declared by the base class. A field(...) expression describes a default factory or field options, not a literal argument default.
Description of one candidate operator in the joint bank.
Parameters
| Name | Type & default | Contract |
|---|---|---|
namedataclass field | strRequired | See the operation contract and implementation below. |
familydataclass field | strRequired | See the operation contract and implementation below. |
complexitydataclass field | floatRequired | See the operation contract and implementation below. |
inputsdataclass field | tuple[int, ...]Required | See the operation contract and implementation below. |
interpretabilitydataclass field | floatDefault: 1.0 | See the operation contract and implementation below. |
Fields & methods
namefield
name: strDeclared str field on OperatorMetadata. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗familyfield
family: strDeclared str field on OperatorMetadata. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗complexityfield
complexity: floatDeclared float field on OperatorMetadata. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗inputsfield
inputs: tuple[int, ...]Declared tuple[int, ...] field on OperatorMetadata. A value must be provided when constructing the configuration, unless an inherited constructor supplies it.
View source ↗interpretabilityfield
interpretability: float = 1.0Declared float field on OperatorMetadata. Default expression: 1.0.
Read the implementation
class OperatorMetadata:
"""Description of one candidate operator in the joint bank."""
name: str
family: str
complexity: float
inputs: tuple[int, ...]
interpretability: float = 1.0Other public import paths
omnibias.torch.architectures.OperatorMetadataomnibias.torch.architectures.joint_operator.OperatorMetadata
fit_joint_operator_regressor
omnibias.torch.architectures.fit_joint_operator_regressorSource ↗fit_joint_operator_regressor(x_train: NDArray[Any], y_train: NDArray[Any], x_val: NDArray[Any] | None=None, y_val: NDArray[Any] | None=None, *, seed: int=0, epochs: int=400, lr: float=0.03, batch_size: int | None=None, patience: int=60, sparsity_weight: float=0.001, weight_decay: float=1e-05, train_sample_weight: NDArray[Any] | None=None, val_sample_weight: NDArray[Any] | None=None, asymmetric_weight: float=0.0, validation_asymmetric_weight: float | None=None, asymmetric_under_scale: float=13.0, asymmetric_over_scale: float=10.0, standardize_x: bool=False, polish_readout: bool=True, polish_ridge: float=1e-06, validation_selection_metric: Callable[[NDArray[Any], NDArray[Any]], float] | None=None, validation_selection_complexity_weight: float=0.0, model_kwargs: dict[str, Any] | None=None) -> FittedJointOperatorRegressorFit a JointOperatorRegressor with train/validation early stopping.
Parameters
| Name | Type & default | Contract |
|---|---|---|
x_trainpositional-or-keyword | NDArray[Any]Required | See the operation contract and implementation below. |
y_trainpositional-or-keyword | NDArray[Any]Required | See the operation contract and implementation below. |
x_valpositional-or-keyword | NDArray[Any] | NoneDefault: None | See the operation contract and implementation below. |
y_valpositional-or-keyword | NDArray[Any] | NoneDefault: None | See the operation contract and implementation below. |
seedkeyword-only | intDefault: 0 | See the operation contract and implementation below. |
epochskeyword-only | intDefault: 400 | See the operation contract and implementation below. |
lrkeyword-only | floatDefault: 0.03 | See the operation contract and implementation below. |
batch_sizekeyword-only | int | NoneDefault: None | See the operation contract and implementation below. |
patiencekeyword-only | intDefault: 60 | See the operation contract and implementation below. |
sparsity_weightkeyword-only | floatDefault: 0.001 | See the operation contract and implementation below. |
weight_decaykeyword-only | floatDefault: 1e-05 | See the operation contract and implementation below. |
train_sample_weightkeyword-only | NDArray[Any] | NoneDefault: None | See the operation contract and implementation below. |
val_sample_weightkeyword-only | NDArray[Any] | NoneDefault: None | See the operation contract and implementation below. |
asymmetric_weightkeyword-only | floatDefault: 0.0 | See the operation contract and implementation below. |
validation_asymmetric_weightkeyword-only | float | NoneDefault: None | See the operation contract and implementation below. |
asymmetric_under_scalekeyword-only | floatDefault: 13.0 | See the operation contract and implementation below. |
asymmetric_over_scalekeyword-only | floatDefault: 10.0 | See the operation contract and implementation below. |
standardize_xkeyword-only | boolDefault: False | See the operation contract and implementation below. |
polish_readoutkeyword-only | boolDefault: True | See the operation contract and implementation below. |
polish_ridgekeyword-only | floatDefault: 1e-06 | See the operation contract and implementation below. |
validation_selection_metrickeyword-only | Callable[[NDArray[Any], NDArray[Any]], float] | NoneDefault: None | See the operation contract and implementation below. |
validation_selection_complexity_weightkeyword-only | floatDefault: 0.0 | See the operation contract and implementation below. |
model_kwargskeyword-only | dict[str, Any] | NoneDefault: None | See the operation contract and implementation below. |
FittedJointOperatorRegressorExplicit validation & failure cases
- When
x_train.ndim != 2, raisesValueError('x_train must be a 2D array'). - When
x_val.ndim != 2 or x_val.shape[1] != x_train.shape[1], raisesValueError('x_val must be a 2D array with the same feature count as x_train'). - When
asymmetric_weight < 0.0, raisesValueError(f'asymmetric_weight must be non-negative, got {asymmetric_weight}'). - When
validation_asymmetric_weight < 0.0, raisesValueError(f'validation_asymmetric_weight must be non-negative, got {validation_asymmetric_weight}'). - When
validation_selection_complexity_weight < 0.0, raisesValueError(f'validation_selection_complexity_weight must be non-negative, got {validation_selection_complexity_weight}'). - When
not np.isfinite(score), raisesValueError(f'validation_selection_metric returned a non-finite score: {score}').
These are explicit source guards. Backend operations may also raise for invalid shapes, dtypes, or unsupported devices.
Executed regression · joint operator fit accepts asymmetric loss
Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_accepts_asymmetric_loss() -> None:
x, y = _synthetic(n=420)
fitted = fit_joint_operator_regressor(
x[:300],
y[:300],
x[300:],
y[300:],
seed=2,
epochs=60,
patience=25,
asymmetric_weight=1e-3,
model_kwargs={"ombu_channels": 0, "stochastic_gates": False},
)
assert "val_asymmetric" in fitted.history
assert np.isfinite(fitted.history["val_asymmetric"]).all()python -m pytest "packages/omnibias-torch/tests/test_joint_operator.py::test_joint_operator_fit_accepts_asymmetric_loss" -qRegression example · joint operator fit accepts sample weights
This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.
def test_joint_operator_fit_accepts_sample_weights() -> None:
x, y = _synthetic(n=500)
weights = np.ones(350, dtype=np.float32)
weights[y[:350] < np.median(y[:350])] = 2.0
fitted = fit_joint_operator_regressor(
x[:350],
y[:350],
x[350:],
y[350:],
seed=1,
epochs=80,
patience=30,
train_sample_weight=weights,
val_sample_weight=np.ones(150, dtype=np.float32),
model_kwargs={"ombu_channels": 0, "stochastic_gates": False},
)
pred = fitted.predict(x[350:])
assert np.isfinite(pred).all()python -m pytest packages/omnibias-torch/tests/test_joint_operator.py -k test_joint_operator_fit_accepts_sample_weights -qRead the implementation
def fit_joint_operator_regressor(
x_train: NDArray[Any],
y_train: NDArray[Any],
x_val: NDArray[Any] | None = None,
y_val: NDArray[Any] | None = None,
*,
seed: int = 0,
epochs: int = 400,
lr: float = 3e-2,
batch_size: int | None = None,
patience: int = 60,
sparsity_weight: float = 1e-3,
weight_decay: float = 1e-5,
train_sample_weight: NDArray[Any] | None = None,
val_sample_weight: NDArray[Any] | None = None,
asymmetric_weight: float = 0.0,
validation_asymmetric_weight: float | None = None,
asymmetric_under_scale: float = 13.0,
asymmetric_over_scale: float = 10.0,
standardize_x: bool = False,
polish_readout: bool = True,
polish_ridge: float = 1e-6,
validation_selection_metric: Callable[[NDArray[Any], NDArray[Any]], float] | None = None,
validation_selection_complexity_weight: float = 0.0,
model_kwargs: dict[str, Any] | None = None,
) -> FittedJointOperatorRegressor:
"""Fit a :class:`JointOperatorRegressor` with train/validation early stopping."""
if x_val is None:
x_val = x_train
if y_val is None:
y_val = y_train
x_train = np.asarray(x_train, dtype=np.float32)
y_train = np.asarray(y_train, dtype=np.float32)
x_val = np.asarray(x_val, dtype=np.float32)
y_val = np.asarray(y_val, dtype=np.float32)
if x_train.ndim != 2:
raise ValueError("x_train must be a 2D array")
if x_val.ndim != 2 or x_val.shape[1] != x_train.shape[1]:
raise ValueError("x_val must be a 2D array with the same feature count as x_train")
if asymmetric_weight < 0.0:
raise ValueError(f"asymmetric_weight must be non-negative, got {asymmetric_weight}")
if validation_asymmetric_weight is None:
validation_asymmetric_weight = asymmetric_weight
if validation_asymmetric_weight < 0.0:
raise ValueError(f"validation_asymmetric_weight must be non-negative, got {validation_asymmetric_weight}")
if validation_selection_complexity_weight < 0.0:
raise ValueError(
"validation_selection_complexity_weight must be non-negative, "
f"got {validation_selection_complexity_weight}"
)
train_weight = _prepare_sample_weight(train_sample_weight, x_train.shape[0], "train_sample_weight")
val_weight = _prepare_sample_weight(val_sample_weight, x_val.shape[0], "val_sample_weight")
if standardize_x:
x_mean = x_train.mean(axis=0)
x_scale = x_train.std(axis=0)
x_scale = np.where(x_scale < 1e-6, 1.0, x_scale).astype(np.float32)
else:
x_mean = np.zeros(x_train.shape[1], dtype=np.float32)
x_scale = np.ones(x_train.shape[1], dtype=np.float32)
y_mean = float(y_train.mean())
y_scale = float(y_train.std())
if y_scale < 1e-6:
y_scale = 1.0
xs_train = (x_train - x_mean) / x_scale
xs_val = (x_val - x_mean) / x_scale
ys_train = (y_train - y_mean) / y_scale
ys_val = (y_val - y_mean) / y_scale
torch.manual_seed(seed)
kwargs = model_kwargs or {}
model = JointOperatorRegressor(x_train.shape[1], **kwargs)
# The numpy I/O contract is float32 end-to-end, but the model's parameters
# are created at the global default dtype. Pin the model to float32 so a
# process-wide torch.set_default_dtype(torch.float64) cannot desync the
# float64 params from the float32 inputs (which otherwise crashes the
# ridge polish and any nn.Linear inside the operator bank).
model.to(torch.float32)
opt = torch.optim.AdamW(model.parameters(), lr=lr, weight_decay=weight_decay)
xtr = torch.as_tensor(xs_train, dtype=torch.float32)
ytr = torch.as_tensor(ys_train, dtype=torch.float32)
xv = torch.as_tensor(xs_val, dtype=torch.float32)
yv = torch.as_tensor(ys_val, dtype=torch.float32)
wtr = torch.as_tensor(train_weight, dtype=torch.float32)
wv = torch.as_tensor(val_weight, dtype=torch.float32)
history: dict[str, list[float]] = {
"train_loss": [],
"val_rmse_z": [],
"val_asymmetric": [],
"complexity": [],
"val_selection_score": [],
}
best_score = float("inf")
best_state: dict[str, Tensor] | None = None
stale = 0
n = xtr.shape[0]
full_batch = batch_size is None or batch_size >= n
for _ in range(epochs):
model.train()
if full_batch:
batch_indices = [torch.arange(n)]
else:
assert batch_size is not None
perm = torch.randperm(n)
batch_indices = [perm[start : start + batch_size] for start in range(0, n, batch_size)]
epoch_losses = []
for idx in batch_indices:
opt.zero_grad()
pred = model(xtr[idx])
mse = _weighted_mse(pred, ytr[idx], wtr[idx])
asymmetric = _weighted_asymmetric_rul_loss(
pred,
ytr[idx],
wtr[idx],
y_scale=y_scale,
under_scale=asymmetric_under_scale,
over_scale=asymmetric_over_scale,
)
complexity = model.complexity_loss()
loss = mse + asymmetric_weight * asymmetric + sparsity_weight * complexity
loss.backward() # type: ignore[no-untyped-call]
opt.step()
epoch_losses.append(float(loss.detach().cpu()))
model.eval()
with torch.no_grad():
val_pred = model(xv)
val_mse = _weighted_mse(val_pred, yv, wv)
val_asymmetric = _weighted_asymmetric_rul_loss(
val_pred,
yv,
wv,
y_scale=y_scale,
under_scale=asymmetric_under_scale,
over_scale=asymmetric_over_scale,
)
val_rmse = float(torch.sqrt(val_mse).cpu())
val_asymmetric_value = float(val_asymmetric.cpu())
complexity_value = float(model.complexity_loss().cpu())
val_pred_cycles = (val_pred.cpu().numpy() * y_scale + y_mean).astype(np.float64)
history["train_loss"].append(float(np.mean(epoch_losses)))
history["val_rmse_z"].append(val_rmse)
history["val_asymmetric"].append(val_asymmetric_value)
history["complexity"].append(complexity_value)
if validation_selection_metric is None:
score = (
val_rmse
+ validation_asymmetric_weight * val_asymmetric_value
+ 0.05 * sparsity_weight * complexity_value
)
else:
score = float(validation_selection_metric(y_val.astype(np.float64), val_pred_cycles))
if not np.isfinite(score):
raise ValueError(f"validation_selection_metric returned a non-finite score: {score}")
score += validation_selection_complexity_weight * complexity_value
history["val_selection_score"].append(float(score))
if score < best_score - 1e-6:
best_score = score
best_state = {name: value.detach().cpu().clone() for name, value in model.state_dict().items()}
stale = 0
else:
stale += 1
if stale >= patience:
break
if best_state is not None:
model.load_state_dict(best_state)
with torch.no_grad():
model.selection_readout_weight.copy_(model.readout.weight.detach().squeeze(0))
if polish_readout:
_polish_linear_readout(
model,
torch.cat([xtr, xv], dim=0),
torch.cat([ytr, yv], dim=0),
sample_weight=torch.cat([wtr, wv], dim=0),
ridge=polish_ridge,
)
model.eval()
return FittedJointOperatorRegressor(
model=model,
x_mean=x_mean.astype(np.float32),
x_scale=x_scale.astype(np.float32),
y_mean=y_mean,
y_scale=y_scale,
history=history,
)Other public import paths
omnibias.torch.architectures.fit_joint_operator_regressoromnibias.torch.architectures.joint_operator.fit_joint_operator_regressor