-
Notifications
You must be signed in to change notification settings - Fork 9
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
Support overlapping tiles #23
Conversation
Codecov Report
@@ Coverage Diff @@
## master #23 +/- ##
==========================================
- Coverage 96.00% 93.10% -2.90%
==========================================
Files 1 2 +1
Lines 75 116 +41
==========================================
+ Hits 72 108 +36
- Misses 3 8 +5
Continue to review full report at Codecov.
|
As a prototype, there's no doubt that this version works for your purpose. I have thought about the enhancement of this package but haven't dig into all the possibilities and implementation details. Here are some of my thoughts; they are not what we must do, but I'd like to see things head approximately in that direction. Codes in the current PR version seems a bit coupled together and might be very hard to extend. If it is possible, I feel it would be better and cleaner to implement a new Range type for the Balanced version, and reuse StepRange for the Fixed version. And keep the previous struct type as possible as we can. struct TileIterator{N,C} <: AbstractArray{NTuple{N, UnitRange{Int}}, N}
covers1d::C
end IIUC Generally, I don't think it's a good direction to make it an array type. For simple cases like this, we could have efficient getindex implementation, but that's not always possible for other cases. Make it an iterator would be more efficient and extensible, but yes, it requires some effort to implement it. I'm not sure if we should add TileIterator(axes::Indices, ::IterationStrategy) size and stride are just meta info to iteration strategy. I prefer to let Does every strategy has a stride meta? I don't know, I don't feel it good to assume that. We assume iteration along the column direction here, it might be good to assume that we also want to support iteration along row direction in the future. How would we solve that, adding a new In general, I want to get to a design where iteration strategies are pluggable and composable. |
Thanks a lot for your comments. I agree with most of what you said, but have a different view on some points:
There seems to be a misunderstanding
I think in the above situation it is very natural to make an struct ExoticTileIterator <: NotAnAbstractArray
...
end Maybe we should use
Excellent point I agree.
I fully agree here, is better to go with your
Again I fully agree. I am however not sure, what pluggable and composable mean here concretely. |
I'm a little bit with my own work here and I'm sorry that I can't give any detailed feedback on the code at this moment. It looks like you clearly know what should be done. My major concern about this PR and the changes is the performance overhead and extensibility. If that's done and I'm good with that.
Hmmm, I don't quite get it here because the constructor tells me this. function TileIterator(covers1d::NTuple{N, AbstractVector{UnitRange{Int}}}) where {N}
C = typeof(covers1d)
return TileIterator{N, C}(covers1d)
end This representation might bring some overhead and I'd like to avoid that overhead. I probably am wrong here but still, a performance benchmark is needed to support this change.
Yeah, perhaps. It seems like this doesn't need to be included in this PR.
By composable I mean two iteration strategy can be composed together into another strategy. For example, |
This constructor is a bit low level. If you ask by whatever API for the typeof(covers1d) = Tuple{CoveredRange{QuantizedRange.... which is a bitstype and completly lazy. Did you worry because you thought e.g. this would allocate a |
Ha, I get your point here; didn't realize that I was worried about the overhead during iteration, for example: julia> titr = TileIterator((1:7, 3:6), tilesize=(2, 2), stride=Balanced((3, 2)));
julia> @btime getindex(titr, 2, 2)
13.920 ns (0 allocations: 0 bytes)
(3:4, 5:6)
julia> titr = TileIterator((1:7, 3:6), tilesize=(2, 2), stride=Fixed((3, 2)));
julia> @btime getindex(titr, 2, 2)
0.045 ns (0 allocations: 0 bytes)
(4:5, 5:6) great that this has zero allocation. So yeah, this implementation is quite efficient already. Perhaps there's still some room to get The time spent on construction is less important here since we generally don't need to repeatedly create This looks good to me now, a really nice play with the types and dispatches. I guess we just need to leave some room for future extensibility as we discussed. Then add docs and tests and I feel it could be good to merge. |
|
||
# strategies | ||
export RelaxStride | ||
struct RelaxStride{N} |
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.
I thought, lets be conservative for now. I just added these two strategies. They are enough to cover the funcionality on master
as well as my balanced tile size use case.
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.
A different PR could implement a strategy that sets the stride to (1,1,1...)
giving the behavior sketched here:
JuliaImages/ImageFiltering.jl#155 (comment)
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.
For more advanced strides, we might want to do
tileiterator(axes, UnitStride())[begin:2:end, :, begin+2:4:end-2]
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.
This works but might not be the most efficient way because indexing with [begin:2:end, :, begin+2:4:end-2]
allocates a new array.
No need to implement in this PR, though. It is also very likely that reducing memory allocation only gives a marginal performance boost.
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.
Yes you are right this allocates currently, we can fix it, when it becomes a practical obstacle.
Probably we could just switch to use Travis for the Windows platform and sunset appveyor so that we don't get troubled with 32bit doctest. |
I did remove appveyor.yml and travis passes on windows. Probably need to deactivate appveyor on the appveyor website or something? |
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.
The current version looks good to me; probably the last round review. More docs and tests might be helpful, though.
Will remove that once this PR is merged. |
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.
LGTM, I think it's good to merge once the test passes. This is not a breaking change, but I'll bump to v0.3.0 since it drops Julia v0.7 support.
ping @timholy in case he has some thoughts about this PR.
Thanks @johnnychen94 for the detailed review and feedback. |
I've got this on my calendar to review tomorrow, sorry for the delay. |
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.
This is really great! In the future we may also want to move some of the tile-padding logic from ImageFiltering here, and this will be a good foundation.
Co-authored-by: Tim Holy <[email protected]>
Co-authored-by: Tim Holy <[email protected]>
Co-authored-by: Tim Holy <[email protected]>
Co-authored-by: Tim Holy <[email protected]>
Co-authored-by: Tim Holy <[email protected]>
There may be something weird going on. E.g., 75b2a90 doesn't match the commit-summary. |
Yeah I messed something up. I think we can just squash this PR or should I try to clean the history? |
I'll squash, no worries about that. |
Thanks again, terrific to have this! |
There's nothing breaking about this, right? Seems a little weird to release such a major improvement as 0.2.6, but OTOH not having to do version bumps in dependencies has advantages. |
Packages that would need [compat] bumps are just ImageFiltering, ImageMorphology, and Images (of those in General, anyway). Not bad at all. If we do want to increase the version number, perhaps we should contemplate 1.0? |
Yeah, I think this is not breaking. I would go with |
The only reason to bump to v0.3.0 is that Julia 0.7 support is dropped here. |
Oh right, we'll have to bump in fact. OK, let's release this as 0.3. |
Close #22
This needs at least docs and more tests. But before I go into that, @johnnychen94 what do you think about the API/design of this PR?