Hi all,
First I have to apologize because I could not write this questions as concise as I’d like to.
My goal is to implement an interface for optimisation/inference where the user can keep certain parameters fix (i.e. not inferred). Additionally, I would like that the user has only to deal with parameters in the form of NameTuple
s.
Example
To make it more concrete assume the following example:
using TransformVariables
# 1) Define model
# The transform is used for flattening and transformation of the parameters
tt = as((
a = asℝ₊,
b = asℝ₊,
w = UnitVector(5)
))
function model(p::NamedTuple, x)
p.a + p.b * x'*p.w
end
model(v::AbstractArray, x) = model(tt(v), x)
# 2) User can call model with NamedTuple
p = (a = 11.1,
b = 2.1,
w = [0.2, 0.2, 0.2, 0.2, 0.2])
x = ones(5)
model(p, x)
# 3) ... and optimizer/sampler routines can call model with V ∈ R^n
v = randn(6)
model(v, x)
# 4) we can define a function to fit the model
function fit_model(p_init::NamedTuple)
v_init = inverse(tt, p_init) # convert into vector
v_optimal = optim(v_init, model, ...) # some optimizer routine, that returns a vector
p_optimal = tt(v_optimal) # user gets back a nice tuple
return p_optimal
end
# The user provides inital parameters in
# the "natural" form, i.e. as NamedTuple
p_init = (a = 3.1,
b = 5.1,
w = [0.2, 0.2, 0.2, 0.2, 0.2])
fit_model(p_init) # ... and gets a Tuple back. All good so far!
Desired user interface
Now, how can I write a extended version fit_model2
that can be used as follows:
# The idea is that the user has to use only the NamedTuple format, i.e.
p_init = (a = 3.1,
b = 5.1,
w = [0.2, 0.2, 0.2, 0.2, 0.2])
p_keep_fix = (a = false,
b = true,
w = [false, false, true, true, false])
fit_model2(p_init, p_keep_fix) # <- how to implement this?
First attempt
I think the structure would look a bit like this. I’m stuck how I can write the ‘splice’ function
function fit_model2(p_init::NamedTuple, p_keep_fix::NamedTuple)
# 1) Transform the initial parameters to R^n.
v_init = inverse(tt, p_init) |> filter(is_not_fixed)
# 2) transform the fixed values to R^n
v_fix = inverse(tt, p_keep_fix) |> filter(is_fixed)
# 3) Splice the fixed and not fixed parameters together in the
# right order. It is not so easy to figure how many parameters are to be optimized,
# as it depends also on the transformation! For example, p.w is
# UnitVector so no parameters must be estimated if either 4 or 5
# values of p.w are fixed.
# Then build function to optimize:
function fopt(v)
v' = splice(v, v_fix)
model(v')
end
# 4) Optimize as usual
v_opt = optim(v_init, fopt)
# 5) combine fiexed and optimized parameters
v_opt' = splice(v_opt, v_fix)
# 6) user get a Named Tuple back
return tt(v_opt')
end
It seems an common and not very difficult problem. Looking forward to any ideas!