2017-02-13 1 views
7

Ich konnte eine Methode, die zu einer Instanz einer Klasse gehört, nicht als Deterministic-Funktion mit PyMc3 anpassen. Kannst du mir zeigen, wie das geht?Wie passe ich eine Methode an, die zu einer Instanz mit pymc3 gehört?

Der Einfachheit halber ist mein Fall unten mit einem einfachen Beispiel zusammengefasst. In Wirklichkeit ist meine Einschränkung, dass alles über eine GUI gemacht wird und Aktionen wie "find_MAP" innerhalb von Methoden sein sollten, die mit pyqt-Buttons verknüpft sind.

Ich möchte die Funktion 'FunctionIWantToFit' über die Datenpunkte passen. Problem: Der folgende Code:

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() 

gibt den folgenden Fehler:

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' 

Was ist los?

Bemerkung 1: Ich bekomme systematisch eine Fehlermeldung bezüglich des letzten Parameters von 'FunctionIWantToFit'. hier ist es "z", aber wenn ich z aus der Signatur entferne, betrifft die Fehlermeldung "y" (identisch mit Ausnahme des Namens der Variablen). Wenn ich in der Signatur eine vierte Variable 'w' hinzufüge, betrifft die Fehlermeldung 'w' (identisch mit Ausnahme des Namens der Variablen).

rk2: es sieht so aus, als hätte ich etwas sehr Einfaches in 'theano' oder 'pymc3' verpasst, denn wenn ich 'FunctionIWantToFit' außerhalb der Klasse platziere, funktioniert es. Siehe das folgende Beispiel.

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() 

gibt:

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)} 

Abgesehen davon, dass ich weiß nicht, wie das in mehrere Module ohne großen Änderungen zu tun, da die wirkliche ‚FunctionIWantToFit‘ auf eine Reihe von Variablen und Methoden abhängt, gehören zu dieser Instanz des Klassenprofils.

Tatsächlich weiß ich nicht einmal, wie ich das machen soll, da 'FunctionIWantToFit' dann Objekte in Argumenten haben sollte (die ich derzeit über self benutze) und ich bin mir nicht sicher, wie das mit dem Theano Decorator geht .

Also würde ich diese Lösung lieber vermeiden ... wenn nicht notwendig. dann brauche ich Erklärungen, wie es zu implementieren ...


am 9. April aufgenommen, 2017:

Auch ohne die Interpolation Frage, funktioniert es nicht, weil ich etwas offensichtlich mit Theano verpasst haben müssen und/oder pymc3. Bitte können Sie das Problem erklären? Ich möchte nur Modell und Daten vergleichen. Erstens ist es so eine Schande, an pymc2 hängen zu bleiben. ; Zweitens bin ich mir sicher, dass ich nicht der einzige bin, der ein so grundlegendes Problem hat.

Zum Beispiel Betrachten wir Variationen dieses sehr grundlegenden Code:

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) 

dieser Code mit der Fehlermeldung in der letzten Zeile nicht: TypeError: unsupported operand type(s) for -: 'TensorConstant' and 'Function'

wenn ich ‚testfunc‘ ändern in:

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 

der Code nicht auf der 'MyModel =' Linie mit Fehler 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?')

, wenn ich auf den ursprünglich ‚testfunc‘ zurückgehen, aber die letzte ‚mit Modell‘ Linien mit ändern:

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

dem Fehler ist das gleiche wie die ersten.

Ich präsentierte hier nur 3 Versuche, aber ich möchte unterstreichen, dass ich viele viele Kombinationen, einfacher und einfacher bis diese, während der Stunden ausprobiert habe. Ich habe das Gefühl, Pymc3 zeigt eine große Veränderung der Geist, im Vergleich zu Pymc2, die ich nicht bekommen habe und schlecht dokumentiert ist ...

Antwort

0

ich konvergierte schließlich in Richtung der erfolgreichen Code unten:

import numpy as np 
import theano 
from scipy.interpolate import interp1d 
import pymc3 as pm3 
theano.config.compute_test_value = 'ignore' 
theano.config.on_unused_input = 'ignore' 

class cprofile: 
    observations = np.array([6.25,2.75,1.25,1.25,1.5,1.75,1.5,1]) 
    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])  

    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) 
      obs=pm3.Normal('obs', 
       mu=FunctionIWantToFit(self)(t,y,z), 
       sd=0.1,observed=self.observations) 
      start = pm3.find_MAP() 
      print('start: ',start) 

class FunctionIWantToFit(theano.gof.Op): 
    itypes=[theano.tensor.dscalar, 
      theano.tensor.dscalar, 
      theano.tensor.dscalar] 
    otypes=[theano.tensor.dvector] 

    def __init__(self, cp): 
     self.cp = cp # note cp is an instance of the 'cprofile' class 

    def perform(self,node, inputs, outputs): 
     t, y, z = inputs[0], inputs[1], inputs[2] 

     xxx = self.cp.x 
     temp = t+y*xxx+z*xxx**2 
     interpolated_concentration = interp1d(xxx,temp) 
     outputs[0][0] = interpolated_concentration(self.cp.observed_x) 

testcp=cprofile() 
testcp.doMAP() 

