Skip to content

[MRG] Simplify cov code path - #4601

Merged
larsoner merged 9 commits into
mne-tools:masterfrom
agramfort:simplify_cov_code_path
Sep 30, 2017
Merged

[MRG] Simplify cov code path#4601
larsoner merged 9 commits into
mne-tools:masterfrom
agramfort:simplify_cov_code_path

Conversation

@agramfort

@agramfort agramfort commented Sep 25, 2017

Copy link
Copy Markdown
Member

a first attempt to give love to cov code by simplifying code path

you can see that dipole fit and LCMV use compute_whitener while make_inverse_operator is using _get_whitener so does not use scalings and does not back project (using eigvec).

this need further thinking...

.. note:: how a lunch with @dengemann ends up :)

Comment thread mne/cov.py Outdated
# scalings = _handle_default('scalings_cov_rank', scalings)
# W, _, rank = compute_whitener(noise_cov, info, picks=picks, rank=rank,
# scalings=scalings, return_rank=True)
# return W, rank

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'll remove this if travis is happy

Comment thread mne/chpi.py Outdated
scale = _get_whitener_data(info, scale, meg_picks, verbose=False)[0]

scalings = _handle_default('scalings', None)
# WTF is the whitener called scale ! cc @larsoner...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

yes because all it does is scale each channel (it's a diagonal matrix), feel free to change if you want

Comment thread mne/cov.py Outdated

.. versionadded:: 0.15
diag : bool
Use a diagonal approximation of the noise covariance.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

versionadded

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

wait, why do we need this? Why not use make_ad_hoc_cov or noise_cov.as_diag()?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

it's used in whiten_evoked which also has a diag option. I think it's cleaner to do all kind of whitening in the same function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

whiten_evoked shouldn't have the option, either :) Rather than propagate this error, I'd rather deprecate it, or do the logic inside whiten_evoked. Does it really save that much work to have this option?

Comment thread mne/chpi.py Outdated
scale = make_ad_hoc_cov(info, verbose=False)
scale = _get_whitener_data(info, scale, meg_picks, verbose=False)[0]

scalings = _handle_default('scalings', None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

you shouldn't need to do this -- this is only used for cov rank internally by compute_whitener, which will easily pass for this diagonal matrix even if it's not a perfect match for the values make_ad_hoc_cov uses.

Comment thread mne/dipole.py Outdated
# whitener = np.dot(whitener, cov['eigvec'])

whitener, rank = _get_whitener_data(info, cov, picks, verbose=False)
scalings = _handle_default('scalings', None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here, I doubt we really need to do this one. I'd consider it a bugfix not to, as it's a better match with what all other solvers do. Can you try not doing it and see if tests still pass? If they don't it might mean we have some problems with our cov rank scale factors.

@agramfort
agramfort force-pushed the simplify_cov_code_path branch from f35a894 to d93046a Compare September 27, 2017 18:41
Comment thread mne/chpi.py
coils = _prep_mf_coils(info)
scale = make_ad_hoc_cov(info, verbose=False)
scale = _get_whitener_data(info, scale, meg_picks, verbose=False)[0]
diag_cov = make_ad_hoc_cov(info, verbose=False)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this is much clearer.

Comment thread mne/cov.py Outdated
# Omit the zeroes due to projection
eig = noise_cov['eig']
nzero = (eig > 0)
n_nzero = sum(nzero)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe we can avoid these matlab style names like n_zero.

Why not:

n_zero = sum(eig > 0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My bad, just forget what I said. Let's keep it as is.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

However, I think replacing *nzero with *non_zero would be a good idea.

non_zero = (eig > 0)
n_non_zero = sum(non_zero)
# and so on ...

Comment thread mne/cov.py
noise_cov = noise_cov.copy()
noise_cov['data'] = np.diag(np.diag(noise_cov['data']))

scalings = _handle_default('scalings_cov_rank', scalings)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this line is not needed any longer. It anyways reappears further down the road in the cov rank estimation function (which we will probably abolish in the future).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I will keep it for now so you can test I can safely remove it. you need to redo the evaluation you did when you added this.

Comment thread mne/cov.py
pca=False, scalings=scalings)

# Do the back projection
W = np.dot(noise_cov['eigvec'].T, W)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

did we want to make this an option?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What about this one?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

arfff true. But then I change the behavior of existing code and I need more complete testing. LCMV and dipole fit have now used the back projection...

I suggest to add it in another PR what would change the numerics.

I don't want to break anything just before the release without full testing

@codecov-io

codecov-io commented Sep 27, 2017

Copy link
Copy Markdown

Codecov Report

Merging #4601 into master will decrease coverage by 0.06%.
The diff coverage is 100%.

@@            Coverage Diff             @@
##           master    #4601      +/-   ##
==========================================
- Coverage   87.77%   87.71%   -0.07%     
==========================================
  Files         351      351              
  Lines       66244    66443     +199     
  Branches    10272    10326      +54     
==========================================
+ Hits        58148    58281     +133     
- Misses       5159     5206      +47     
- Partials     2937     2956      +19

@larsoner larsoner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM +1 for merge

@agramfort agramfort changed the title [WIP] Simplify cov code path [MRG] Simplify cov code path Sep 28, 2017
@agramfort

Copy link
Copy Markdown
Member Author

good to go from my end when green

@dengemann

dengemann commented Sep 28, 2017 via email

Copy link
Copy Markdown
Member

@agramfort

Copy link
Copy Markdown
Member Author

@dengemann ok to merge this one and do the rest in a subsequent PR?

@larsoner larsoner added this to the 0.15 milestone Sep 29, 2017
Comment thread mne/cov.py Outdated

.. versionadded:: 0.15
diag : bool
Use a diagonal approximation of the noise covariance.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

wait, why do we need this? Why not use make_ad_hoc_cov or noise_cov.as_diag()?

Comment thread mne/cov.py Outdated
if diag:
noise_cov = noise_cov.copy()
noise_cov['data'] = np.diag(np.diag(noise_cov['data']))
scalings = _handle_default('scalings', None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It looks like this code path (for whiten_evoked) previously used:

_get_whitener_data

Which in turn used:

scalings = _handle_default('scalings_cov_rank', scalings)

but now you have it just do:

scalings = _handle_default('scalings', None)

Shouldn't this still be scalings = _handle_default('scalings_cov_rank', scalings) here?

If so, I don't think you even need it because compute_whitener does this default check internally on line 1641.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

good catch

@agramfort

agramfort commented Sep 29, 2017 via email

Copy link
Copy Markdown
Member Author

@larsoner
larsoner merged commit ce2486c into mne-tools:master Sep 30, 2017
@larsoner
larsoner deleted the simplify_cov_code_path branch September 30, 2017 00:03
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.

4 participants