how to fit a method belonging to an instance with pymc3?

Ok, let's do this by parts. First I'll explain the error messages that you got, and then I'll tell you how I would proceed.

On the first question, the direct reason why you're getting a complaint on the missing parameters is because your function, defined inside the class, takes as input (self, t, y, z), while you're declaring it in the op decorator as having only three inputs (t, y, z). You would have to declare the inputs as being four in your decorator to account for the class instance itself.

On "added on april 9, 2017:", the first code will not work because the output of test.testfunc(t,y,z) is a theano function itself. pymc3.Deterministic is expecting it to output theano variables (or python variables). Instead, make test.testfun output val = t2 + y2 * self.observed_x + z2 * self.observed_x**2 directly.

Then, on "if I change 'testfunc' into:", you get that error because of the way pymc3 is trying to work with theano functions. Long story short, the problem is that when pymc3 is making use of this function, it will send it theano variables, while fval is expecting numerical variables (numpy arrays or other). As in the previous paragraph, you just need to output val directly: no need to compile any theano function for this.

As for how I would proceed, I would try to declare the class instance as input to the theano decorator. Unfortunately, I can't find any documentation on how to do this and it might actually be impossible (see this old post, for example).

Then I would try to pass everything the function needs as inputs and define it outside of the class. This could be quite cumbersome and if it needs methods as input, then you run into additional problems.

Another way of doing this is to create a child class of theano.gof.Op whose init method takes your class (or rather an instance of it) as input and then define your perform() method. This would look something like this:

class myOp(theano.gof.Op):
    """ These are the inputs/outputs you used in your as_op
    decorator.
    """
    itypes=[tt.dscalar,tt.dscalar,tt.dscalar]
    otypes=[tt.dvector]
    def __init__(self, myclass):
        """ myclass would be the class you had from before, which
        you called cprofile in your first block of code."""
        self.myclass = myclass
    def perform(self,node, inputs, outputs):
        """ Here you define your operations, but instead of
        calling everyting from that class with self.methods(), you
        just do self.myclass.methods().

        Here, 'inputs' is a list with the three inputs you declared
        so you need to unpack them. 'outputs' is something similar, so
        the function doesn't actually return anything, but saves all
        to outputs. 'node' is magic juice that keeps the world
        spinning around; you need not do anything with it, but always
        include it.
        """
        t, y, z = inputs[0][0], inputs[0][1], inputs[0][2]
        outputs[0][0] = t+y*self.myclass.x+z*self.myclass.x**2
myop = myOp(myclass)

Once you have done this, you can use myop as your Op for the rest of your code. Note that some parts are missing. You can check my example for more details.

As for the example, you do not need to define the grad() method. Because of this, you can do all operations in perform() in pure python, if that helps.

Alternatively, and I say this with a smirk on my face, if you have access to the definition of the class you're using, you can also make it inherit from theano.gof.Op, create the perform() method (as in my other example, where you left a message) and try to use it like that. It could create conflicts with whatever else you're doing with that class and it's probably quite hard to get right, but might be fun to try.

Tags:

Pymc3