2017-05-22 1 views
2

Ich versuche, eine DST für die probablistische Programmierung von Jared Tobin blog post inspiriert zu implementieren.Modellierung Beobachtung für probabilistische Programmiersprache mit freien Monaden

Ein freies Monade für eine DST die Bernoulli und Beta-Verteilung einschließlich könnte wie folgt aussehen:

data ModelF r = 
    BernoulliF Double (Bool -> r) 
    | BetaF Double Double (Double -> r) 
    deriving (Functor) 

type Model = Free ModelF 

bernoulli :: Double -> Model Bool 
bernoulli p = liftF (BernoulliF p id) 

beta :: Double -> Double -> Model Double 
beta a b = liftF (BetaF a b id) 

ich es verlängern möchten Beobachtung auf Ausschüttungen zu unterstützen. Das heißt: erzwinge einen bestimmten Rückgabewert.

Erster Versuch war die Funktors zu verlängern:

data ModelF r = 
    BernoulliF Double (Bool -> r) 
    | BetaF Double Double (Double -> r) 
    | ObsF (ModelF r) r 
    deriving (Functor) 

Diese Problematik ist jedoch, da es für eine rekursive Verschachtelung von ObsF ermöglicht.

Eine Lösung wäre, den freien Monade in eine andere freie Monade heben einen beobachteten Wert darstellt:

data ObsModelF r = 
    PureF (Model r) 
    | ObsF (Model r) r 
    deriving (Functor) 

observe :: Model r -> r -> Free ObsModelF r 
observe model o = liftF (ObsF model o) 

Die Syntax ich nach obwohl bin ist:

let dist = do 
     p <- beta 1 1 
     observe (bernoulli p) True 

Dies ist unvereinbar mit ObsModelF seit beta 1 1 sollte auch in ObsModelF gehoben werden. Dies erfordert zwei separate Konstruktoren: einen für Verteilungen ohne Beobachtung und einen mit einer Beobachtung. Ist es möglich, diese Komplexität in der Sommerzeit zu vermeiden?


Ein dritter Versuch. Diesmal wickle ich den Verteilungsfunktor (ModelF) in den Beobachtungsfunktor ein, den ich dann anhebe (ObsModelF). ich einige Art Fehler ich allerdings recht nicht verstehen (die Kommentare sehen):

data ModelF r = 
    BernoulliF Double (Bool -> r) 
    | BetaF Double Double (Double -> r) 
    deriving (Functor) 

data ObsModelF r = 
    PureF (ModelF r) 
    | ObsF (ModelF r) r 
    deriving (Functor) 

type ObsModel = Free ObsModelF 

bernoulli :: Double -> ObsModel Bool 
bernoulli p = liftF . PureF $ BernoulliF p id 

beta :: Double -> Double -> ObsModel Double 
beta a b = liftF . PureF $ BetaF a b id 

observe :: ObsModel r -> r -> ObsModel r 
observe f o = liftF $ case f of 
      (Free f') -> case f' of 
       (PureF f'') -> ObsF f'' o -----| Couldn't match expected type ‘Free ObsModelF r’ 
       (ObsF f'' o') -> ObsF f'' o --| with actual type ‘r’ 

toSampler :: (RandomGen g) => ObsModel r -> State g r 
toSampler = iterM $ \case 
    ObsF a o -> case a of 
    BernoulliF p f -> return o >>= f -----| Couldn't match type ‘StateT g Data.Functor.Identity.Identity r’ 
    BetaF a b f -> return o >>= f  --| with ‘Bool’ 
    PureF a -> case a of 
    BernoulliF p f -> MWC.bernoulli p >>= f 
    BetaF a b f -> MWC.beta a b >>= f 

ich einen sehr einfachen Interpreter enthalten haben (toSampler). Derzeit ignoriert es die Verteilung vollständig und bildet nur den Beobachtungswert ab. Bitte beachten Sie, dass dies nicht das beabsichtigte Verhalten beim Konditionieren einer Distribution ist. Es wird nur gezeigt, wie der Interpreter die freie Struktur durchqueren würde.

+0

Ich bin nicht sicher über die Semantik, die Sie vom Typ 'ObsModelF' erwarten. Könnten Sie einen Dolmetscher schreiben? Was ist falsch daran, 'beta 1 1' mit' PureF' oder einer 'lift'-ähnlichen Funktion zu verpacken? –

+0

Ich möchte eine willkürliche Verteilung beobachten. Wenn ich alle Distributionen mit 'Pure' (sowohl mit Bernoulli als auch mit Beta) aufheben würde, müsste ich Bernoulli auspacken, um es wieder mit' ObsF' zu heben. Es scheint wie eine Menge Operationen für eine einfache Aufgabe. Was ich erreichen möchte, ist, einen 'ModelF r'-Rückgabewert zu fixieren, indem man es als beobachtet' markiert '. Ich kann versuchen, mehr im Fragekörper auszuarbeiten. – tmpethick

+1

Vom Lesen des Blogposts und von einigem mehr Materialien habe ich eine Idee von, was es bedeutet zu "beobachten", aber ich kann das nicht mit deinem Typ im Moment folglich vereinbaren Warum habe ich darum gebeten, einen Dolmetscher zu haben? Darüber hinaus kann das Wrapping/Entpacken normalerweise ziemlich einfach vom Sprachbenutzer ausgeblendet werden, aber es ist einfacher, einen geeigneten Weg zu finden, um die API zu bereinigen, wenn es zuerst eine funktionierende Implementierung gibt. –

Antwort

1

Ich kenne etwas ähnliches in anderen Sprachen/DSLs. Ich bin mir nicht sicher, ob das, was ich vorhabe, genau das ist, wonach Sie suchen, aber ich werde eine grobe Skizze der Idee geben. Vielleicht findest du es hilfreich. Der observeobserveobserve Ich bin vertraut mit hat einen Typ etwas wie Distribution a -> a -> Model(), und es wird interpretiert als Multiplikation der Wahrscheinlichkeit des aktuellen Pfads durch das Modell durch die Wahrscheinlichkeit (/ Dichte) der Beobachtung unter der Verteilung. Diese observe nimmt eine Distribution statt eine Model, da wir eine Möglichkeit zur Berechnung der Wahrscheinlichkeit (/ Dichte) der Beobachtung benötigen.

Sobald Sie einen Distribution-Typ haben, können Sie die einzelnen Verteilungsvorgänge auch durch eine einzige Operation ersetzen, um Unsicherheit einzuführen. Dies würde ein Distribution als Argument nehmen.

Ich habe eine Haskell DSL, die auf diese Weise funktioniert here.Der einzige Unterschied ist, dass observeimplemented in Bezug auf eine einfachere Operation namens weight, ist, die willkürlich die Log-Wahrscheinlichkeit des aktuellen Pfads ändert.

BTW, dieser Ansatz wird in seiner Gesamtheit aus der WebPPL Sprache gehoben. Hier

+0

Sieht aus wie ein wirklich netter Port - ich werde es mir genauer ansehen. Sie sollten auch https://github.com/adscib/monad-bayes ausprobieren, falls Sie dies nicht bereits getan haben. Es scheint einige Ähnlichkeiten zu geben. Es sieht auch so aus, als hätten sie begonnen, Single-Site-MH hinzuzufügen, die nicht Teil der ursprünglichen Arbeit war. Mein Interpreter wird es schließlich zu einem Single-Site-MH zuordnen, also sollte eine Beobachtung das 'logPdf' und' sample' für eine gegebene Distribution fixieren. Ich bemühe mich zu verstehen, wie dies als eine freie Monade modelliert werden kann - würdest du die freie Monade stapeln? – tmpethick

1

ist ein Vorschlag

data ModelF r = 
    BernoulliF Double (Bool -> r) 
    | BetaF Double Double (Double -> r) 
    | ObsFail 
    deriving (Functor) 

Dazu

let dist = do 
     p <- beta 1 1 
     b <- bernoulli p 
     if (b==True) 
      then return() 
      else ObsFail 

Im Allgemeinen tun können, können wir definieren

observe dist r = do 
    r' <- dist 
    if r == r' 
     then return() 
     else ObsFail 

zu probieren, wir wie normale Probe, außer wir wieder -Probe es jedes Mal, wenn wir ObsFail bekommen.