-
-
Notifications
You must be signed in to change notification settings - Fork 187
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
Reuse intermediate computations in distributions part 2 #1752
Conversation
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
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.
This is only a partial review, but I wanted to stop and ask a question before finishing it.
There seem to be a lot of logic changes with the templates. Presumably before we spent an unnecessary amount of time computing things that don't matter.
Is this all being tested somewhere?
Like are the gradients of gamma_lcdf(y, a, b)
being tested for all argument combinations? Like:
gamma_lcdf(double, double, double);
gamma_lcdf(double, double, var);
..
gamma_lcdf(var, var, var);
Etc. Does the distribution test framework do that?
All these are tested in the distribution tests. For chi_square_lcdf, for example, all the following are being tested:
Same for I'm going to push a further commit to ensures that the Thanks for looking at this PR too! |
Thanks for checking! |
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
Should this branch be tested by all the models in the cmdstan performance test suit? I only say that because I've tried one of these before that led to a revert |
The code here looks good (tests pass and looking over it there's nothing obviously wrong), but I'm worried (as Steve points out) that we've made changes to these distribution functions before and it's broken stuff downstream unexpectedly. Regarding this scope/objectives of pull/how to get it merged, I have a few questions:
It looks like the point of these changes is to make the lpdfs faster in situations where not all of the arguments are autodiff variables (and so there are optional calculations). Is that closer to the mark? I guess the additional question here is how will I know the problem fixed?
I'll look into #3 myself (feel free to add links if you know about stuff). #1 and #2 are for you @mcol. |
My plan is to cover the large majority of distributions, excluding the multivariate distributions and the glms (for both these types of distributions, the code is quite different from the rest, and I'm not familiar with that). If we go with PRs of sizes such as this and #1744 (which seems a reasonable size to me, but let me know if smaller would be desirable), then we will have a part 3 and a part 4. Note that #1758 will reduce the size of these PRs, so I will wait until it goes in before I pick this one up again. This set of PRs does indeed more that what #1230 required. I can open a new issue to describe that, if that's what you'd like to see. Overall, this is not motivated by performance gains, as I expect them to be generally tiny if measurable at all, but from the attempt to reuse some intermediate computations and simplify existing ones. In a few cases some computations can be avoided for non-autodiff types, but those are the minority. |
Just talk them out here for now. We can just copy-paste them over to an issue easily.
Oh, is it for numerical reasons? I don't think simplifying these things just for the sake of simplification really justifies the work or dangers, honestly. |
This is an example of what I mean by simplification, from stan/math/prim/prob/chi_square_cdf.hpp (the first one in the diff):
What's going on is the following:
In this example, only the last point could potentially change the numerics, and only skipping the extra There may be cases in which what's going on is a bit more involved than this: I could go and find an example if you'd find it helpful. |
Yeah the numbers make sense and weren't too bad to check. The things that scare me are the template logic/the VectorBuilder logic/the Looking at the pull request that got reverted for Steve, I think the culprit line is: https://github.com/stan-dev/math/pull/1331/files#diff-565dac80cbb935e5597e584799cc9220R76
|
That line is part of the problem. In case of Steve's bug, I think what happened is that the normalizing constants were originally computed in three blocks:
Further down, those terms were summed up again respecting those In the buggy version, they got computed only if In general, the rule for the For example, looking at this code block (again, the first I found):
Before it was run only if As for moving these check out of for loops, that should be neutral. Both examples below will do the same amount of work as the
Sorry for the long message, especially because I'm probably telling you stuff you already know by heart! |
Good point. Our problems are with
So if
So we can compute K at a couple different values of x and make sure they're the same. This would have caught Steve's bug (f in that case was constant, but g would have changed).
I think there is a bug in the probability test framework in handling 3 (#1763). I think the probability test framework should be doing 4 but I didn't check.
I don't :D. This is why I'm so scared to move forward with this if it's purely code-style changes. We're really playing with fire. Do you know how the bug you found in #1662 got through the testing framework? I see that the glms aren't tested in the testing framework so it's no surprise that bugs made it through there. That's a problem. |
#1662 was caused by VectorBuilder loops that ran for the wrong number of times if one of the parameters was a vector and the rest were not. The distribution tests admittedly contains test for this case, but perhaps there's a subtle bug there too? |
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
@mcol if you get a chance, mind taking a look at the test framework to see if this is something it tests for? If it doesn't, that's okay, just report back and we'll make an issue. If it does, then presumably there's another bug with the test framework? |
@bbbales2 There's a |
@mcol is there an obvious way to change it so that it goes through multiple values? And if so, does it catch the #1662 error? You can run specific probability tests with code like:
which is much faster than running them all. |
@bbbales2, mind taking a few minutes to see if your comments have been addressed? (Either confirm the PR shouldn't be in, approve the PR, or remove the review.) |
@syclik yeah sorry. I originally hesitated on this pull requestion because it touches a lot of difficult code and so I was scared a cleanup for the sake of a cleanup is kinda risky cause something might break. The fear was that shuffling things around might break something that the tests don't catch. Even though we think our tests are fairly comprehensive, we found a bug in the test framework in the process of reviewing this code: #1763 But now I'm thinking the reverse logic applies as well. If someone goes through and shuffles around the code they might also find bugs we didn't notice before. And it is useful when people do this. So I think I should accept this if tests pass and the code looks good. What's your opinion on this? I think I accept it if it passes tests (and this goes through) and I review it -- I think I only made it part way through the first roung. |
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.
Sorry for the delay @mcol, finished looking through this. Looks good , a couple questions though. The only thing I'm really concerned about are the negative infinity gradients at infinity. I assume those should be zero.
The half_nu vs half_nu_dbl thing just looked weird to me but I suspect I'm missing something.
Ignore the half_nu comments. There's nothing wrong with what's there.
I'm gonna take the question here: #1752 (comment) to a separate thread so it doesn't hold this up.
@mcol any chance you could take a look at the Edit: I just don't think the gradients of any CDF-like thing will be infinity at infinity because the CDF limits to a constant 1.0 or 0.0 here. |
All those infinity cases were pre-existing, I only touch those lines for variable renames or some similar cleanups. Since those you pointed out are lccdfs, at infinity they will take on the value of log(0), which is negative infinity. At least, that's how I justified to myself that code and kept it around. If that's not correct, then there must be something that we are not testing or not testing correctly. |
@mcol oh yeah you are right on all counts |
Merged in the new develop since this has been sitting awhile (just wanna make sure nothing went funky). I'll merge when the tests pass thanks! |
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
@bbbales2 you have reviewed this thoroughly and want to merge it? I am not sure if you can given that you pushed commits, so let me know if you need a hand. |
Should we wait for the fixes to the testing framework before approving this? (i.e. this would wait till the next release most likely) |
@SteveBronder well I was thinking really conservatively on this back in March and that stalled the pull request quite a bit (though we did find a couple problems with the test framework). I don't think we'll ever be totally happy with the distribution tests. There's at least one fix (#1764) that'll probably make it in this release (and will presumably catch in merge any #1764 bugs this introduces if it does). But there are also problems/weaknesses with the tests that won't be fixed this release: #1978 and #1976 And that's just the stuff I know about. I'm more leaning now we accept what's passing our tests, otherwise it's kindof an impossible moving bar to hop over. |
You guys decide on this one, please. |
imo I'd rather wait till the distribution tests are beefier till we merge this |
Sure, but we should decide what beefier is so we don't just leave it hanging. |
By "beefier" I just meant merging in #1764. Ben I can look this over if you want another set of eyes but otherwise I'm fine with it (though I'd classify this as not a bugfix so it would wait till the next release) |
We can wait. I reran the tests after 1764 merged and it's green light. We can press the merge button next Tuesday. |
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
Is this good to go now? |
I'm working on the test framework now so we can just merge it after #1989 is through. I think it would pass everything fine, but I am working on the test framework (and there are problems with it I'm finding), so this may as well wait. I'm trying to get that done asap. |
Cool cool. Test away! |
@mcol The distributions in this pull request ended up all getting rewritten before I got the tests in place (still open: #2085). I guess this in particular didn't go through because my testing standards lowered between July and now. Apologies for that. Mind if I close this (I'll go ahead and do it in a few days if I don't hear anything back)? |
No problem, let's close this now! |
This is the second of a few PRs that aim to clean up the distributions so that we make better use of intermediate computations and composed functions.
This covers the following distributions:
Tests
None, this is just cleanup.
Side Effects
None.
Release Notes
Cleaned up implementations of
chi_square
,gamma
,inv_chi_square
,inv_gamma
, andscaled_inv_chi_square
to make use of intermediate calculations more.Checklist
Math issue: Make use of composed functions and temporaries #1230
Copyright holder: Marco Colombo
The copyright holder is typically you or your assignee, such as a university or company. By submitting this pull request, the copyright holder is agreeing to the license the submitted work under the following licenses:
- Code: BSD 3-clause (https://opensource.org/licenses/BSD-3-Clause)
- Documentation: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
the basic tests are passing
./runTests.py test/unit
)make test-headers
)make test-math-dependencies
)make doxygen
)make cpplint
)the code is written in idiomatic C++ and changes are documented in the doxygen
the new changes are tested