Frequently Asked Questions¶
What is the ObservationModel class / do I need it?¶
ObservationModel is a convenience class that wraps a callable (x, u, t) -> Distribution into a standard interface with log_prob and sample methods. You don't strictly need it: you can pass any callable that returns a NumPyro distribution to DynamicalModel's observation_model argument. The built-in LinearGaussianObservation and DiracIdentityObservation implement this interface for common cases. See the observations API reference for details.
What are the most common ways to condition models on data for system identification?¶
Say you have a dynestyx model model that accepts obs_times, obs_values (and optionally ctrl_times, ctrl_values for controlled systems) and passes them to dsx.sample:
def model(obs_times=None, obs_values=None, ctrl_times=None, ctrl_values=None):
params = numpyro.sample(...)
dynamics = DynamicalModel(...)
return dsx.sample("f", dynamics, obs_times=obs_times, obs_values=obs_values, ctrl_times=ctrl_times, ctrl_values=ctrl_values)
ctrl_times and ctrl_values when the model has no controls.
-
HMM: Use the HMM filter (using an
HMMConfigconfiguation). See HMM inference.from dynestyx.inference.filters import Filter, HMMConfig with Filter(filter_config=HMMConfig()): return model(obs_times=obs_times, obs_values=obs_values) -
Discrete-time: Either a Simulator (NUTS samples both parameters and latent states) or a Filter (pseudo-marginal MCMC—parameters only). Note: the usage of discrete-time filters is currently under active development (likely incorrect implementations). For explicit representation of latent states (NUTS / SVI do all the work of parameter and latent state inference), use the simulator approach (currently working reliably), do:
For filter-based marginalization (currently not working reliably), do:with DiscreteTimeSimulator(): return model(obs_times=obs_times, obs_values=obs_values)with Filter(): return model(obs_times=obs_times, obs_values=obs_values) -
Continuous-time stochastic differential equation: Filter is the main choice. EnKF is the default and works well for nonlinear models, but only works if your initial condition and observation model are linear/gaussian. Use the particle filter (PF) only if you have non-Gaussian initial conditions or observation models—see SDE with non-Gaussian observations. We stand by these implementations, and they appear to be working well currently (especially EnKF).
from dynestyx.inference.filters import Filter, ContinuousTimeEnKFConfig, ContinuousTimeDPFConfig with Filter(filter_config=ContinuousTimeEnKFConfig()): # with Filter(filter_config=ContinuousTimeDPFConfig(n_particles=1000)): return model(obs_times=obs_times, obs_values=obs_values)
If you happen to have high-frequency, fully-observed, low-noise data, then there IS a much faster option, as shown in this deep dive. Simply do:
with DiscreteTimeSimulator():
with Discretizer():
return model(obs_times=obs_times, obs_values=obs_values, dirac_observation=True)
- Continuous-time ordinary differential equation: You can use a Simulator or a Filter. The simulator simply rolls out solutions from the initial conditions and checks fit to data; see tutorial on ODE inference.
Despite the deterministic nature of an ODE, sometimes a filtering-algorithm helps a lot (especially for long timeseries rollouts, partial/noisy observations, systems with large sensitivities to intial conditions). You can modify the model definition to have a small diffusion coefficient to "relax" the ODE problem to an SDE.
with ODESimulator(): return model(obs_times=obs_times, obs_values=obs_values)from dynestyx.inference.filters import Filter, ContinuousTimeEnKFConfig with Filter(filter_config=ContinuousTimeEnKFConfig()): return model(obs_times=obs_times, obs_values=obs_values, diffusion_coefficient=0.01)
What about multiple trajectories?¶
Feature coming soon.
What about hierarchical models?¶
Feature coming soon.
What about neural nets?¶
We will put examples up soon. See CD-Dynamax's Lorenz 63 neural drift tutorial to convince yourself that this will work well.
What about SINDy?¶
See our Sparse system identification deep dive. TL;DR: pick a Laplace or Spike-and-Slab prior and do everything else the dynestyx-way.
Why are particle filters underperforming?¶
Yes, they are worse than we thought in pseudo-marginal settings too. This is an area of active research. If you know how to do things better, please tell us!
How can I contribute?¶
Open an issue or submit a Pull Request on GitHub.