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
Change the writeable flag back to its original state when finished. #431
Conversation
streamlines_length[i] = _length[double2d](streamlines[i]) | ||
streamline.setflags(write=writeable) |
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.
Sorry this is probably me just being stupid, but what is streamline here? It doesn't seem like the streamline variable is being updated in the loop.
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.
Woa, no you are not, I am. It should be streamlines[i]
instead of streamline
.
My issue with this approach is that it doesn't solve the problem in general. Read-only arrays sometimes raise an error if you try and make them writable. Take this example:
I think the only way to solve this problem in general is to copy the array by doing something like this:
That being said, I think this is an OK solution to the nibable issue if we make it clear in the comments that's the problem it's meant to solve. Another approach to solve the nibabel problem (though it may have it's own issues) is to have |
Streamlines are usually very large datasets >1.5 Gbytes. If we start copying them we will definitely get MemoryErrors. |
You only need to copy one at a time, it leaves memory as soon as you need On Wed, Oct 1, 2014 at 2:06 PM, Eleftherios Garyfallidis <
|
Okay this was not clear in your previous post. But I see what you mean now. But copying memory in small blocks takes time too. So please before you change this, profile it first with a few millions of streamlines. And let's see how it does. |
Following the same idea proposed by @MrBago, I used I benchmarked the change using respectively 1k and 10k streamlines of 100 points for bench_resample ... Timing set_number_of_points() in Cython bench_length ... Timing length() in Cython What do you think of this slow down? It is still faster than the python version though. Edit: This benchmarking was done on streamlines that are writeable and in float32 (I think the useful use case for those functions). But it worth mentioning that the new version is more flexible as it accepts list of streamlines with different dtypes and different writeable flag status. Basically before calling the inner Cython function (e.g. _length) I cast each streamline into either float32 or float64 depending on its dtype (int8/int16/int32 or int64) using astype or if its writeable flag is False. |
Can you try it with millions of streamlines please? |
Keep in mind the difference should only effect read-only arrays. On Thu, Oct 2, 2014 at 11:11 AM, Eleftherios Garyfallidis <
|
@MrBago with the modifications I made (called flexible version), it is not the case anymore. Even for arrays that are not read-only, there will be a difference because I am now doing more comparisons in order to handle list of streamlines with mixed dtype/writeable flags. The code is cleaner and shorter this way but it adds a small cost proportional to the number of streamlines. @Garyfallidis I tested with a millions of streamlines, I forgot to mention that I was repeat the functions 100 times in the benchmark. Here are the results for 1M streamlines and repeat set to 1: Timing length() in Cython Timing set_number_of_points() in Cython It seems the overhead has a bigger impact on function |
I guess we don't really need those functions to be more flexible. In the end, the normal use case for those functions is to have a list of streamlines having the same dtype/writeable flag status. I should have start by showing you this benchmarking: repeat=10, 1M streamlines, 100 points each, writeable=True, dtype=float32.
Edit: It appears caching was impacting the benchmark. So I've redone the benchmark making sure new streamlines are recreated before calling the function. |
…lexible version of functions length and set_number_of_points in Cython
Okay @Garyfallidis , I did some modifications on the flexible version. The flexible version (the one included in this PR) still supports having mixed dtypes and writeable flag status. @MrBago's version supports mixed writeable flag status. Whereas, the original version (the Cythonize version, that is not the Python ones in The following benchmark was produced on 100k streamlines containing 100 points (float32) each and were all writeable. When
|
I think this is OK to merge. I haven't reviewed the tests as well as I probably should, mainly because there seem to be a lot of changes that don't have to do directly with this PR. The one thing I'd like to add at some point is support for streamlines from a generator (which does not have len), but I don't think it should block this PR. If you guys think that's a good idea make an issue and assign it to me. I'll get around to it eventually (it shouldn't be that hard). |
Cool, added the issue as a reminder. Thx Marc! |
Change the writeable flag back to its original state when finished.
Right now, using Cython version of length and set_number_of_points on read-only numpy arrays (as provided by NiBabel) will fail. The reason is memoryview can only be used with writable numpy array (for more details check https://mail.python.org/pipermail/cython-devel/2013-February/003394.html)
This PR makes sure those Cython functions set the writeable flag of numpy arrays to True before processing them and changed it back to its original state once done.