Skip to content
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

Reduce ridge filters memory footprints #6509

Merged
merged 8 commits into from
Sep 20, 2022

Conversation

tkumpumaki
Copy link
Contributor

@tkumpumaki tkumpumaki commented Sep 8, 2022

Description

Reduce ridge filters memory footprints by not storing intermediate results for final max computation. Instead after each sigma take max between last and current sigma result.

Closes #6507

For reviewers

  • Check that the PR title is short, concise, and will make sense 1 year
    later.
  • Check that new functions are imported in corresponding __init__.py.
  • Check that new features, API changes, and deprecations are mentioned in
    doc/release/release_dev.rst.
  • There is a bot to help automate backporting a PR to an older branch. For
    example, to backport to v0.19.x after merging, add the following in a PR
    comment: @meeseeksdev backport to v0.19.x
  • To run benchmarks on a PR, add the run-benchmark label. To rerun, the label
    can be removed and then added again. The benchmark output can be checked in
    the "Actions" tab.

@pep8speaks
Copy link

pep8speaks commented Sep 8, 2022

Hello @tkumpumaki! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

Line 113:80: E501 line too long (81 > 79 characters)
Line 126:80: E501 line too long (88 > 79 characters)

Line 462:22: E127 continuation line over-indented for visual indent

Comment last updated at 2022-09-11 12:21:25 UTC

Copy link
Member

@mkcor mkcor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tkumpumaki thank you so much for your contribution!

@mkcor
Copy link
Member

mkcor commented Sep 9, 2022

@scikit-image/core since memory use is greatly improved with this PR, should we include a benchmark?

Copy link
Member

@rfezzani rfezzani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent! Thank you @tkumpumaki 😉
I simply suggest a small code formatting, otherwise every think seems fine. @mkcor, not sure if a benchmark is necessary, but up to other @scikit-image/core members 🙂

skimage/filters/ridges.py Outdated Show resolved Hide resolved
@lagru
Copy link
Member

lagru commented Sep 9, 2022

not sure if a benchmark is necessary, but up to other https://github.com/orgs/scikit-image/teams/core members

I'd say yes. @tkumpumaki let us know if you want to do that yourself or we will happily do so for you if you are not that familiar with asv.

@tkumpumaki
Copy link
Contributor Author

not sure if a benchmark is necessary, but up to other https://github.com/orgs/scikit-image/teams/core members

I'd say yes. @tkumpumaki let us know if you want to do that yourself or we will happily do so for you if you are not that familiar with asv.

I don't have a slightest clue how to test memory usage with the asv as python is not my main weapon. ;)
I would guess that CPU time is not that different as same amount of computation is done.

@grlee77
Copy link
Contributor

grlee77 commented Sep 9, 2022

I don't have a slightest clue how to test memory usage with the asv as python is not my main weapon. ;)

no worries @tkumpumaki. @lagru, are you interested in adding the benchmark? If so that is great and we can wait for that, but if no one plans to work on it soon let's not hold up the PR over it.

Certainly the memory usage will be lower with this change and I doubt there is a substantial change in runtime. There will be more calls to maximum, but each one does less work and the maximum operations are not the most expensive operations in this function in any case. Even if there were a small performance decrease, I would still vote to merge this for the clear memory efficiency gain!

@lagru
Copy link
Member

lagru commented Sep 9, 2022

@grlee77 happy to. I'll do it in a minute.

@lagru
Copy link
Member

lagru commented Sep 9, 2022

