-
-
Notifications
You must be signed in to change notification settings - Fork 609
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
Why is Flux.destructure type unstable? #2405
Comments
Flux uses Functors.jl for all kinds of recursive walks, and when there are mutable objects, it keeps a cache of their objectIDs to look for duplicates. This means that it branches on the values of The reason it does this is to allow for shared parameters. The same array may appear multiple times. To be honest this is a giant pain, maybe it's a feature not worth preserving? Forbidding it would simplify many things. It is turned off for e.g. models with SMatrix parameters (which have no identitty beyond their value). Type stability is super-important deep inside tight loops, and hence drummed into us when learning Julia, but often doesn't matter at all for larger objects. E.g. removing type parameters from Flux layers often has no impact on performance, as there are enough function barriers between there and operations which take all the time. Having said all that, I'm not 100% sure this isn't an XY problem. Is your question actually why it is unstable, or are you really implying that you believe this is the cause of a performance problem? |
Same Q on discourse here, please link things so as not to waste time on duplicates. Here's a quick example to show some design differences between ComponentArrays and Optimisers.destructure: julia> using ComponentArrays, Optimisers
julia> arr = [1.0, 2.0];
julia> v, re = Optimisers.destructure((one=arr, two=[3f0], three=arr)) # this notices & preserves x1 === x3
([1.0, 2.0, 3.0], Restructure(NamedTuple, ..., 3))
julia> v .= 99; # this does not mutate arr, v is a copy
julia> nt = re([10, 20, 30.0])
(one = [10.0, 20.0], two = Float32[30.0], three = [10.0, 20.0])
julia> nt.one === nt.three # identity is restored
true
julia> ca = ComponentArray(one=arr, two=[3f0], three=arr) # this ignores the identity
ComponentVector{Float64}(one = [1.0, 2.0], two = [3.0], three = [1.0, 2.0])
julia> getfield(ca, :data)
5-element Vector{Float64}:
1.0
2.0
3.0
1.0
2.0
julia> ca.two # type has been promoted on construction
1-element view(::Vector{Float64}, 3:3) with eltype Float64:
3.0
julia> ca.three .= 99; # structured form is a view of flat form
julia> ca
ComponentVector{Float64}(one = [1.0, 2.0], two = [3.0], three = [99.0, 99.0]) |
Thank you @mcabbott and sorry for not linking. These component arrays seem very nice, especially as you can easily acess them and (apparently) mutate them in place. #Having said all that, I'm not 100% sure this isn't an XY problem. Is your question actually why it is unstable, or are you really implying that you believe this is the cause of a performance problem? Both actually. Since the code is quite simple for now, I'd like to have most that I can under control. So I'd like to understand what is going on. |
I was building a simple model and at some point I needed to "unroll" it to get all the parameters in an array.
So I tired with Flux.destructure. I got some type instability, so I checked the documentation and I tried with the example provided there:
But this gives a type instability as well!
What am I missing?
The text was updated successfully, but these errors were encountered: