TuringLang / DynamicPPL.jl

Implementation of domain-specific language (DSL) for dynamic probabilistic programming
https://turinglang.org/DynamicPPL.jl/
MIT License
164 stars 29 forks source link

`submodel` and `generated_quantities` operations on models #691

Open yebai opened 1 week ago

yebai commented 1 week ago

Currently implemented operations on Turing models:

@model function demo1()
  x ~ Normal()
  z ~ Normal()
  y = x - z
  return y
end

m = demo1()
conditioned_m = condition(m, (x=1))
fixed_m = fix(m, (x=1))
ret = generated_quantities(m, (x=1.0, z=2.0))
predict(m, chain) 

Proposed new model operation

This will replace and unify two current syntax submodel and generated_quantities. A reviewer for a Turing.jl preprint has pointed out that the generated_quantities is confusing due to the name clash with Stan's generated quantities block, but with different motivations (Stan's generated quantities are entirely motivated for performance while ours is a return statement that can be used for many purposes).

Another consideration is that submodel and generated_quantities have almost identical semantics from the user's perspective: both syntaxes obtain the returned variables of a model. However, the submodel syntax requires some special treatment for inference purposes, i.e., storing all submodel random variables in the parent model's VarInfo. This distinction doesn't matter much for users and won't deserve two separate syntaxes.

@model function demo2a(x, y) 
   @submodel a  = demo1(x)
   return y ~ Uniform(0, abs(a)) 
end

# with the proposed syntax, this becomes: 

@model function demo2b(x, y) 
   a = @returned_quantities(demo1()) 
   return y ~ Uniform(0, a) 
end 

In addition, the generated_quantites becomes

returned_quantities(model::Model, parameters::NamedTuple)
returned_quantities(model::Model, values, keys)
torfjelde commented 1 week ago

There's a big discussion that seems very relevant here: #589

But the syntax you propose is not possible to achieve. It would have to be a macro, unless we want to start messing with function calls in a model, which really doesn't seem like something we want to do :confused:

yebai commented 1 week ago

But the syntax you propose is not possible to achieve. It would have to be a macro, unless we want to start messing with function calls in a model, which really doesn't seem like something we want to do 😕

I am aware of this. It is easily approachable by replacing all returned_quantities calls with @returned_quantities as part of the @model transformation if we want. I don't think the issue is the difficulty of implementation, but rather, it is if we wish to abuse the function call syntax slightly. I can see the arguments for preferring not to go down that route; if so, we can use @returned_quantities instead of returned_quantities in the above example.