Ony my machine
$ asv continuous main 7535320f661c2734321edbfe24f9fb3e5ae3bc6f -b RidgeFilters
· Creating environments
· Discovering benchmarks
·· Uninstalling from virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
·· Installing 7535320f <ridge-operator-less-memory-use~1> into virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
· Running 10 total benchmarks (2 commits * 1 environments * 5 benchmarks)
[  0.00%] · For scikit-image commit 7535320f <ridge-operator-less-memory-use~1> (round 1/1):
[  0.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 10.00%] ··· benchmark_filters.RidgeFilters.peakmem_frangi                                        394M
[ 20.00%] ··· benchmark_filters.RidgeFilters.peakmem_hessian                                       394M
[ 30.00%] ··· benchmark_filters.RidgeFilters.peakmem_meijering                                     380M
[ 40.00%] ··· benchmark_filters.RidgeFilters.peakmem_sato                                          269M
[ 50.00%] ··· benchmark_filters.RidgeFilters.peakmem_setup                                         143M
[ 50.00%] · For scikit-image commit 6342ec59 <main> (round 1/1):
[ 50.00%] ·· Building for virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
[ 50.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 60.00%] ··· benchmark_filters.RidgeFilters.peakmem_frangi                                        528M
[ 70.00%] ··· benchmark_filters.RidgeFilters.peakmem_hessian                                       523M
[ 80.00%] ··· benchmark_filters.RidgeFilters.peakmem_meijering                                     412M
[ 90.00%] ··· benchmark_filters.RidgeFilters.peakmem_sato                                          332M
[100.00%] ··· benchmark_filters.RidgeFilters.peakmem_setup                                         145M
before           after         ratio
[6342ec59]       [7535320f]
<main>           <ridge-operator-less-memory-use~1>
-            332M             269M     0.81  benchmark_filters.RidgeFilters.peakmem_sato
-            523M             394M     0.75  benchmark_filters.RidgeFilters.peakmem_hessian
-            528M             394M     0.75  benchmark_filters.RidgeFilters.peakmem_frangi

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.
PERFORMANCE INCREASED.

Co-authored-by: Riadh Fezzani <rfezzani@gmail.com>
@lagru
Copy link
Member

lagru commented Sep 9, 2022

@tkumpumaki, I pushed to your branch. To avoid conflicts, I recommend pulling these changes if and before you add commits yourself again: git pull origin ridge-operator-less-memory-use (assuming your fork is associated with origin).

@grlee77
Copy link
Contributor

grlee77 commented Sep 9, 2022

The stochastic RANSAC failure on CI is unrelated.

@grlee77
Copy link
Contributor

grlee77 commented Sep 9, 2022

Thanks for the quick update, @lagru . While we are adding the benchmarks, can you also add time_meijering, etc. as well?

@lagru
Copy link
Member

lagru commented Sep 11, 2022

It seems that the label run-benchmarks triggers something but the workflow is shown as "Skipped" nevertheless. Does someone know why?

@lagru
Copy link
Member

lagru commented Sep 11, 2022

My machine, with CPU benchmarks added
$ asv continuous main HEAD -b RidgeFilters
· Creating environments
· Discovering benchmarks
·· Uninstalling from virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
·· Installing 1d0e9d37 <pr6509-ridge-operator-less-memory-use> into virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
· Running 18 total benchmarks (2 commits * 1 environments * 9 benchmarks)
[  0.00%] · For scikit-image commit bfcb6298 <main> (round 1/2):
[  0.00%] ·· Building for virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv..
[  0.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 16.67%] ··· Running (benchmark_filters.RidgeFilters.time_frangi--)...
[ 25.00%] ··· Running (benchmark_filters.RidgeFilters.time_sato--).
[ 25.00%] · For scikit-image commit 1d0e9d37 <pr6509-ridge-operator-less-memory-use> (round 1/2):
[ 25.00%] ·· Building for virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
[ 25.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 41.67%] ··· Running (benchmark_filters.RidgeFilters.time_frangi--)...
[ 50.00%] ··· Running (benchmark_filters.RidgeFilters.time_sato--).
[ 50.00%] · For scikit-image commit 1d0e9d37 <pr6509-ridge-operator-less-memory-use> (round 2/2):
[ 50.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 52.78%] ··· benchmark_filters.RidgeFilters.peakmem_frangi                                        394M
[ 55.56%] ··· benchmark_filters.RidgeFilters.peakmem_hessian                                       394M
[ 58.33%] ··· benchmark_filters.RidgeFilters.peakmem_meijering                                     380M
[ 61.11%] ··· benchmark_filters.RidgeFilters.peakmem_sato                                          268M
[ 63.89%] ··· benchmark_filters.RidgeFilters.peakmem_setup                                         143M
[ 66.67%] ··· benchmark_filters.RidgeFilters.time_frangi                                        1.35±0s
[ 69.44%] ··· benchmark_filters.RidgeFilters.time_hessian                                       1.36±0s
[ 72.22%] ··· benchmark_filters.RidgeFilters.time_meijering                                     4.89±0s
[ 75.00%] ··· benchmark_filters.RidgeFilters.time_sato                                          935±7ms
[ 75.00%] · For scikit-image commit bfcb6298 <main> (round 2/2):
[ 75.00%] ·· Building for virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
[ 75.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 77.78%] ··· benchmark_filters.RidgeFilters.peakmem_frangi                                        527M
[ 80.56%] ··· benchmark_filters.RidgeFilters.peakmem_hessian                                       527M
[ 83.33%] ··· benchmark_filters.RidgeFilters.peakmem_meijering                                     448M
[ 86.11%] ··· benchmark_filters.RidgeFilters.peakmem_sato                                          336M
[ 88.89%] ··· benchmark_filters.RidgeFilters.peakmem_setup                                         145M
[ 91.67%] ··· benchmark_filters.RidgeFilters.time_frangi                                        1.37±0s
[ 94.44%] ··· benchmark_filters.RidgeFilters.time_hessian                                       1.37±0s
[ 97.22%] ··· benchmark_filters.RidgeFilters.time_meijering                                  4.88±0.01s
[100.00%] ··· benchmark_filters.RidgeFilters.time_sato                                          941±4ms
before           after         ratio
[bfcb6298]       [1d0e9d37]
<main>           <pr6509-ridge-operator-less-memory-use>
-            448M             380M     0.85  benchmark_filters.RidgeFilters.peakmem_meijering
-            336M             268M     0.80  benchmark_filters.RidgeFilters.peakmem_sato
-            527M             394M     0.75  benchmark_filters.RidgeFilters.peakmem_hessian
-            527M             394M     0.75  benchmark_filters.RidgeFilters.peakmem_frangi

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.
PERFORMANCE INCREASED.

