Conversation
Only sort the tail values of the array, rather than the whole thing.
|
Is this keeping the largest value smaller than tail values in a correct position? |
|
Hopefully someday my brain will stop making off-by-one errors, but today is not that day. |
|
Maybe I need to rephrase. After your change, how do you determine the largest value that is smaller than the tail values? If you don't sort them, I think you should at least find the largest value among the non-tail values, e.g. with max() function. |
Doesn't the code determine that by sorting the |
|
Ah, I was too tired when checking this and got confused. I'm also confused as off-by-one commit didn't make any change to the code, only change is in json. So how did you fix that off-by-one error? |
Whoops, pushed the wrong change -- this should fix the off-by-one error. (I was accidentally only sorting the tail, rather than sorting from the last element not in the tail.) |
|
Thanks @ParadaCarleton and sorry for not getting to this sooner! I just triggered all the continuous integration tests to run again so let's see if they pass. And yeah, @avehtari I think the latest commit from Carlos fixes the off by one issue, although if you want to double check that would be great. The tests should also catch it since I think we have regression tests that detect any changes to the loo results (and presumably an off by one error would lead to some change in the results). |
|
Actually some tests seem to be failing, so we'll need to look into that: https://github.com/stan-dev/loo/pull/185/checks?check_run_id=3656664234#step:11:150 |
|
Are there benchmarks showing that this is indeed a performance improvement in R? I tried something similar for PSIS.jl and found that in Julia at least it was always slower. e.g. julia> using BenchmarkTools
julia> tail_length(reff, S) = min(cld(S, 5), ceil(Int, 3 * sqrt(S / reff)));
julia> function foo(logw)
S = length(logw)
M = tail_length(1, S)
return sort(logw)[M:S]
end;
julia> function bar(logw)
S = length(logw)
M = tail_length(1, S)
return partialsort(logw, M:S)
end;
julia> logw = randn(1000);
julia> foo(logw) == bar(logw)
true
julia> @btime $foo($logw);
18.822 μs (2 allocations: 15.19 KiB)
julia> @btime $bar($logw);
21.504 μs (1 allocation: 7.94 KiB) |
I benchmarked this and got a major speedup in Julia when I switched to only sorting partially; I assume the difference is to do with Julia's sorting algorithms, which have some large problems with cache misses. Feel free to discuss this with me on Slack. |
You're sorting from the tail length to the end of the array (accidentally sorting everything but the tail). The result is you're asking for almost the whole array to be sorted (~900 instead of ~100 elements), so the constant overhead of |
Good catch! Yes, I'm seeing the same performance improvement you're seeing now. |
Only sort the tail values of the array, rather than the whole thing.