-
Notifications
You must be signed in to change notification settings - Fork 14
added ChainRules examples with forward and backward #91
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
Conversation
Codecov Report
@@ Coverage Diff @@
## master #91 +/- ##
==========================================
+ Coverage 81.50% 81.82% +0.32%
==========================================
Files 5 5
Lines 865 864 -1
==========================================
+ Hits 705 707 +2
+ Misses 160 157 -3
Continue to review full report at Codecov.
|
this is great. i've been stuck at finding the difference b/t frules and rrules in implementation. now its much clear |
@oxinabox if you want to take a look |
Looks good. |
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.
Thanks for the work, looks really nice. Left some minor comments and a question.
examples/chainrules.jl
Outdated
model = Model(() -> diff_optimizer(Clp.Optimizer)) | ||
pv = unit_commitment(load1_demand, load2_demand, gen_costs, noload_costs, model=model) | ||
energy_balance_cons = model[:energy_balance_cons] | ||
MOI.set.(model, DiffOpt.ForwardIn{DiffOpt.ConstraintConstant}(), energy_balance_cons, [d1 + d2 for (d1, d2) in zip(Δload1_demand, Δload1_demand)]) |
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 might be a dumb question because I'm not familiar with DiffOpt and AD in general, but what are we doing here exactly and why is it specifically for the energy balance constraint?
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.
would it be too much to put a comment before each of these about what it does?
Not something that one would do in normal code, but since this is a tutorial it might be suitable.
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.
we are setting the perturbation for the right-hand-side of the energy balance constraints, which is the sum of perturbations of each of the quantities in the RHS (in that case sum of load demands)
Co-authored-by: Raphael Saavedra <raphael.saavedra93@gmail.com>
- `noload_costs` is the vector of fixed activation costs of the generators, | ||
and returning the optimal output power `p`. | ||
""" | ||
function unit_commitment(load1_demand, load2_demand, gen_costs, noload_costs; model = Model(() -> diff_optimizer(Clp.Optimizer))) |
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 think we can just do
function unit_commitment(load1_demand, load2_demand, gen_costs, noload_costs; model = Model(() -> diff_optimizer(Clp.Optimizer))) | |
function unit_commitment(load1_demand, load2_demand, gen_costs, noload_costs; model = Model(Clp.Optimizer)) |
function ChainRulesCore.frule((_, Δload1_demand, Δload2_demand, Δgen_costs, Δnoload_costs), ::typeof(unit_commitment), load1_demand, load2_demand, gen_costs, noload_costs) | ||
# creating the UC model with a DiffOpt optimizer wrapper around Clp | ||
model = Model(() -> diff_optimizer(Clp.Optimizer)) |
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.
We need to also pass the kwargs in: so probably can do:
function ChainRulesCore.frule((_, Δload1_demand, Δload2_demand, Δgen_costs, Δnoload_costs), ::typeof(unit_commitment), load1_demand, load2_demand, gen_costs, noload_costs) | |
# creating the UC model with a DiffOpt optimizer wrapper around Clp | |
model = Model(() -> diff_optimizer(Clp.Optimizer)) | |
function ChainRulesCore.frule((_, Δload1_demand, Δload2_demand, Δgen_costs, Δnoload_costs), ::typeof(unit_commitment), load1_demand, load2_demand, gen_costs, noload_costs; model=Model(Clp.Optimizer)) | |
# creating the UC model with a DiffOpt optimizer wrapper around Clp | |
model = Model(() -> diff_optimizer(optimizer(model))) |
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.
one issue here is that backend(.)
only gives you the top-most backend layer, so you add two layers of CachingOptimizer
# Reverse-mode differentiation of the solution map | ||
# The computed pullback takes a seed for the optimal solution `̄p` and returns | ||
# derivatives wrt each input parameter. | ||
function ChainRulesCore.rrule(::typeof(unit_commitment), load1_demand, load2_demand, gen_costs, noload_costs; model = Model(() -> diff_optimizer(Clp.Optimizer))) |
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.
we should write this assuming the Model they use isn't a diff_optimizer
model.
And we should unwrap and rewrap the model
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.
unwrapping and rewrapping the model results in the same issue as above
Copying the unit commitment example with ChainRules.
We depend on ChainRulesCore through SetDistances, so I added it as a dependency