-
Notifications
You must be signed in to change notification settings - Fork 147
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
"Fix" perturbation confusion, ushering in a new age of glorious dual numbers and prosperity #213
Conversation
Is the preferred method for instantiating configs in terms of performance to tie the config with the differentiated function, or it doesn't matter speed-wise if one uses nothing as an input arg to the config? |
The latter - passing in the function vs. passing |
0634627
to
65b273d
Compare
e8310ec
to
dca95b4
Compare
Trying to resolve nested dual number method ambiguities on Julia v0.5 is turning out to be a pretty hellish endeavor. Julia v0.6 doesn't seem to have these problems, however. It's enough of a struggle that I'm quite tempted to just drop Julia v0.5 support from this PR, and moving forward, maintain a separate release branch for ForwardDiff v0.4.x, which would still support Julia v0.5. ForwardDiff v0.5.0 (which would include this PR, and require Julia v0.6 and up) can then be tagged once Julia v0.6 is released. Does anybody has a very good reason for me to not do this? cc @mlubin @tkelman For the time being, I'm only going to develop this branch against Julia v0.6. |
Fine with me |
This enables us to throw the proper error(s) in case of perturbation confusion
…moving experimental multithreading functionality If you have a use case where the input is large enough for multithreading to be useful, then you should probably be using ReverseDiff instead of ForwardDiff. The exception to this is jacobian calculation, but ForwardDiff.jacobian never supported multithreading anyway. Once Julia's multithreading model matures, we can consider implementing multithreading for ForwardDiff.jacobian, but we probably should never again support it for gradients.
…currently poorly tested)
…h a simpler predicate (proposed by @KristofferC)
This is basically finished, assuming Travis passes. |
Hmm. Actually, I'm going to change one thing about this PR before merging: instead of the low-dimensional gradients being accessible via |
Alright, I'm realizing the API for the stack-allocated gradient/Jacobian could make more sense if I just use StaticArrays instead of |
Resolves #83.
This PR overhauls ForwardDiff to support a tagging system. The bulk of the work is done, but it still has a bunch of TODOs:
support tuple of output buffers for new n-aryWork is done, but will be introduced in a separate PR (see comment below)derivative!
hypot
methodsNotable changes:
Experimental multithreading support has been removed. See the relevant commit for details.
Dual{N,V<:Real}
→Dual{T,V<:Real,N}
whereT
is the tag parameter,V
is the value type, andN
is the chunk size. Similar parameterization changes were made to theAbstractConfig
types.If the tagging system is enabled, and perturbation confusion is about to happen, the culprit operation will dispatch to a descriptive error saying "ForwardDiff won't differentiate this safely".
(EDIT: This work was completed, but will refactored/added in a separate PR.) Now that we have a tagging system, it's safe to implement n-ary
derivative
(analogous to ReverseDiff's n-ary API, which allows the user to pass a tuple of arguments instead of a single argument). Now we have low dimensional, stack allocated gradients:My plan is to implement n-ary versions of the other API functions in future PRs.
AbstractConfig
constructors have changed, and our friendChunk
has made a comeback (and brought a new buddy,Tag
). For example,GradientConfig{N}(x)
is nowGradientConfig(f, x, Chunk{N}())
; here's the actual code for the constructor:As you can see, the user is now expected to pass in the target function for which the
GradientConfig
is being used to perform differentiation. This function, along with a hash of the input element type, is used to generate aTag
.Note the implication here: configuration instances are now tied to the function being differentiated. If you try to reuse a configuration instance constructed with one function to differentiate a different function, you'll get an error:
Don't worry - if you currently are reusing ForwardDiff configurations between different target functions, you can still do so by inserting
nothing
as the function argument:Note that this (halfway) opts out of the tagging system - a tag is still created from a hash of the element type, but does not incorporate the target function's type. Thus, the cost for this convenience is that you're a bit "less safe" w.r.t. perturbation confusion.