-
Notifications
You must be signed in to change notification settings - Fork 429
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
Iteratively reweighted least squares for robust fitting #3170
base: master
Are you sure you want to change the base?
Conversation
Hello @samcoveney, Thank you for updating !
Comment last updated at 2024-04-26 15:51:29 UTC |
Thank you for this @samcoveney ! @RafaelNH and @arokem, it would be great if you could look at this! |
Many thanks for this PR. I will give a look asap. @samcoveney et al - In the meantime, please give a look to the PR #3151. I will be great to have that PR merged asap, so that we can avoid some duplicate work here. Particularly if you noticed I increased the dki.py test coverage to 100%, in PR #3151, it will be great if we maintain that test coverage in the work here as well. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3170 +/- ##
==========================================
+ Coverage 83.73% 83.92% +0.18%
==========================================
Files 153 154 +1
Lines 21316 21540 +224
Branches 3440 3494 +54
==========================================
+ Hits 17849 18077 +228
+ Misses 2611 2604 -7
- Partials 856 859 +3
|
When do you think you will have time to look at this @arokem? Thank you in advance for your update |
Sorry - busy week, so not before next Monday at earliest. |
I'll try to get tests etc done in the meantime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @samcoveney! Thanks for the PR and your hard work here!
I did a first review of it. I haven't managed yet to read all the suggested alterations due to it volume, but I have already some comments that I would like you to address before carrying on. Basically, I want to make sure that our previous DKI core implementations are not affected by the changes of your new fitting method, for instance you changed the weights of our previous WLS from diag(fn**2) to diag(fn). Could you clarify the rationale behind this adjustment? I'm concerned it might affect the outcomes of previous implementations, unless I'm missing something. Moreover, since what you are proposing is something new an tutorial explaining the method will help the review process. Also make sure to add some tests - for example, I quickly tried to run your new implementations in single voxel simulations and it is giving me an error.
Thanks for the review @RafaelNH - I appreciate getting some heads up about the overall structure, if okay? You are right, that a tutorial and some tests will help. If you can let me know if you think the overall implementation (in terms of form) is alright, and can get onto adding these tests. (on the PR, I give some examples of use - does this sort of workflow look okay? I think it was better to allow the user to define the weight functions for the best generality) Could you give me some information on the error please? In dki.py I recall perhaps an issue with the single voxel fit case, which is based on |
Looks good for me so far - I still have to understand better the code e.g. why number of iterations have to be at least 4. But the structure looks good, specially if it resembles what we have in dti.py. If you want to be sure (and avoid unnecessary work), you can wait for the feedback from @arokem before implementing the tests and example. Here is the error that I get when trying to run your implementation in single voxel signals (based on the variables in test_dki.py): Code error: Runs fine for:
Thanks again for your hard work on this! |
Thanks @RafaelNH I think this might be related to the test you are doing having no error on the data - can I confirm that this is true? I thought I had handled this, but perhaps not! Either way, I will add a test for such a case. edit: if you can send me your full test e.g. DM me on the discord, that would be awesome. Thanks again for helping edit 2: |
@RafaelNH when you get the chance, can you confirm whether the test you performed was on noiseless data please? |
7dd544d
to
8524f68
Compare
Yes, I test it on noiseless synthetic signals. |
Thanks @RafaelNH I have added tests for DTI, will get them done for DKI and try to address what to do when fitting noiseless signals (issue is that the noise is zero in this case: imagine weighting by inverse standard deviation of noise, when the noise is zero!) |
Have updated dki tests as well, should all be done. @RafaelNH I note that you didn't get an error, but just a warning, is this okay given the user error to use robust weighting with noiseless data? @skoudoro @arokem @Garyfallidis can you also take a look please? Probably I need to add a tutorial, but if that can wait that would be great.... |
Yes, I will take a look today. Can you just make sure to address some failing CI's like:
Thank you ! |
I must have missed this, both the warnings (will have to find those) and the discussion of this change... |
Note that the code format checks often fail while insisting on things that would fail pep8... shame. Also:
Please ignores these, they are literally wrong warnings, where pep8 doesn't understand comparisons with NumPy arrays of bools |
indeed 🤣 , Thank you for catching that. @jhlegarreta, can you check line-length for ruff, I suppose the default is wrong and create incompatibility between ruff and pep8check. We should also check pep8check. We should document it and it seems there is a consensus with
we can not 😅 , you can do like here: Line 2037 in 60669b8
|
Not sure if I follow this: we are not using |
look here: https://github.com/dipy/dipy/actions/runs/8850919427/job/24306287312?pr=3170#step:4:135 ruff enforces the one line import |
OK, then the solution is to either add a |
Hmm does this do what is needed? Surely that would need argwhere, for starters? Anyway, the changes in this PR are quite substantial, if we can focus on that, it'd be great thanks |
Looks like I think this may all be related to Possible: the constraints are set up for the log signal, but don't work as planned for the weighted log signal. I'll look into it, any thoughts appreciated. |
Adds ability to do iteratively re-weighted least squares for DTI and DKI (with/without positivity constraints) by defining a function to return weights based on the residuals of the last fit.
Implementation is in:
iterative_fit_tensor
inreconst/dti.py
iterative_fit
inreconst/dki.py
The methods work by iterating over a standard fit method, such as WLS, NLLS, or CWLS, but between fitting iterations weights are calculated from a supplied function
weights_method
. Some examples are given inreconst/weights_method.py
, but users can define their own functions outside of DIPY and pass the methods as arguments. Outlier rejection is naturally handled by theweights_method
supplied.Example:
Notes:
This is a fairly major extension that I think can be applied to other models using the same framework. I am sharing now to benefit everyone, ahead of my own publications, so please be kind!
Also, this has been a lot of work. Sorry I haven't done:
but I would like to get feedback at this stage please