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

Non linear peak finding #84

Merged
merged 10 commits into from Nov 6, 2012
Merged

Conversation

MrBago
Copy link
Contributor

@MrBago MrBago commented Oct 9, 2012

We've been talking about this for a little while so, here it is!

@Garyfallidis
Copy link
Contributor

Is this necessary for this release? What about the updated PR for shm.py? I would much prefer to merge shm.py first. Let me know if the nonlinear has to be prioritized for some good reason. Great job, otherwise.

relative_peak_threshold, min_separation_angle)


def _nl_peak_finder(sphere_eval, seeds, fmin, gtol):
"""Non-linear search for peaks from each seed
Copy link
Contributor

Choose a reason for hiding this comment

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

Let me see if I follow the logic of this: sphere_eval is a function that takes a Sphere as its input and returns a number. Here, we initialize the Sphere object with a single vector: theta, phi = x[0], x[1] and it tells us the value of this function in that location in spherical coordinates? In what follows, you get back a 'peak' of this function for every seed that we placed? That seems good. One things to think about is boundary conditions for theta and phi: what happens here when theta, phi go out of their domain (for example, above 2*pi for theta). The Sphere init doesn't seem to check for that, but maybe it should?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You pretty much have the logic down. sphere_eval takes a sphere with N points and returns an array of length N. In this case we create a sphere with one point. The main peak finding function we have in dipy is called local_maxima. It is a discrete peak finding, we use it on line 140 to find the seeds for the non-linear search.

Boundary conditions are not an issue, I believe, because we eventually convert back to Cartesian coordinates and return unit vectors. ie theta=pi, phi={pi, 3pi} will both result in the same unit vector so I don't think we should should have any issues.

@arokem
Copy link
Contributor

arokem commented Oct 9, 2012

Do we have any peak-finding other than this, now that recspeed.peak_finding
has been removed (why was it removed, btw?)

On Tue, Oct 9, 2012 at 11:41 AM, Eleftherios Garyfallidis <
notifications@github.com> wrote:

Is this necessary for this release? What about the updated PR for shm.py?
I would much prefer to merge shm.py first. Let me know if the nonlinear has
to be prioritized for some good reason. Great job, otherwise.


Reply to this email directly or view it on GitHubhttps://github.com//pull/84#issuecomment-9273818.

@MrBago
Copy link
Contributor Author

MrBago commented Oct 9, 2012

The main peak finding function is dipy.reconst.recspeed.local_maxima it returns discrete peaks from a sphere, but sometimes you want the ability to find peaks with better precision than possible with a discrete sphere so in those cases this peak finder is useful. This peak finder makes many calls to sphere_eval, so if sphere_eval is slow, finding it's peaks will be slow.

@@ -162,6 +162,50 @@ def remove_similar_vertices(cnp.ndarray[cnp.float_t, ndim=2, mode='strided'] ver
return unique_vertices[:count].copy()


@cython.boundscheck(False)
@cython.wraparound(False)
def search_descending(cnp.ndarray[cnp.float_t, ndim=1, mode='c'] a,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this faster than np.searchsorted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The short answer is yes. I tried using searchsorted but the overhead was too high, also it ends up looking ugly. The equivalent expression using search sorted is something like (len(a) - a[::-1].searchsorted(relative_threshold * a[0])) or 1. I figured having a dedicated function was cleaner and it allowed me to optimize it using cython.

Copy link
Contributor

Choose a reason for hiding this comment

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

`searchsorted(.., side='left')`` should help

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe searchsorted uses side='left' as default, and I believe that's the side we need. The main issue is the len(a) - a[::-1] part adds a lot of overhead. I don't think numpy has a search descending only search ascending, ie searchsorted.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds like np.searchsorted(-x, -T).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the biggest problem with this is that -x is an O(n) operation so you loose the benefit of doing a O(log(n)) search. It's all moot anyways for two reasons: 1, x tends to be small so this pretty fast no matter how you do it and 2, I like my little function and you're not going to take it away from me ;).

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, @MrBago knows my opinion on this one :)

@stefanv
Copy link
Contributor

stefanv commented Oct 16, 2012

This works beautifully.

I coded up a version that optimized all the variables at the same time, but got exactly the same results without much (any?) speedup.

When I initially tried this, my code broke due to the assumption that spheres store theta/phi as 1D arrays--I submitted a PR against your branch for that, @MrBago

I'm +1 on merging.

# Remove small peaks
n = search_descending(values, relative_peak_threshold)
directions = vertices[:n]
# Remove peaks too close to each-other
Copy link
Contributor

Choose a reason for hiding this comment

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

On a purely aesthetic note, I prefer blank lines between logical sections, but I know this is contradictory to some other members' opinions, so I leave it to the author :)

@stefanv
Copy link
Contributor

stefanv commented Oct 16, 2012

Oh, I believe this warrants using one of the new GitHub emoticons: 👍

self._config = {"sphere": sphere,
"relative_peak_threshold": relative_peak_threshold,
"min_separation_angle": min_separation_angle,
"fmin":fmin, "gtol":gtol}
Copy link
Contributor

Choose a reason for hiding this comment

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

PEP8 spaces

MrBago and others added 2 commits October 17, 2012 11:52
@MrBago
Copy link
Contributor Author

MrBago commented Oct 19, 2012

@stefanv, when you have a sec try running this and see if you're still getting division by zero issues.

@stefanv
Copy link
Contributor

stefanv commented Oct 24, 2012

@MrBago They're still there, unfortunately :/

…it is

harder than I expected to support the fmin function as an argument to the
NonLinearDirectionFinder.  I've hard codded scipy.optimize.fmin as the
optimization function for now and might re-visit this later.
stefanv added a commit that referenced this pull request Nov 6, 2012
@stefanv stefanv merged commit 830e31c into dipy:master Nov 6, 2012
@MrBago MrBago deleted the non-linear_peak_finding branch November 19, 2013 04:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants