如何使用pymc3拟合属于实例的方法?

时间:2017-02-13 13:22:56

标签: pymc3

我无法通过PyMc3使用属于类实例的方法作为确定性函数。你能告诉我怎么做吗?

为简单起见,下面用一个简单的例子总结我的案例。实际上,我的约束是一切都是通过GUI完成的,像'find_MAP'这样的动作应该在链接到pyqt按钮的方法中。

我想在数据点上安装函数'FunctionIWantToFit'。问题,以下代码:

import numpy as np
import pymc3 as pm3
from scipy.interpolate import interp1d
import theano.tensor as tt
import theano.compile

class cprofile:
    def __init__(self):
        self.observed_x = np.array([0.3,1.4,3.1,5,6.8,9,13.4,17.1])
        self.observations = np.array([6.25,2.75,1.25,1.25,1.5,1.75,1.5,1])
        self.x = np.arange(0,18,0.5)

    @theano.compile.ops.as_op(itypes=[tt.dscalar,tt.dscalar,tt.dscalar],
                              otypes=[tt.dvector])
    def FunctionIWantToFit(self,t,y,z):
        # can be complicated but simple in this example
        # among other things, this FunctionIWantToFit depends on a bunch of 
        # variables and methods that belong to this instance of the class cprofile,
        # so it cannot simply be put outside the class ! (like in the following example)
        val=t+y*self.x+z*self.x**2
        interp_values = interp1d(self.x,val)
        return interp_values(self.observed_x)

    def doMAP(self):
        model = pm3.Model()
        with model:
            t = pm3.Uniform("t",0,5)
            y = pm3.Uniform("y",0,5)
            z = pm3.Uniform("z",0,5)
            MyModel = pm3.Deterministic('MyModel',self.FunctionIWantToFit(t,y,z))
            obs = pm3.Normal('obs',mu=MyModel,sd=0.1,observed=self.observations)
            start = pm3.find_MAP()
            print('start: ',start)

test=cprofile()
test.doMAP()

给出以下错误:

Traceback (most recent call last):

  File "<ipython-input-15-3dfb7aa09f84>", line 1, in <module>
    runfile('/Users/steph/work/profiles/GUI/pymc3/so.py', wdir='/Users/steph/work/profiles/GUI/pymc3')

  File "/Users/steph/anaconda/lib/python3.5/site-packages/spyder/utils/site/sitecustomize.py", line 866, in runfile
    execfile(filename, namespace)

  File "/Users/steph/anaconda/lib/python3.5/site-packages/spyder/utils/site/sitecustomize.py", line 102, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "/Users/steph/work/profiles/GUI/pymc3/so.py", line 44, in <module>
    test.doMAP()

  File "/Users/steph/work/profiles/GUI/pymc3/so.py", line 38, in doMAP
    MyModel = pm3.Deterministic('MyModel',self.FunctionIWantToFit(x,y,z))

  File "/Users/steph/anaconda/lib/python3.5/site-packages/theano/gof/op.py", line 668, in __call__
    required = thunk()

  File "/Users/steph/anaconda/lib/python3.5/site-packages/theano/gof/op.py", line 912, in rval
    r = p(n, [x[0] for x in i], o)

  File "/Users/steph/anaconda/lib/python3.5/site-packages/theano/compile/ops.py", line 522, in perform
    outs = self.__fn(*inputs)

TypeError: FunctionIWantToFit() missing 1 required positional argument: 'z'

怎么了?

备注1:我系统地收到有关'FunctionIWantToFit'的最后一个参数的错误消息。这里是'z'但是如果我从签名中删除z,则错误消息涉及'y'(除了变量名称之外相同)。如果我在签名中添加第四个变量'w',则错误消息涉及'w'(除了变量名称之外相同)。

rk2:看起来我错过了'theano'或'pymc3'中非常基本的东西,因为当我在课堂外放置'FunctionIWantToFit'时,它可以正常工作。请参阅以下示例。

