Skip to content

Using a wrapper + mutation to "implicitly" update scheduled parameters? #35

Open
@ToucheSir

Description

@ToucheSir

This is to write down a thought which came from #34 and FluxML/Optimisers.jl#89. Presently, we rely on mutably/immutably updating any objects which depend on the schedule value after each step. This is simple and easy to understand, but it could get unwieldy with more complex optimizer state trees.

What if we instead created a stateful type or wrapper which keeps track of the current schedule value? Then, we make this or some type which contains a reference to it subclass a number type (maybe Real? Could make it parametric on the value type). This proxy number can then be manipulated directly by Optimisers.jl rules, but will appear to update automatically whenever the schedule is ticked.

Some pseudocode for the above:

Option 1: wrapper itself is mutable number proxy

mutable struct ScheduleValue{T<:Real} <: Real
  inner::T
end

# Overload basic math operations (much like Flux.Nil)
Base.:+(sv::ScheduleValue, x::Number) = sv.inner + x
....

eta = ScheduleValue(0f0)
d = Descent(eta)
schedule = Exp(...)

for s in schedule
  eta.inner = s  # probably want a proper function for this
  ...
end

Option 2: number proxy is derived from wrapper

struct ScheduleValue{S<:Stateful} <: Real
  iter::S
end

_getval(sv::ScheduleValue) = sv.iter.schedule(sv.iter.state)

# Overload basic math operations (much like Flux.Nil)
Base.:+(sv::ScheduleValue, x::Number) = _getval(sv.inner) + x
...

schedule = Stateful(Exp(...))

eta = ScheduleValue(schedule)
d = Descent(eta)

for _ in schedule  # no need for value here, just next! on the Stateful
  ...
end

Too magic? Perhaps. I could also see serialization being an issue because of the mutable references, but BSON/JLD2 at least should work. However, this does seem more ergonomic than wrapping optimization rules when it comes to scheduling multiple hyperparameters simultaneously.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions