-
Notifications
You must be signed in to change notification settings - Fork 35
Accumulators stage 2 #925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: breaking
Are you sure you want to change the base?
Accumulators stage 2 #925
Conversation
Benchmark Report for Commit 175b633Computer Information
Benchmark Results
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## breaking #925 +/- ##
===========================================
Coverage ? 81.11%
===========================================
Files ? 37
Lines ? 4035
Branches ? 0
===========================================
Hits ? 3273
Misses ? 762
Partials ? 0 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Hmmm, in terms of design, the other potential option I see is to make the new
So it seems the main tradeoff is that having it as a positional argument allows for the most efficient varinfo (one without a likelihood accumulator) to be generated if you do e.g. I think my first instinct is that I prefer the latter, and you could either insert a check in the inner constructor to see if the accumulators are consistent (i.e. warn if you have extra accs, or error if you don't have enough accs), or just straight-up call Do you prefer the former? I'll mull over it a bit more too and see if any ideas come up. |
I wouldn't even bother checking for consistency if the user provides both I would be happy to give up the case of There's also something about type dispatch treating keyword args differently. Sometimes methods are specialised on them and sometimes they are not, and I don't understand the details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it and I think I would prefer to be able to keep the new getlogdensity
argument optional by declaring the extra method:
function LogDensityFunction(
model::Model,
varinfo::AbstractVarInfo,
context::AbstractContext=DefaultContext();
adtype::Union{ADTypes.AbstractADType,Nothing}=nothing
)
return LogDensityFunction(model, getlogjoint, varinfo, context; adtype)
end
This is the 2^N method problem but in this case N = 1 so I'm still fine with it. Main reason is because (in my experience working with this codebase) LogDensityFunction(model, varinfo)
is used far more commonly than LogDensityFunction(model, varinfo, PriorContext())
(or LikelihoodContext
), so it's a nice convenience.
Also I think LogDensityFunction is likely to become more user-facing so that would likely be useful for many people.
It's not the worst, but I'm not a big fan of the behaviour of
If this is true, then I agree, but I'm not sure it is. How often do users want to customise their VarInfos? If we were making this from scratch, what would we do?
I think of these 1. is a thing that makes sense to a statistician/modeller, and should thus be more prominent than the others. EDIT: It's also the only one that changes the output of |
Yeah, that's fair -- I don't really like it too and I feel like I'm kind of stumbling around trying to find what I really want...
...I thought about it and I think my real hang-up is not so much convenience, but I think that the information about which part of logp is to be calculated is being specified twice — once in the function, and once in the VarInfo's accumulators. And I don't like that there's potential inconsistency between the two sources of information — and although we can resolve it by declaring the function to be the source of truth — this isn't obvious from the interface, and future readers will have to look into this file to figure it out.* In my ideal world,† I would want there to be a single source of truth (this would necessarily be the varinfo, since you can't create an LDF without a varinfo) and for the user to specify this information (by setting the accumulators themselves). i.e instead of
they would call
and to make that easier I'd probably make * It's still overall better than the previous world where the context was magically doing things to modify how varinfo was being changed. † Okay, in my ideal-ideal world everything would be a keyword argument, but Julia probably doesn't like this world. |
A bit off topic, but I want to do something like this regardless of what we do with LDF, but I've so far struggled with the fact that I see what you mean by a single source of truth. The way I explain this to myself, which is definitely imperfect, is that Note that accumulators and possible EDIT: Maybe a better example of |
I'm making various changes to accumulators as I integrate Turing.jl with them. This isn't ready for review yet, but @penelopeysm, can I ask you for your thoughts on the design of the proposed changes to LogDensityFunction? It would now have a new field, given as the second constructor argument, called
getlogdensity
. By default it'sgetlogjoint
, but you can set it togetlogprior
orgetloglikelihood
or any other function that takes anAbstractVarInfo
. Its return value will be the return value oflogdensity_and_gradient
etc. The defaultVarInfo
, if one isn't given by the user, is also now set based ongetlogdensity
, to make sure it has the right accumulators.