class cprofile:
    def __init__(self):
        self.observations = np.array([6.25,2.75,1.25,1.25,1.5,1.75,1.5,1])

    def doMAP(self):
        model = pm3.Model()
        with model:
            t = pm3.Uniform("t",0,5)
            y = pm3.Uniform("y",0,5)
            z = pm3.Uniform("z",0,5)
            MyModel = pm3.Deterministic('MyModel',FunctionIWantToFit(t,y,z))
            obs = pm3.Normal('obs',mu=MyModel,sd=0.1,observed=self.observations)
            start = pm3.find_MAP()
            print('start: ',start)

@theano.compile.ops.as_op(itypes=[tt.dscalar,tt.dscalar,tt.dscalar],
                              otypes=[tt.dvector])
def FunctionIWantToFit(t,y,z):
        observed_x = np.array([0.3,1.4,3.1,5,6.8,9,13.4,17.1])
        x = np.arange(0,18,0.5)
        val=t+y*x+z*x**2
        interp_values = interp1d(x,val)
        return interp_values(observed_x)

test=cprofile()
test.doMAP()

给出:

Warning: gradient not available.(E.g. vars contains discrete variables). MAP estimates may not be accurate for the default parameters. Defaulting to non-gradient minimization fmin_powell.
WARNING:pymc3:Warning: gradient not available.(E.g. vars contains discrete variables). MAP estimates may not be accurate for the default parameters. Defaulting to non-gradient minimization fmin_powell.
Optimization terminated successfully.
         Current function value: 1070.673818
         Iterations: 4
         Function evaluations: 179
start:  {'t_interval_': array(-0.27924150484602733), 'y_interval_': array(-9.940000425802811), 'z_interval_': array(-12.524909223913992)}

除非我在几个模块中没有大的修改就不知道如何做到这一点,因为真正的'FunctionIWantToFit'依赖于属于类配置文件的这个实例的一堆变量和方法。

事实上,我甚至不确定我是怎么做的,因为'FunctionIWantToFit'应该在参数中有对象(我目前通过self使用)并且我不确定如何使用theano装饰器做到这一点。

所以我宁愿避免这种解决方案......除非必要。那么我需要解释如何实现它......

于2017年4月9日添加:

即使没有插值问题,它也不起作用,因为我必须错过了与theano和/或pymc3有关的一些东西。请问你能解释一下这个问题吗?我只想比较模型和数据。首先,它是如此羞于被pymc2所困扰。 ;第二,我确定我不是唯一一个有这种基本问题的人。

例如,让我们考虑一下这个基本代码的变体:

import numpy as np
import theano
import pymc3
theano.config.compute_test_value = 'ignore'
theano.config.on_unused_input = 'ignore'

class testclass:
    x = np.arange(0,18,0.5)
    observed_x = np.array([0.3,1.4,3.1,5,6.8,9,13.4,17.1])
    observations = np.array([6.25,2.75,1.25,1.25,1.5,1.75,1.5,1])

    def testfunc(self,t,y,z):
        t2 = theano.tensor.dscalar('t2')
        y2 = theano.tensor.dscalar('y2')
        z2 = theano.tensor.dscalar('z2')
        val = t2 + y2 * self.observed_x + z2 * self.observed_x**2
        f = theano.function([t2,y2,z2],val)
        return f

test=testclass()
model = pymc3.Model()
with model:
    t = pymc3.Uniform("t",0,5)
    y = pymc3.Uniform("y",0,5)
    z = pymc3.Uniform("z",0,5)

with model:
   MyModel = pymc3.Deterministic('MyModel',test.testfunc(t,y,z))

with model:
   obs = pymc3.Normal('obs',mu=MyModel,sd=0.1,observed=test.observations)

此代码在最后一行失败,并显示错误消息:TypeError: unsupported operand type(s) for -: 'TensorConstant' and 'Function'

如果我更改&#39; testfunc&#39;成:

def testfunc(self,t,y,z):
    t2 = theano.tensor.dscalar('t2')
    y2 = theano.tensor.dscalar('y2')
    z2 = theano.tensor.dscalar('z2')
    val = t2 + y2 * self.observed_x + z2 * self.observed_x**2
    f = theano.function([t2,y2,z2],val)
    fval = f(t,y,z,self.observed_x)
    return fval

