Source code for neuralfieldmanifold.training.evaluation
"""Prediction, coefficient, and AR-order evaluation."""
import numpy as np
import torch
[docs]
def evaluate(
model,
signals,
*,
true_coefficients=None,
true_orders=None,
batch_size=32,
device="cpu",
sample_order=False,
):
"""Evaluate DeepLagField predictions and optional ground-truth targets.
Prediction MSE excludes the leading maximum-order lag context.
Coefficient MSE includes all time positions and lag coefficients.
When true_orders are supplied, returns exact and within-one order
accuracy, mean absolute order error, and mean relative order error.
Inputs have shape (batch, sequence_length). Returned predictions,
coefficients, and selected orders are NumPy arrays. Order selection is
deterministic unless sample_order=True.
"""
if batch_size < 1:
raise ValueError("batch_size must be positive")
signals = torch.as_tensor(signals, dtype=torch.float32)
if (
signals.ndim != 2
or signals.shape[1] != model.sequence_length
or not len(signals)
):
raise ValueError("Expected nonempty (batch, sequence_length) signals")
model.to(device).eval()
coefficients, predictions, orders = [], [], []
with torch.no_grad():
for start in range(0, len(signals), batch_size):
output = model(
signals[start : start + batch_size].to(device),
sample_order=sample_order,
)
coefficients.append(output.coefficients.cpu().numpy())
predictions.append(output.prediction.cpu().numpy())
orders.append(output.order.cpu().numpy())
coefficients, predictions, orders = map(
np.concatenate, (coefficients, predictions, orders)
)
result = {
"coefficients": coefficients,
"prediction": predictions,
"order": orders,
"prediction_mse": float(
np.mean(
(
predictions[:, model.max_order :]
- signals.numpy()[:, model.max_order :]
)
** 2
)
),
}
if true_coefficients is not None:
truth = np.asarray(true_coefficients)
if truth.shape != coefficients.shape:
raise ValueError("true_coefficients must match model output shape")
result["coefficient_mse"] = float(np.mean((coefficients - truth) ** 2))
if true_orders is not None:
truth = np.asarray(true_orders)
if truth.shape != orders.shape or not np.isin(truth, model.orders).all():
raise ValueError(
"true_orders must contain one supported actual order per signal"
)
result.update(
order_accuracy=float(np.mean(orders == truth)),
within_one_accuracy=float(np.mean(np.abs(orders - truth) <= 1)),
order_mae=float(np.mean(np.abs(orders - truth))),
order_relative_error=float(np.mean(np.abs(orders - truth) / truth)),
)
return result