-
Notifications
You must be signed in to change notification settings - Fork 37
Make FastLDF the default #1139
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
Make FastLDF the default #1139
Conversation
79a440c to
64ad4af
Compare
Benchmark Report
Computer InformationBenchmark Results |
|
DynamicPPL.jl documentation for PR #1139 is available at: |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## breaking #1139 +/- ##
============================================
- Coverage 81.59% 81.07% -0.52%
============================================
Files 42 41 -1
Lines 3955 3894 -61
============================================
- Hits 3227 3157 -70
- Misses 728 737 +9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
3e646ca to
0dd2f70
Compare
c4f93fe to
c1ee6cc
Compare
0dd2f70 to
077457f
Compare
d86ff22 to
be27184
Compare
0150ef4 to
2fad97b
Compare
0cc9278 to
6f5df1a
Compare
177656b to
9310ec0
Compare
|
@mhauru Feel free to not do a full review at this stage, right now I'm more curious as to your thoughts about SVI. Happy to either keep it in for now, or remove it outright. Regardless of which way we go, I can rebase this against breaking so that this can actually be reviewed. |
9310ec0 to
6a52955
Compare
|
Trying to think of reasons to keep SVI, and the only one I can think of would be if we, or someone else, used it with one of the methods that don't use LDF. It hasn't traditionally worked with particle samplers because it didn't have Its days are definitely numbered. The only reason I can think of for not doing it now would be to investigate using it with particle samplers, but I doubt we'll get to that. So I'd lean towards getting the code simplification straight-away, make it easier to work with VarInfo as we keep refactoring. |
6a52955 to
992cea9
Compare
7fa0986 to
6849bc2
Compare
|
I think CloudFlare is responsible for the remaining ordinary test suite failures. The perf benchmarks are pretty much where I expected them to be.
The gradient evaluation benchmarks are not amazing, but I think it's mainly because any perf gains for these models are in primal evaluation, and so if the gradient doesn't also get sped up, it looks bad. Arguably there should be a third column which is |
6849bc2 to
b1368dd
Compare
HISTORY.md
Outdated
|
|
||
| #### SimpleVarInfo | ||
|
|
||
| `SimpleVarInfo` has been removed. |
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.
SimpleVarInfo has cleaner code than VarInfo. Doesn't it make more sense to remove VarInfo and replace it with SimpleVarInfo?
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.
Markus can probably say more, but I don't think the choice is between SVI and VI. The structs are actually the same except that SVI carries an extra field to store a transformation (which would typically be part of VI's metadata field).
DynamicPPL.jl/src/simple_varinfo.jl
Lines 188 to 196 in 052bc19
| struct SimpleVarInfo{NT,Accs<:AccumulatorTuple where {N},C<:AbstractTransformation} <: | |
| AbstractVarInfo | |
| "underlying representation of the realization represented" | |
| values::NT | |
| "tuple of accumulators for things like log prior and log likelihood" | |
| accs::Accs | |
| "represents whether it assumes variables to be transformed" | |
| transformation::C | |
| end |
Lines 106 to 109 in 052bc19
| struct VarInfo{Tmeta,Accs<:AccumulatorTuple} <: AbstractVarInfo | |
| metadata::Tmeta | |
| accs::Accs | |
| end |
I think the complexity lies in what kinds of metadata they carry. SVI code looks simpler because src/simple_varinfo.jl only handles NamedTuple or Dict metadata. VarInfo code looks terrible because src/varinfo.jl mostly deals with Metadata metadata (hence all the generated functions).
So instead of saying removing SVI, maybe it would have been more accurate to say that this is removing NamedTuple and Dict as supported forms of metadata. As far as I can tell it's mostly a coincidence that this code is associated with SVI.
If the aim is to clean up src/varinfo.jl, then what really needs to happen is to replace Metadata with VNV (although VNV has 1.7k lines of code to itself, so IMO that's not exactly clean; but it probably feels better because it's in its own file, more documented, etc.)
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.
(#1105)
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.
IIRC, the plan is to use SimpleVarInfo with VNV and VNT as the unifying tracing data type, largely because SimpleVarInfo has a cleaner API and better documentation. I agree that the differences between SVI and VI aren’t all that significant.
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 think the reason we can currently dispense with SVI but not VI is that Gibbs requires the ability to link some of the variables, and only some. Whereas SVI assumes that either all or none are linked. If not for needing VI for Gibbs, I think we could be pretty close to in fact removing both SVI and VI, if we can just get ValuesAsInModelAccumulator to be as fast as they are (something I hope #1150 will eventually lead to).
mhauru
left a comment
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.
After reading the PR, I'm inclined to request splitting the deletion of SVI into a separate PR, if it's not too much work. Reasons:
- I think it would be good to remove DynamicTransform and maybe some other stuff that is no longer needed in the same go, to not leave dead code behind to confuse us later.
- I foresee wanting to revert the removal of SVI to benchmark VNT against it at some point, and thus would be good to have it all in a single commit, or a range of back-to-back commits.
Otherwise broadly happy with this, some naming questions.
| julia> model = demo(); | ||
| julia> vi = SimpleVarInfo(x=1.0) |
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.
Does the StaticTransform stuff not work with VarInfo?
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 don't think so. SimpleVarInfo has a field for the transformation
DynamicPPL.jl/src/simple_varinfo.jl
Lines 194 to 195 in 052bc19
| "represents whether it assumes variables to be transformed" | |
| transformation::C |
but VarInfo doesn't (transformation is done on a per-variable basis). It will always hit this method:
Lines 162 to 165 in 052bc19
| # NOTE: This is kind of weird, but it effectively preserves the "old" | |
| # behavior where we're allowed to call `link!` on the same `VarInfo` | |
| # multiple times. | |
| transformation(::VarInfo) = DynamicTransformation() |
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.
(Not that it matters now, ofc, but I guess this will come up when we discuss SVI :))
src/fasteval.jl
Outdated
|
|
||
| """ | ||
| FastLDF( | ||
| DynamicPPL.fast_evaluate!!( |
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.
Above I raised a comment about whether this needs to be exported. I also wonder even if it's not exported whether it could have a more descriptive name. If I would come across this, I would think "if fast_evaluate!! is fast, why does evaluate!! exist then". "Fast" feels like an implementation thing and maybe the more interface-oriented question is "what does evaluate do that this doesn't", or the other way around.
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.
Technically, it doesn't need to be exported. I would say the main reason why this exists is to save on a lot of code repetition. It's needed upstream in Turing as well (e.g. in Prior() sampling) so I think it is a good idea to have a method. I see the point about the name though; it's not very meaningful except to you and I.
In many ways, I think the point of this method is really to generate a set of accumulators given an initialisation strategy. So one could say init_accs!! maybe?
Or, even more Julian (although antithetical to my own sensibilities :) - but it's conceptually similar enough that I actually quite like it), is to overload DynamicPPL.init!!(...) (see current definition here) for AccumulatorTuple? It might be a bit weird in that it would take an AccumulatorTuple (or NTuple{N,<:AbstractAccumulator}) and return an OnlyAccsVarInfo, but I reckon that's fine.
If we wanted to make it more consistent, we could make AccumulatorTuple subtype AbstractVarInfo directly, e.g.
DynamicPPL.getaccs(at::AccumulatorTuple) = at
DynamicPPL.setaccs!!(::AccumulatorTuple, new_at::AccumulatorTuple) = new_atI would say that technically it should not subtype AbstractVarInfo but maybe there should be a broader supertype, AbstractContainsAccs, and AbstractVarInfo should be a subtype of that. I can't say I'm bothered enough to change that.
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.
we could make
AccumulatorTuplesubtypeAbstractVarInfodirectly
I've just gone ahead and done this now. What used to be
fast_evaluate!!(model, strategy, accs)is now simply the existing function
init!!(model, accs, strategy)There is actually a slight difference in code, which is that init!! will call resetaccs!!. I thought that this might cause some slowdown, but I benchmarked it and it's nonexistent / swallowed by benchmark noise anyway. So I'm quite pleased with this new setup.
The only issue seems to be Enzyme is a bit unhappy, but I think that's something that can be resolved separately.
I'm aware I did this quite impulsively without giving time for discussion, so if you don't like it / have another idea, please tell me, I won't be annoyed.
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.
OK, very sadly, I ran into method ambiguities. In particular, at[:] was not well-defined because getindex(::AbstractVarInfo, ::Colon) says "get all the values", but getindex(::AccumulatorTuple, idx) says "get the accumulators". Obviously the ambiguity itself could be resolved manually, but there's a deeper semantic difference, so I didn't feel comfortable with doing that.
So we're back to using OnlyAccsVarInfo, but we can keep using init!! instead of fast_evaluate!!. Sorry about the rollercoaster.
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.
Okay, even that failed. The problem is that init!! doesn't contain the TSVI-acc-eltype code (which is why CI is failing now). I copied that code into init!!, and that just absolutely killed performance, trivial model took 100 µs. No amount of @inline could get it to work. Frustrating.
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.
Damn, I liked this solution.
| @@ -1,49 +0,0 @@ | |||
| using Test, DynamicPPL, ADTypes, LogDensityProblems, ForwardDiff | |||
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 take it that tests/fasteval.jl covers everything previously done here and in ad.jl?
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.
Yup, that's the idea. Actually looking at this now, I realise I forgot to test some aspects of the LogDensityProblems interface. I'll add those tests in.
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.
Added.
b1368dd to
0c3ea56
Compare
0c3ea56 to
2f5ae65
Compare
src/accumulators.jl
Outdated
|
|
||
| """ | ||
| AccumulatorTuple{N,T<:NamedTuple} | ||
| AccumulatorTuple{N,T<:NamedTuple} <: AbstractVarInfo |
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.
It’s interesting that the accumulator mechanism evolved into a generalisation of VarInfos.
11f1770 to
a0331cd
Compare
dfb27f4 to
7108ddd
Compare
6fd177a to
cf33cff
Compare
cf33cff to
d1c002f
Compare
|
Alright, after some experimentation I think I managed to move the definition of I think any subsequent changes to this need to be done in quite careful, small steps, since the performance characteristics seem genuinely quite fragile towards refactoring. That makes me quite displeased, but I guess that's the cost of caring about performance. The SVI removal is rolled back now. Finally, regarding file names: I would be very much on board with renaming both |
|
(BTW, the first commit is the big one, but that's the same commit as before — I had to rebase on breaking hence the force push includes that commit. Only the two smaller later ones are new since the last review.) |
mhauru
left a comment
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.
Very pleased with this, thanks. Happy to merge after the renaming of files (or rename them in another PR, whichever you prefer).
Will the fragility of performance get better once TSVI is opt-in, and the num_threads > 1 check is replaced with something that can be evaluated at compile time? Also, even if it doesn't, I presume performance won't be worse than it was with the old LDF, just maybe roughly the same?
Possibly. That's the next thing to check... it might get better or worse! I tried dabbling with it but didn't manage to get anywhere. I think it'll be easier when I'm not juggling two changes at once though. |
This PR replaces
LogDensityFunctionwithFastLDF.This PR, at first, also removed SimpleVarInfo. This has been separated into a separate PR, but the rationale for removing SVI is detailed here.
SVI
SimpleVarInfo
I would argue that the main purpose of SVI was for performance when evaluating a model with NamedTuple or Dict parameters:
However, exactly the same thing can be accomplished now with the combination of
InitFromParams+OnlyAccsVarInfo:Indeed, this strategy is on par with SVI for the NamedTuple case and faster than SVI for the Dict case (see benchmarks on #1125; performance characteristics on this PR are the same).
The other context in which SVI was useful was evaluation with vector parameters, but that's handled by FastLDF. Thus, my conclusion is that SVI is no longer needed.
Furthermore, because SVI is gone, I believe
DynamicTransformation,StaticTransformation, andmaybe_invlink_before_eval!!can also go. However, we'll leave that for another time.I looked through GitHub for usage of SimpleVarInfo, and it's only in DPPL, Turing, Mooncake benchmarks (trivially fixed once FastLDF is released), and https://github.com/epimap/Epimap.jl-public and https://github.com/marius311/MuseInference.jl, which haven't been updated in a while.