Single threaded split#85
Conversation
Codecov Report
@@ Coverage Diff @@
## master #85 +/- ##
==========================================
- Coverage 96.96% 96.74% -0.22%
==========================================
Files 10 10
Lines 1053 1076 +23
==========================================
+ Hits 1021 1041 +20
- Misses 32 35 +3
Continue to review full report at Codecov.
|
NicolasHug
left a comment
There was a problem hiding this comment.
Looks good in general! Thanks!
Made a few comments.
Waiting for @ogrisel input but maybe it would be interesting to have a new benchmark script comparing the memory usage with parallel_splitting=True and parallel_splitting=False.
| def split_indices_single_thread(context, split_info, sample_indices): | ||
| """Split samples into left and right arrays. | ||
|
|
||
| This implementation requires less memory than the parallel version. |
There was a problem hiding this comment.
Maybe add a comment about using Hoare's partition scheme, just for reference
There was a problem hiding this comment.
Ok, I didn't know it had a name, I'm ok with adding it, but did you check that it is effectively the same algo?
There was a problem hiding this comment.
Yes I'm pretty sure it is https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme
| ---------- | ||
| context : SplittingContext | ||
| The splitting context | ||
| split_ingo : SplitInfo |
There was a problem hiding this comment.
split_info (my fault ^^)
can you also fix it at the other occurrence please?
| i += 1 | ||
| j -= 1 | ||
| return (sample_indices[:i], | ||
| sample_indices[i:]) |
There was a problem hiding this comment.
return sample_indices[:i], sample_indices[i:] ?
| node = heappop(self.splittable_nodes) | ||
|
|
||
| tic = time() | ||
| split_indices = split_indices_parallel if self.parallel_splitting else split_indices_single_thread |
There was a problem hiding this comment.
I think we should fork in SplittingContext instead of in the grower. We probably don't need grower.parallel_splitting.
That is, call SplittingContext.split_indice() in the grower, and in splitting.py do:
def split_indice(...)
if self.parallel_splitting:
return ...
else:
return ...| assert samples_left.shape[0] == si_root.n_samples_left | ||
| assert samples_right.shape[0] == si_root.n_samples_right | ||
|
|
||
| samples_left_single_thread, samples_right_single_thread = split_indices_single_thread( |
There was a problem hiding this comment.
Maybe instead parametrize this test with parallel_split=True and parallel_split=False, so that both methods go through exactly the same tests (though I agree your current test also covers this implicitly)
ogrisel
left a comment
There was a problem hiding this comment.
Some more comments on top of @NicolasHug's review.
| n_iter_no_change=None, | ||
| random_state=0, | ||
| verbose=1) | ||
| verbose=1, parallel_splitting=False) |
There was a problem hiding this comment.
Maybe you can expose this a commandline flag to make it easy to profile with mprof run benchmarks/bench_higgs_boson.py --disable-parallel-splitting (using memory_profiler).
d8585bb to
e84cdc3
Compare
| @@ -304,6 +312,31 @@ def split_indices(context, split_info, sample_indices): | |||
| return (sample_indices[:right_child_position], | |||
| sample_indices[right_child_position:]) | |||
|
|
|||
There was a problem hiding this comment.
PEP8: you need 2 blank lines to separate top level functions.
NicolasHug
left a comment
There was a problem hiding this comment.
Few more comments,
Also please see the pep8 issues on travis, or locally run
flake8 pygbm tests examples benchmarks
| return (sample_indices[:right_child_position], | ||
| sample_indices[right_child_position:]) | ||
|
|
||
| @njit(parallel=False) |
There was a problem hiding this comment.
You can just use @njit, parallelism is off by default
| @njit(parallel=False) | |
| @njit |
| sample_indices[i], sample_indices[j] = sample_indices[j], sample_indices[i] | ||
| i += 1 | ||
| j -= 1 | ||
| return (sample_indices[:i], sample_indices[i:]) |
There was a problem hiding this comment.
no need for parenthesis
| all_gradients, all_hessians, | ||
| l2_regularization, min_hessian_to_split, | ||
| min_samples_leaf, min_gain_to_split) | ||
| min_samples_leaf, min_gain_to_split, True) |
There was a problem hiding this comment.
Please parametrize this test with True/False instead and remove the checks below
| sample_indices[right_child_position:]) | ||
|
|
||
| @njit(parallel=False) | ||
| def _split_indices_single_threaded(context, split_info, sample_indices): |
There was a problem hiding this comment.
| def _split_indices_single_threaded(context, split_info, sample_indices): | |
| def _split_indices_single_threaded(context, split_info, sample_indices): | |
| # single-threaded partition into left and right arrays (Hoare's partition scheme) |
(continues from #79, will rebase after merge)
Implement what is discussed in #83.
TODO: