My overall goal is to do inference for a SIR-model that is represented by a multidimensional SDE.
My idea was to interprete the Euler-scheme as an autoregressive process with mean and standard deviation non-linear dependent on the last state of the process.
The Euler-scheme for a SDE takes the form
Since dB_t is a vector of independent normally distributed random variables it should be multivariate normal distributed. But trying to implement that I always get a RuntimeError: Initialization failed.
error appearing.
A minimal example I created is using the following two-dimensional SDE for an SIS-model:
I encoded the model as follows:
functions {
vector mu(vector y, real alpha, real beta, real gamma) {
vector[2] m;
m[1] = (beta-alpha*y[1]*y[2]-gamma*y[2]-beta*y[1]);
m[2] = (alpha*y[1]*y[2]-(beta+gamma)*y[2]);
return m;
}
vector Sigma(vector y, real sigma) {
vector[2] sig;
sig[1] = sigma*y[1]*y[2]/10;
sig[2] = sigma*y[1]*y[2]/10;
return sig;
}
}
data{
int<lower=0> N;
real<lower=0> dt;
array[N] vector[2] y;
}
parameters{
real<lower=0, upper=1> alpha;
real<lower=0, upper=1> beta;
real<lower=0, upper=1> gamma;
real<lower=0, upper=1> sigma;
}
model{
for (n in 2:N) {
y[n] ~ normal(y[n-1]+mu(y[n-1], alpha, beta, gamma)*dt, sqrt(dt)*Sigma(y[n-1], sigma));
}
}
And then used same synthetic generated data to build and fit the model using PyStan
with
post_sec = stan.build(second_model, data=sec_input_data )
sec_fit = post_sec.sample(num_chains=4, num_samples=1000)
This worked fine, at least no errors occured.
But this was just an easy model, which I could write as a vector of independent normal distributed random variables. The model which I normally want to fit is much more complicated and especially involves correlation of the noise of the different compartments, so I would need to sample a vector from a multivariate normal with given mean and covariance matrix.
So the next step was to take the simple model from above and write the noise function as a diagonal matrix (no correlation in the simple model) and then draw y from a multivariate normal:
functions {
vector mu(vector y, real alpha, real beta, real gamma) {
vector[2] m;
m = y*(beta-alpha-gamma-beta);
return m;
}
matrix Sigma(vector y, real sigma) {
matrix[2, 2] sig;
sig[1, 1] = - sqrt(sigma*y[1]*y[2]/100);
sig[2, 2] = sqrt(sigma*y[1]*y[2]/100);
sig[2,1] = 0
sig[1,2] = 0
return sig;
}
}
data{
int<lower=0> N;
real<lower=0> dt;
array[N] vector[2] y;
}
parameters{
real<lower=0, upper=1> alpha;
real<lower=0, upper=1> beta;
real<lower=0, upper=1> gamma;
real<lower=0, upper=1> sigma;
}
model{
for (n in 2:N) {
y[n] ~ multi_normal(y[n-1]+mu(y[n-1], alpha, beta, gamma)*dt, sqrt(dt)*Sigma(y[n-1], sigma));
}
}
The model still compiles and I try to sample from it using the same synthetic data as before
post_third = stan.build(third_model, data=third_input_data)
third_fit = post_third.sample(num_chains=4, num_samples=1000)
but this gives the following error
Sampling: 0%Sampling: Initialization failed.
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
/home/vinc777/masterthesis/two_variant_model/PyStan/try.ipynb Cell 19' in <module>
----> 1 third_fit = post_third.sample(num_chains=4, num_samples=1000)
File ~/.local/lib/python3.8/site-packages/stan/model.py:89, in Model.sample(self, num_chains, **kwargs)
61 def sample(self, *, num_chains=4, **kwargs) -> stan.fit.Fit:
62 """Draw samples from the model.
63
64 Parameters in ``kwargs`` will be passed to the default sample function.
(...)
87
88 """
---> 89 return self.hmc_nuts_diag_e_adapt(num_chains=num_chains, **kwargs)
File ~/.local/lib/python3.8/site-packages/stan/model.py:108, in Model.hmc_nuts_diag_e_adapt(self, num_chains, **kwargs)
92 """Draw samples from the model using ``stan::services::sample::hmc_nuts_diag_e_adapt``.
93
94 Parameters in ``kwargs`` will be passed to the (Python wrapper of)
(...)
105
106 """
107 function = "stan::services::sample::hmc_nuts_diag_e_adapt"
--> 108 return self._create_fit(function=function, num_chains=num_chains, **kwargs)
File ~/.local/lib/python3.8/site-packages/stan/model.py:311, in Model._create_fit(self, function, num_chains, **kwargs)
308 return fit
310 try:
--> 311 return asyncio.run(go())
312 except KeyboardInterrupt:
313 return
File ~/.local/lib/python3.8/site-packages/nest_asyncio.py:38, in _patch_asyncio.<locals>.run(main, debug)
36 task = asyncio.ensure_future(main)
37 try:
---> 38 return loop.run_until_complete(task)
39 finally:
40 if not task.done():
File ~/.local/lib/python3.8/site-packages/nest_asyncio.py:81, in _patch_loop.<locals>.run_until_complete(self, future)
78 if not f.done():
79 raise RuntimeError(
80 'Event loop stopped before Future completed.')
---> 81 return f.result()
File /usr/lib/python3.8/asyncio/futures.py:178, in Future.result(self)
176 self.__log_traceback = False
177 if self._exception is not None:
--> 178 raise self._exception
179 return self._result
File /usr/lib/python3.8/asyncio/tasks.py:280, in Task.__step(***failed resolving arguments***)
276 try:
277 if exc is None:
278 # We use the `send` method directly, because coroutines
279 # don't have `__iter__` and `__next__` methods.
--> 280 result = coro.send(None)
281 else:
282 result = coro.throw(exc)
File ~/.local/lib/python3.8/site-packages/stan/model.py:235, in Model._create_fit.<locals>.go()
233 sampling_output.clear()
234 sampling_output.write_line("<info>Sampling:</info> <error>Initialization failed.</error>")
--> 235 raise RuntimeError("Initialization failed.")
236 raise RuntimeError(message)
238 resp = await client.get(f"/{fit_name}")
RuntimeError: Initialization failed.
I already tried to give more constraints on the parameters to avoid some log-probability going to infinity, but it did not work.
I am wondering whether I am using the multivariate normal in a wrong way, or it is not supported.
Or is there any better way to deal with inference for SDEs in STAN?
Or would you even say STAN is not yet the right package for that and have some other recommendations.
I am glad for every idea or hint.