Live data from Hacker News

Foundations for Efficient and Expressive Differentiable Programming [pdf]

papers.nips.cc

11–15 of 15 posts

Re: Foundations for Efficient and Expressive Differentiable Programming [pdf]

#11

Earlier quoted context omitted.

This looks interesting, thanks. What you call "delimited continuations" sounds a bit like how AD works in Julia's Flux package (and maybe elsewhere): During the forward calculation, a chain of functions is constructed, whose evaluation is the backward pass. This is done by overloading the original * to return both x * y and a closure Δ -> (Δ * y, x * Δ). Does that sound right, are these indeed similar, or have I mis-…

It's different -- instead of returning a closure, we take a closure as additional parameter (check paper for details). This means that the call stack stays intact and all intermediate values can be stack-allocated.

Could you please elaborate on what exactly enables stack allocation of intermediate values?

Is it a direct result of the semantics of delimited continuations? (perhaps because closures are passed as parameters and don't capture variables)

Or is it enabled via staging or optimizations?

Re: Foundations for Efficient and Expressive Differentiable Programming [pdf]

#12
I saw this paper at nips and I thought it was an awesome application of continuation passing style. Typically in CPS one of the advantages is that you really only need a single stack frame (since the remainder of the program is encoded in the callback), but in this paper they allow the CPS’d program to use multiple stack frames and store the intermediate results from backprop in the callstack. It never would’ve occurred to me to remove one of the advantages of CPS in order to store values on the callstack. Cool idea!

Re: Foundations for Efficient and Expressive Differentiable Programming [pdf]

#13
post #6

Earlier quoted context omitted.

Very cool. Like all really good ideas, this one seems "obvious" in hindsight. I mean that is a compliment: It would have never occurred to me that transforming code into continuation-passing-style code would allow for automatic differentiation through all dynamic control-flow structures, by leveraging the function-call stack, thus eliminating the need for some kind of "tape" data structure, e.g., as in PyTorch. My qu…

Thanks! Yes, it wasn't obvious at all when we started looking at AD either. Lantern supports a good deal of PyTorch (via Snek, our Python front-end similar to AutoGraph) and can also read ONNX. Full feature parity is not our main goal--so far, supported features have been driven mostly by what is required for certain interesting models.

How does this effort compare to Myia https://github.com/mila-udem/myia ?

Re: Foundations for Efficient and Expressive Differentiable Programming [pdf]

#14
post #11

Earlier quoted context omitted.

It's different -- instead of returning a closure, we take a closure as additional parameter (check paper for details). This means that the call stack stays intact and all intermediate values can be stack-allocated.

Could you please elaborate on what exactly enables stack allocation of intermediate values? Is it a direct result of the semantics of delimited continuations? (perhaps because closures are passed as parameters and don't capture variables) Or is it enabled via staging or optimizations?

It's specific to CPS form: every basic statement is a full function call, which moves to the next statement by calling another function (i.e. the continuation). Normally this would just be a very quick way to get yourself a stack overflow, so typical CPS-form compilers optimise (or require) the tail-call case, where you can pop the stack frame for the last instruction before moving on to the next. But for AD that's not a big deal, you just re-use those values in the backwards pass.

I doubt it's better than just allocating your own stack on the heap, especially when you have something like a differential equation solver with millions of statements, but it's still a neat trick.

Re: Foundations for Efficient and Expressive Differentiable Programming [pdf]

#15
post #11

Earlier quoted context omitted.

Could you please elaborate on what exactly enables stack allocation of intermediate values? Is it a direct result of the semantics of delimited continuations? (perhaps because closures are passed as parameters and don't capture variables) Or is it enabled via staging or optimizations?

It's specific to CPS form: every basic statement is a full function call, which moves to the next statement by calling another function (i.e. the continuation). Normally this would just be a very quick way to get yourself a stack overflow, so typical CPS-form compilers optimise (or require) the tail-call case, where you can pop the stack frame for the last instruction before moving on to the next. But for AD that's n…

Aha, that makes sense, thanks!

I agree that the performance benefits of such stack allocation (over heap allocation) aren't quite clear in practice.

I feel the bigger win of delimited cont./closure-based AD approaches is that they can model the control flow of reverse-mode AD without AD-specific code transformations. Delimited cont. is especially great at making things modular: each differentiable function performs primal computation, calls the callback with primal result, then performs adjoint computation.

Post reply on HN