Live data from Hacker News

Differentiable Programming Mega-Proposal

forums.swift.org

51–60 of 78 posts

Re: Differentiable Programming Mega-Proposal

#51
post #43

Earlier quoted context omitted.

Maybe this is the piece I don't understand. What do you mean by "more than an expression-only language"? What is a non-expression in a language? And what would it mean to have a derivative for your non-expression?

You can easily use expressions to create trees rather than values in a library. Eg a + b need not compute a value, through a bit of operating overloading it can compute the tree plus(tree-a, tree-b). This “trick” does not extend to statements, however. You can’t override if or semicolon in most languages. You can encode statements as expressions, but then you have to worry about things like variable bindings on your…

Building expression trees is not the only way to do automatic differentiation. A simpler way is to just carry the value and it's derivative as a pair:

    #include 
    #include 

    struct autodiff { double value, deriv; };

    autodiff just(double x) { return { x, 1 }; }

    autodiff operator +(autodiff a, autodiff b) {
        return { a.value + b.value, a.deriv + b.deriv };
    }

    autodiff operator *(autodiff a, autodiff b) {
        return { a.value * b.value, a.deriv*b.value + a.value*b.deriv };
    }

    autodiff sin(autodiff a) {
        return { sin(a.value), cos(a.value)*a.deriv };
    }

    int main() {
        autodiff x = just(.1);
        for (int ii = 0; ii
There is no need to differentiate the for loop or the semicolons. This way is not doing symbolic differentiation. It's implementing the differentiation rules in parallel to calculating the values at run time.

This generalizes to partial derivatives for multivariate functions too:

     template
     struct autograd { double value, grad[dims}; };

Re: Differentiable Programming Mega-Proposal

#52
post #31

Earlier quoted context omitted.

notice the qualifier "really". obviously you can implement autodiff kind of outside the complier since pytorch and tensor flow exist. but those implementations constrain you to a select few compositions (please no comments on Turing completeness with just loops and conditionals). so for example if statements in pytorch are not differentiable (they might have piece wise continuous derivates) because pytorch doesn't ac…

If statements aren't really meaningfully differentiable, regardless of how you do it. Take if x == 59: return 1000 else if x > 59: return -x else: return x How do you optimize this to maximize x, regardless of what language you're in? It's true that you can get a derivative, but the derivative is essentially meaningless.

  if x 
Is in the core of most neural networks today (relu activation), so it is definitely useful.

Re: Differentiable Programming Mega-Proposal

#53
I don't see why a well written library could not serve the same purpose. It seems like a lot of cruft. I doubt, for example, Python would ever consider adding this and it's the defacto language that would benefit the most from something like this - due to the existing tools and communities.

It just seems so narrow and not at the same level of abstraction that languages typically sit at. I could see the language supporting higher level functionality so a library could do this without a bunch of extra work (such as by some reflection).

Re: Differentiable Programming Mega-Proposal

#54
post #31

Earlier quoted context omitted.

If statements aren't really meaningfully differentiable, regardless of how you do it. Take if x == 59: return 1000 else if x > 59: return -x else: return x How do you optimize this to maximize x, regardless of what language you're in? It's true that you can get a derivative, but the derivative is essentially meaningless.

There is a derivative, but since the function is non continuous, the derivative will likewise be messed up (but just around x=59). You really don’t want to be climbing a gradient around non continuous functions!

The function has a derivative by some notions of derivative.

But the function's derivative can't be derived by an application of the chain rule and the know derivatives of primitive functions, which is what Algorithmic/automatic differentiation ultimately does (though it does this at run time, not compile time, since ordinary, symbolic differentiation explodes in memory for a complicated functions).

Also:

The continuous function

    int f(int x) {
        if(x > 2) 
            return x + x;
        else 
            return x*2;
    }
Is not automatically or symbolically differentiable when represented that way.

Re: Differentiable Programming Mega-Proposal

#55
post #31

Earlier quoted context omitted.

notice the qualifier "really". obviously you can implement autodiff kind of outside the complier since pytorch and tensor flow exist. but those implementations constrain you to a select few compositions (please no comments on Turing completeness with just loops and conditionals). so for example if statements in pytorch are not differentiable (they might have piece wise continuous derivates) because pytorch doesn't ac…

If statements aren't really meaningfully differentiable, regardless of how you do it. Take if x == 59: return 1000 else if x > 59: return -x else: return x How do you optimize this to maximize x, regardless of what language you're in? It's true that you can get a derivative, but the derivative is essentially meaningless.

Yeah, Automatic differentiation is essentially only usable on functions specified the way mathematicians specify functions; the compositions of a series of primitives (plus operators like the integral and the differential itself, as well inverse relations).

AD is not usable on loops, conditionals or recursive calls.

So basically, whatever way you specify your functions, you are effectively going to have DSL (within a general purpose language or otherwise) since not all the functions you form are going to be differentiable by AD (and there's some confusion between differentiable in the abstract and differentiable by the methods of AD).

Edit: actually, it's pretty easy to extend AD to functions defined piecewise on intervals to be in the class of function amenable of AD. What's hard/impossible is extending functions defined by loops or recursion.

Re: Differentiable Programming Mega-Proposal

#56
post #44
post #34

Earlier quoted context omitted.

From the proposal: > While the differentiation APIs are flexible and fully dynamic, differentiation is based on a program transformation that happens at compile-time. This enables many static analyses that not only help produce more efficient programs, but also detect common numerical programming mistakes such as non-differentiable functions and zero derivatives. > With a first-class differentiable programming langua…

I still don't get it. Why can't I use a debugger to step through derivatives when autodiff is implemented as a library?

Reverse mode autodiff is best implemented with a non-local transformation of the program: First you run the original operations forward; then you run corresponding operations in reverse order.

You can do this with a library by implementing "number" types that, as a side effect of arithmetic operations, record those operations onto a "tape", so that corresponding (different) operations can be played back later in reverse order.

Unfortunately, those side effects have a cost during the forward pass. And during the backwards pass you are essentially running a little interpreter to execute your instructions.

Putting this stuff into the compiler lets the forward pass just be normal, native code on doubles/floats, and the same for the reverse-pass code. Moreover, all of this can now be worked on by the optimizing compiler.

This is especially important for embedded applications where you can't afford all this interpretation.

I guess the original TensorFlow "computation graph" approach is a little different to the "tape" I described because the graph is built explicitly rather than through side effects, but that just makes even more clear that you're really assembling an AST for some /other/ language and (when not using XLA) running an interpreter.

In principle some suitably powerful macro language with full access to the AST might be able to do good compile-time reverse-mode AD, but I am not aware of any language with powerful enough macros. Again, this is because the transformation is not just a local pattern replacement; it involves flipping the code upside down.

What's funny is that physicists have been able to do this kind of program transformation in a slightly clunky(?) way -- FORTRAN in, FORTRAN out -- since the 70s, supposedly.

It all makes me think that our ideas about what a "language" is, what a "compiler" is, what a "library" is, are all stuck in convention and prematurely ossified. The first compilers, which we celebrate, looked to their users like codegen (which we detest, I think)! I would love for the boundary between "language" and "compiler" to be broken down more so that AD could be more easily done "within the language"; maybe one day that will happen in Julia, or Nim, or Jai, or Terra.

But for now I think I agree with the designers that the best hope for good results, and really the most straightforward way, is to just do it in the compiler.

Re: Differentiable Programming Mega-Proposal

#57
post #44

Earlier quoted context omitted.

I still don't get it. Why can't I use a debugger to step through derivatives when autodiff is implemented as a library?

Reverse mode autodiff is best implemented with a non-local transformation of the program: First you run the original operations forward; then you run corresponding operations in reverse order. You can do this with a library by implementing "number" types that, as a side effect of arithmetic operations, record those operations onto a "tape", so that corresponding (different) operations can be played back later in reve…

It's already bring done in Julia. See zygote.jl.

Works with typed IR equivalent to a core compiler pass but from a third party package with regular Julia staged programming.

Re: Differentiable Programming Mega-Proposal

#59
post #11

I'm not a Swift programmer, so perhaps my confusion is just a symptom of broader ignorance, but I find two things unclear here: - What does 'first-class' mean, really? - Which of these benefits are unique to integrating notions of derivatives into the language, and which could be enjoyed well-written libraries? The mega-proposal links out to a separate doc on embedded DSLs, with broad statements about what's "typical…

>Why choose to carve out this added support for a single family

> of algorithms rather than add in some more general

> metaprogramming abilities that enable better EDSLs?

It is The Swift Way

The answer is always to add something to the language and the compiler, the question seems to be largely irrelevant.

Of course, that's a consequence of not heeding Alan Kay's advice from 1998, that when you design a new language, you need to focus on the metasystem first, the rest will follow.

http://wiki.c2.com/?AlanKayOnMessaging

When you don't do that, every new requirement comes as a surprise that you need to hack into the compiler somehow. Objective-C compatibility: hack the language; Python integration: hack the language; SwiftUI: hack the language; Differentiable Programming: hack the language.

And of course, each additional hack makes the already not-to-elegant base language even more difficult for implementing stuff without hacking the language.

What kind of a metasystem would we need in order to not have to hack the language for all of these features? That, detective, is the right question!

https://www.youtube.com/watch?v=ZKxr0wyIic4

Post reply on HN