GSoC 2019: Testing an API
Published:
This is a really short update. Here are a couple things I have been working on since the last blog post.
1) Continuing to write the API so that it is intuitive
2) Writing unit tests
3) Benchmarking
When I last made a blog post about the API, users were to pass the ode parameters and initial conditions as a single vector. That was just to get things off the ground. Now that API is working, I can go back and make that a little more user friendly. The ODEModel
(the meat and potatoes of the API) inherits from the theano.Op
class, so in the make_node
method I changed
def make_node(self, x):
x = theano.tensor.as_tensor_variable(x)
return theano.Apply(self, [x], [x.type()])
to
def make_node(self, odeparams, initial_condition):
if np.ndim(odeparams)>1:
odeparams = np.ravel(odeparams)
if np.ndim(initial_condition) > 1:
odeparams = np.ravel(initial_condition)
odeparams = tt.as_tensor_variable(odeparams)
initial_condition = tt.as_tensor_variable(initial_condition)
x = tt.concatenate([odeparams,initial_condition])
return theano.Apply(self, [x], [x.type()])
The little bit of logic at the beginning is to get around some shape problems with theano
. So now to use the API, instead of doing
all_params = pm.math.stack([<parameters here>, <initial conditions here>])
forward = ode_model(all_params)
you can do
forward = ode_model(odeparams = [<parameters here>], initial_condition = [<initial conditions here>])
which I think is much better. Explicit is better than implicit. This change actually makes some models run much faster which is interesting.