@grlee77
Copy link
Contributor

grlee77 commented Sep 16, 2022

Hi @tkumpumaki, I merged a larger refactor of ridge filters by @anntzer via #6446 today. It has created conflicts here, but more importantly it had also refactored these same sections and removed the upfront memory allocations!

Given that, it may be that no code changes are necessary in ridge.py for this PR? In that case, please just update the issue title to something like "add ridge filter benchmarks".

My apologies for not realizing the full overlap between these two and pointing it out earlier. Let us know if you need help resolving conflicts here.

@anntzer
Copy link
Contributor

anntzer commented Sep 16, 2022

That PR removed the large upfront memory allocations but still first computes the filters for all sigmas before taking the max (so there's a large memory use just before the max is taken); it may still be useful to replace that by computing the pairwise maxes after each sigma computation.

@tkumpumaki
Copy link
Contributor Author

I merged main branch back to this branch and replaced ridges.py with the new one from the main. Then added memory fix again.

@lagru
Copy link
Member

lagru commented Sep 20, 2022

I'm kind of confused by the commit hash that is used by the benchmark workflow which is d3e5df6. It looks like a merge commit but is not listed on this PR...

@lagru
Copy link
Member

lagru commented Sep 20, 2022

But it shows an decreased memory use locally:

Click to expand
$ asv continuous --show-stderr --split main pr6509-ridge-operator-less-memory-use -b RidgeFilters
· Creating environments
· Discovering benchmarks
·· Uninstalling from virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
·· Installing 4a792387 <pr6509-ridge-operator-less-memory-use> into virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
· Running 18 total benchmarks (2 commits * 1 environments * 9 benchmarks)
[  0.00%] · For scikit-image commit daa991ad <main> (round 1/2):
[  0.00%] ·· Building for virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv................................................................................
[  0.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 16.67%] ··· Running (benchmark_filters.RidgeFilters.time_frangi--)...
[ 25.00%] ··· Running (benchmark_filters.RidgeFilters.time_sato--).
[ 25.00%] · For scikit-image commit 4a792387 <pr6509-ridge-operator-less-memory-use> (round 1/2):
[ 25.00%] ·· Building for virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
[ 25.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 41.67%] ··· Running (benchmark_filters.RidgeFilters.time_frangi--)...
[ 50.00%] ··· Running (benchmark_filters.RidgeFilters.time_sato--).
[ 50.00%] · For scikit-image commit 4a792387 <pr6509-ridge-operator-less-memory-use> (round 2/2):
[ 50.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 52.78%] ··· benchmark_filters.RidgeFilters.peakmem_frangi                                        332M
[ 55.56%] ··· benchmark_filters.RidgeFilters.peakmem_hessian                                       332M
[ 58.33%] ··· benchmark_filters.RidgeFilters.peakmem_meijering                                     279M
[ 61.11%] ··· benchmark_filters.RidgeFilters.peakmem_sato                                          268M
[ 63.89%] ··· benchmark_filters.RidgeFilters.peakmem_setup                                         145M
[ 66.67%] ··· benchmark_filters.RidgeFilters.time_frangi                                      5.49±0.2s
[ 69.44%] ··· benchmark_filters.RidgeFilters.time_hessian                                    5.58±0.05s
[ 72.22%] ··· benchmark_filters.RidgeFilters.time_meijering                                  5.18±0.04s
[ 75.00%] ··· benchmark_filters.RidgeFilters.time_sato                                       4.80±0.03s
[ 75.00%] · For scikit-image commit daa991ad <main> (round 2/2):
[ 75.00%] ·· Building for virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv.
[ 75.00%] ·· Benchmarking virtualenv-py3.10-cython-numpy1.23-pooch-pythran-scipy-virtualenv
[ 77.78%] ··· benchmark_filters.RidgeFilters.peakmem_frangi                                        382M
[ 80.56%] ··· benchmark_filters.RidgeFilters.peakmem_hessian                                       382M
[ 83.33%] ··· benchmark_filters.RidgeFilters.peakmem_meijering                                     329M
[ 86.11%] ··· benchmark_filters.RidgeFilters.peakmem_sato                                          318M
[ 88.89%] ··· benchmark_filters.RidgeFilters.peakmem_setup                                         143M
[ 91.67%] ··· benchmark_filters.RidgeFilters.time_frangi                                     5.14±0.03s
[ 94.44%] ··· benchmark_filters.RidgeFilters.time_hessian                                    5.35±0.09s
[ 97.22%] ··· benchmark_filters.RidgeFilters.time_meijering                                  5.13±0.02s
[100.00%] ··· benchmark_filters.RidgeFilters.time_sato                                        4.55±0.1s
before           after         ratio
[daa991ad]       [4a792387]
<main>           <pr6509-ridge-operator-less-memory-use>
-            382M             332M     0.87  benchmark_filters.RidgeFilters.peakmem_frangi
-            382M             332M     0.87  benchmark_filters.RidgeFilters.peakmem_hessian
-            329M             279M     0.85  benchmark_filters.RidgeFilters.peakmem_meijering
-            318M             268M     0.84  benchmark_filters.RidgeFilters.peakmem_sato

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.
PERFORMANCE INCREASED.

@lagru lagru requested review from rfezzani and mkcor September 20, 2022 10:52
Copy link
Member

@rfezzani rfezzani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, simply recommending the use of np.zeros_like when possible.

skimage/filters/ridges.py Outdated Show resolved Hide resolved
skimage/filters/ridges.py Outdated Show resolved Hide resolved
skimage/filters/ridges.py Outdated Show resolved Hide resolved
Co-authored-by: Riadh Fezzani <rfezzani@gmail.com>
@lagru lagru merged commit d549c79 into scikit-image:main Sep 20, 2022
@lagru
Copy link
Member

lagru commented Sep 20, 2022

Thanks everyone!

@mkcor
Copy link
Member

mkcor commented Sep 24, 2022

I'm kind of confused by the commit hash that is used by the benchmark workflow which is d3e5df6. It looks like a merge commit but is not listed on this PR...

Right... It looks as if CI, instead of running directly for the latest commit (i.e., 4a79238), would merge this very commit into an ad hoc branch before running it.

@jarrodmillman jarrodmillman added this to the 0.20 milestone Oct 4, 2022
grlee77 added a commit to grlee77/cucim that referenced this pull request Oct 28, 2022
rapids-bot bot pushed a commit to rapidsai/cucim that referenced this pull request Nov 16, 2022
…y footprint) (#423)

related to #419

A large overhaul of the ridge filters, addressing inaccuracies and errors has been implemented for scikit-image 0.20. This PR ports the same changes to these functions to cuCIM.

upstream PRs: 
 - scikit-image/scikit-image#6149
 - scikit-image/scikit-image#6440 
 - scikit-image/scikit-image#6446
 - scikit-image/scikit-image#6509

These fix various bugs, simplify the implementation and reduce the memory footprint

Authors:
  - Gregory Lee (https://github.com/grlee77)

Approvers:
  - Gigon Bae (https://github.com/gigony)

URL: #423
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Sato filter memory usage with multiple sigmas
8 participants