dank der Antwort von Dario, weil ich zu langsam war von mir die erste Antwort zu verstehen. Ich bekomme es retrospektiv, aber ich denke stark, dass der pymc3 doc schmerzlich unklar ist. Es sollte sehr einfache und anschauliche Beispiele enthalten.

Allerdings habe ich nichts getan, was nach dem Kommentar von Chris funktioniert. Könnte jemand erklären und/oder ein Beispiel geben?

Noch eine Sache: Ich weiß nicht, ob mein Beispiel oben effizient ist oder vereinfacht werden könnte. Insbesondere gibt es mir den Eindruck, dass die Instanz 'testcp' zweimal in den Speicher kopiert wird. Weitere Kommentare/Antworten sind willkommen, weiter zu gehen.

1

theano.compile.ops.as_op ist nur eine Abkürzung für die Definition von einfachen Theano Ops. Wenn Sie komplexere codieren möchten, ist es besser, sie in einer separaten Klasse zu definieren. Objekte dieser Klasse können natürlich auf eine Instanz Ihres cprofile verweisen, wenn dies wirklich notwendig ist.

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

+0

danke für Ihre Antwort. Ich war weg und werde es jetzt versuchen. –

+0

Entschuldigung, aber es bleibt mir unklar. Ich habe viele Kombinationen aus einer hausgemachten Theano-Op mit pymc3 ausprobiert, aber nichts funktioniert und die Docs sind schmerzhaft verschwommen ... Könnten Sie ein Beispiel für Code geben? –

+0

Wenn Sie Ihre eigene Interpolationsfunktion mit Theano schreiben, sollten Sie keinen Op benötigen. Die 1D-Interpolation sollte einfach sein. –

3

Ok, lassen Sie uns diese Teile tun. Zuerst erkläre ich die Fehlermeldungen, die Sie erhalten haben, und dann erzähle ich Ihnen, wie ich vorgehen würde.

Bei der ersten Frage, der direkte Grund, warum Sie eine Beschwerde über die fehlenden Parameter erhalten, ist, weil Ihre Funktion, innerhalb der Klasse definiert, als Eingabe (selbst, t, y, z), während Sie sind Deklaration im Op-Dekorator mit nur drei Eingaben (t, y, z). Sie müssten die Eingaben im Dekorator als vier deklarieren, um die Klasseninstanz selbst zu berücksichtigen.

Am "hinzugefügt am 9. April 2017:", der erste Code wird nicht funktionieren, da die Ausgabe von test.testfunc (t, y, z) eine Theano-Funktion ist. pymc3.Deterministic erwartet, dass es dieano-Variablen (oder Python-Variablen) ausgibt. Setzen Sie stattdessen test.testfun val = t2 + y2 * self.observed_x + z2 * self.observed_x ** 2 direkt.

Dann, auf "Wenn ich 'testfunc' in:" ändern, erhalten Sie diesen Fehler wegen der Art, wie pymc3 versucht, mit denano-Funktionen zu arbeiten. Lange Rede, kurzer Sinn, das Problem ist, dass, wenn pymc3 diese Funktion nutzt, es die theano-Variablen sendet, während fval numerische Variablen (numpy arrays oder andere) erwartet. Wie im vorherigen Abschnitt müssen Sie Val nur direkt ausgeben: Sie müssen dafür keine theano-Funktion kompilieren.

Für wie ich fortfahren würde, würde ich versuchen, die Klasseninstanz als Eingabe für den Theano Decorator zu deklarieren. Leider kann ich keine Dokumentation darüber finden, wie dies zu tun ist und es könnte tatsächlich unmöglich sein (siehe zum Beispiel this old post).

Dann würde ich versuchen, alles, was die Funktion benötigt, als Eingaben und definieren Sie es außerhalb der Klasse. Das könnte ziemlich umständlich sein und wenn es Methoden als Eingabe benötigt, dann treten zusätzliche Probleme auf.

Eine andere Möglichkeit, dies zu tun, ist eine untergeordnete Klasse von theano.gof zu erstellen.Op, deren Methode init Ihre Klasse (oder eher eine Instanz davon) als Eingabe akzeptiert und dann Ihre perform() -Methode definiert. Dies würde in etwa so aussehen:

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) 

Sobald Sie dies getan haben, können Sie Kurzsichtige als Op für den Rest des Codes verwenden. Beachten Sie, dass einige Teile fehlen. Sie können my example für weitere Details überprüfen.

Wie bei the example müssen Sie die Methode grad() nicht definieren. Aus diesem Grund können Sie alle Operationen in perform() in reinem Python durchführen, wenn das hilft.

Alternativ, und ich sage dies mit einem Grinsen auf meinem Gesicht, wenn Sie Zugriff auf die Definition der Klasse, die Sie verwenden, können Sie auch erben von theano.gof.Op, erstellen Sie die perform() Methode (as in my other example, wo Sie eine Nachricht hinterlassen) und versuchen Sie es so zu verwenden. Es könnte zu Konflikten mit allem, was Sie sonst noch mit dieser Klasse machen, führen und es ist wahrscheinlich ziemlich schwer, es richtig zu machen, aber es könnte Spaß machen, es zu versuchen.

Verwandte Themen