代码在&#39; MyModel =&#39;处失败错误TypeError: ('Bad input argument to theano function with name "/Users/steph/work/profiles/GUI/pymc3/theanotest170409.py:32" at index 0(0-based)', 'Expected an array-like object, but found a Variable: maybe you are trying to call a function on a (possibly shared) variable instead of a numeric array?')

的行

如果我回到原来的&#39; testfunc&#39;但改变最后一个模型&#39;以下行:

with model:
   fval = test.testfunc(t,y,z)
   obs = pymc3.Normal('obs',mu=fval,sd=0.1,observed=test.observations)

错误与第一个错误相同。

我在这里只展示了3次尝试,但我想强调一下,我尝试了很多种组合,在这几种情况下,这些组合更简单,更简单。我觉得pymc3表现出一种巨大的精神变化,与pymc2相比,我没有得到并且记录不足......

3 个答案:

答案 0 :(得分:3)

好的,让我们按部分来做。首先,我将解释您收到的错误消息,然后我会告诉您我将如何继续。

关于第一个问题,您对缺失参数进行投诉的直接原因是因为您在类中定义的函数将作为输入(self,t,y,z),而您&# 39;在op装饰器中重新声明它只有三个输入(t,y,z)。您必须在装饰器中将输入声明为四,以便考虑类实例本身。

On&#34; 2017年4月9日添加:&#34;,第一个代码无效,因为test.testfunc(t,y,z)的输出本身就是theano函数。 pymc3.Deterministic期望它输出theano变量(或python变量)。相反,直接使test.testfun输出val = t2 + y2 * self.observed_x + z2 * self.observed_x ** 2.

然后,在&#34;如果我改变&#39; testfunc&#39;进入:&#34;,由于pymc3尝试使用theano函数的方式,你得到了这个错误。长话短说,问题是当pymc3正在使用这个函数时,它会发送它的theano变量,而fval期望数值变量(numpy数组或其他)。与前一段一样,您只需要直接输出val:无需为此编译任何theano函数。

至于我将如何继续,我会尝试将类实例声明为theano装饰器的输入。不幸的是,我无法找到有关如何执行此操作的任何文档,实际上可能无法实现(例如,请参阅this old post)。

然后我会尝试将函数所需的所有内容作为输入传递,并在类之外定义它。这可能非常麻烦,如果它需要方法作为输入,那么你会遇到其他问题。

另一种方法是创建一个theano.gof.Op的子类,其 init 方法将您的类(或者更确切地说是它的实例)作为输入,然后定义您的perform()方法。这看起来像这样:

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)

完成此操作后,您可以使用myop作为其余代码的操作。请注意,某些部分缺失。您可以查看my example了解详情。

至于the example,您不需要定义grad()方法。因此,如果有帮助,你可以在纯python中的perform()中执行所有操作。

或者,我在脸上露出笑容说,如果你可以访问你正在使用的类的定义,你也可以让它继承自theano.gof.Op,创建表演( )方法(as in my other example,你留下了一条消息)并尝试使用它。它可能会与您在该课程中所做的任何事情产生冲突,而且可能很难做到正确,但尝试可能会很有趣。

答案 1 :(得分:1)

theano.compile.ops.as_op只是定义简单的Theano Ops的简称。如果您想编写更多涉及的代码,最好在单独的类中定义它。如果真的有必要,这个类的对象当然可以引用你的cprofile实例。

http://deeplearning.net/software/theano/extending/extending_theano.html

答案 2 :(得分:1)

我终于收敛到下面成功的代码:

{{1}}

感谢Dario的回答,因为我自己太慢了解第一个答案。我回顾性地得到它,但我强烈认为pymc3 doc是痛苦的不清楚。它应该包含非常简单和说明性的例子。

然而,在Chris的评论之后,我没有成功地做任何有用的事情。任何人都可以解释和/或举例吗?

还有一件事:我不知道上面的例子是否有效或可以简化。特别是它给我的印象是实例'testcp'在内存中被复制两次。欢迎提出更多意见/答案。