From 9f30c799e1c663446515f6836bd0694c1558a79a Mon Sep 17 00:00:00 2001 From: Philip Turner Date: Sun, 5 Dec 2021 14:16:28 -0500 Subject: [PATCH 1/5] Create differentiable-programming-implementation-overview --- Documentation/differentiable-programming-implementation-overview | 1 + 1 file changed, 1 insertion(+) create mode 100644 Documentation/differentiable-programming-implementation-overview diff --git a/Documentation/differentiable-programming-implementation-overview b/Documentation/differentiable-programming-implementation-overview new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Documentation/differentiable-programming-implementation-overview @@ -0,0 +1 @@ + From 4779b9e537a9f42b6657dd680407d2bdf023ca68 Mon Sep 17 00:00:00 2001 From: Philip Turner Date: Sun, 5 Dec 2021 11:18:21 -0800 Subject: [PATCH 2/5] Add files via upload --- Documentation/differentiation-control-flow.png | Bin 0 -> 67949 bytes .../the-swift-compilation-pipeline.png | Bin 0 -> 52880 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Documentation/differentiation-control-flow.png create mode 100644 Documentation/the-swift-compilation-pipeline.png diff --git a/Documentation/differentiation-control-flow.png b/Documentation/differentiation-control-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..05c52556c1974912b97fdfeecb6fbc67319877f6 GIT binary patch literal 67949 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 VXYjPZ8b3i0+WYl2sp^M={s((U-s%7V literal 0 HcmV?d00001 diff --git a/Documentation/the-swift-compilation-pipeline.png b/Documentation/the-swift-compilation-pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..cb3f0f1073e8888acb20c8e38d0c4f1d5473f532 GIT binary patch literal 52880 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
8W6uWz&4jsYbVVrfHv?;@1i+ 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 literal 0 HcmV?d00001 From df846e61c222602a8d2ad31e343df574154c7fc2 Mon Sep 17 00:00:00 2001 From: Philip Turner Date: Sun, 5 Dec 2021 14:19:40 -0500 Subject: [PATCH 3/5] Rename differentiable-programming-implementation-overview to Differentiable-Programming-Implementation-Overview --- ...verview => Differentiable-Programming-Implementation-Overview} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/{differentiable-programming-implementation-overview => Differentiable-Programming-Implementation-Overview} (100%) diff --git a/Documentation/differentiable-programming-implementation-overview b/Documentation/Differentiable-Programming-Implementation-Overview similarity index 100% rename from Documentation/differentiable-programming-implementation-overview rename to Documentation/Differentiable-Programming-Implementation-Overview From b429225dc83cc4c70d32cd2136b3cb8c9aaa27d9 Mon Sep 17 00:00:00 2001 From: Philip Turner Date: Sun, 5 Dec 2021 14:19:52 -0500 Subject: [PATCH 4/5] Rename Differentiable-Programming-Implementation-Overview to Differentiable-Programming-Implementation-Overview.md --- ...view => Differentiable-Programming-Implementation-Overview.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/{Differentiable-Programming-Implementation-Overview => Differentiable-Programming-Implementation-Overview.md} (100%) diff --git a/Documentation/Differentiable-Programming-Implementation-Overview b/Documentation/Differentiable-Programming-Implementation-Overview.md similarity index 100% rename from Documentation/Differentiable-Programming-Implementation-Overview rename to Documentation/Differentiable-Programming-Implementation-Overview.md From 2c57de7ade30c5ac4acbcb797d7dca94c1325bae Mon Sep 17 00:00:00 2001 From: Philip Turner Date: Sun, 5 Dec 2021 14:21:00 -0500 Subject: [PATCH 5/5] Update Differentiable-Programming-Implementation-Overview.md --- ...ble-Programming-Implementation-Overview.md | 1029 +++++++++++++++++ 1 file changed, 1029 insertions(+) diff --git a/Documentation/Differentiable-Programming-Implementation-Overview.md b/Documentation/Differentiable-Programming-Implementation-Overview.md index 8b1378917..56e851c4a 100644 --- a/Documentation/Differentiable-Programming-Implementation-Overview.md +++ b/Documentation/Differentiable-Programming-Implementation-Overview.md @@ -1 +1,1030 @@ +# Swift Differentiable Programming Implementation Overview +> Philip Turner: This note ensures changes aren't buried under a comment thread until they're individually approved. In addition, some section hyperlinks might break in a PR comment. Each line in this header will be deleted as it is approved. +> +> After that is done, the document can be merged into `tensorflow/swift-apis@main` and hyperlinked in the [Differentiable Programming Manifesto](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md). The original Google Doc will receive a deprecation notice like the old [Differentiable Programming Manifesto Draft](https://docs.google.com/document/d/1bPepWLfRQa6CtXqKA8CDQ87uZHixNav-TFjLSisuKag/edit). This action will commence the resurrection of S4TF. +> +> - [ ] I went ahead and added myself to the list of authors/contributors. In addition, I added a table of contents and merged some otherwise line-separated text in [Terminology](#terminology) to make it more legible in Markdown. +> +> - [ ] Certain comments and instances of the 🚧 emoji were converted into TODO asides. +> +> - [ ] The links are unchanged, with an exception. There is an [outdated Google Docs draft](https://docs.google.com/document/d/1bPepWLfRQa6CtXqKA8CDQ87uZHixNav-TFjLSisuKag/edit) that was transferred into the Differentiable Programming Manifesto. I mapped all of those links to appropriate sections in the new location. +> +> - [ ] Explicit function conversion (in [Differentiable function type conversion](#differentiable-function-type-conversion)) no longer works as of Swift 5.5. May I put a warning there to alert readers? +> +> - [ ] I added a note in the [Registration](#registration) section, warning that the custom differentiation tutorial is not up to date. When Swift supports online DocC, we can replace it. For more context - [\[1\]](https://github.com/tensorflow/swift-apis/issues/1185#issuecomment-986038594) [\[2\]](https://github.com/tensorflow/swift-apis/issues/1185#issuecomment-986100609) under the "Requesting assistance" issue. +> +> - [ ] The highlighting for [Activity analysis](#activity-analysis) doesn't work in Markdown. I changed the highlighted syntax in that section to all caps. +> +> --- + +- Authors: [Dan Zheng](https://github.com/dan-zheng), [Bart Chrzaszcz](https://github.com/bartchr808), [Philip Turner](https://github.com/philipturner) +- Status: Draft, work in progress. + +## Table of contents + +- [Introduction](#introduction) +- [Overview](#overview) +- [Terminology](#terminology) + - [JVP and VJP functions](#jvp-and-vjp-functions) + - [Typing rules](#typing-rules) + - [Registration](#registration) +- [Background](#background) + - [The Swift compilation pipeline](#the-swift-compilation-pipeline) + - [Differentiation in the compilation pipeline](#differentiation-in-the-compilation-pipeline) +- [Two triggers of differentiation](#two-triggers-of-differentiation) + - [The `@differentiable` declaration attribute](#the-differentiable-declaration-attribute) + - [Differentiable function type conversion](#differentiable-function-type-conversion) +- [The differentiation transform](#the-differentiation-transform) + - [Activity analysis](#activity-analysis) + - [Canonicalization](#canonicalization) +- [Derivative code generation](#derivative-code-generation-automatic-differentiation) + - [JVP and differential generation](#jvp-and-differential-generation) + - [VJP and pullback generation](#vjp-and-pullback-generation) + - [Derivative code generation details](#derivative-code-generation-details) + - [Special cases](#special-cases) +- [Future directions and infrastructural changes](#future-directions-and-infrastructural-changes) +- [Acknowledgements](#acknowledgements) + +## Introduction + +This document explains how differentiation is implemented in the Swift compiler, stage by stage. Namely, it answers the following questions: + +```swift +// From the standard library: +// func gradient(at x: T, in f: @differentiable (T) -> R) -> T.TangentVector +// where R: FloatingPoint, R.TangentVector == R + +// 1. What does the `@differentiable` attribute do? +// Answer: the attribute marks `cubed` as a differentiable function declaration. +// The compiler will verify that `cubed` is indeed differentiable. +@differentiable +func cubed(_ x: Float) -> Float { + return x * x * x +} + +// 2. How does this call to `gradient` work? +// Answer: the closure expression is implicitly converted to a differentiable +// function-typed value and passed to `gradient`. In SIL, the differentiation +// transform generates derivative functions for the closure expression. The +// `gradient` higher-order function extracts and applies a derivative function to +// evaluate a gradient value. +gradient(at: 4, in: { x in x * x * x }) // 48.0 +``` + +> NOTE: +> - Please see the [Swift Differentiable Programming Manifesto](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md) for background and a holistic overview of differentiable programming in Swift. +> - This document describes the current implementation of differentiation in Swift. Some details may differ from [Swift Differentiable Programming Manifesto](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md), which describes the final design for differentiation in Swift. As the implementation of differentiation changes, this document will be updated accordingly. + +## Overview + +Swift supports first-class, language-integrated differentiable programming. This includes the following components: +- [The `Differentiable` protocol](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#the-differentiable-protocol): a protocol that generalizes all data structures that can be a parameter or result of a differentiable function. +- [The `@differentiable` declaration attribute](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#the-differentiable-declaration-attribute): used to mark function-like declarations (function declarations, initializers, properties, and subscripts) as being differentiable. +- [Differentiable function types](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#differentiable-function-types): subtypes of normal function types, with a different runtime representation and calling convention. Differentiable function types have differentiable parameters and results. +- [Differential operators](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#differential-operators): core differentiation APIs. Differential operators are higher-order functions that take `@differentiable` functions as inputs and return derivative functions or evaluate derivative values. +- [The differentiation transform](#the-differentiation-transform): a compiler transformation on the Swift Intermediate Language (SIL) that implements automatic differentiation and generates derivative functions. The differentiation transform is explained in this document. + +## Terminology + +### JVP and VJP functions + +A JVP (Jacobian-vector products) function is a forward-mode derivative function. A VJP (vector-Jacobian products) function is a reverse-mode derivative function. + +### Typing rules + +Consider a function with type `(T0, ...) -> U`, where `T0, ..., U` all conform to the `Differentiable` protocol. + +The JVP function type is: + +```swift +// (T0, ...) -> (U, (T0.TangentVector, ...) -> (U.TangentVector)) +// ^ ^ ^~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~ +// original args result derivative wrt args derivative wrt result +``` + +The JVP function returns a tuple with two elements: +- The original result of type `U`. +- A linear approximation function called the “differential”, which takes derivatives with respect to arguments and returns the derivative with respect to the result. + +The VJP function type is: + +```swift +// (T0, ...) -> (U, (U.TangentVector) -> (T0.TangentVector, ...)) +// ^ ^ ^~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~ +// original args result derivative wrt result derivative wrt args +``` + +The VJP function returns a tuple with two elements: +- The original result of type `U`. +- A backpropagation function called the “pullback”, which takes the derivatives with respect to the result and returns the derivative with respect to arguments. + +> TODO: Explain typing rules for functions with `inout` parameters. + +### Registration + +JVP and VJP functions can be registered using the `@derivative` attribute. JVP functions should return a tuple with labels `(value: ..., differential: ...)`. VJP functions should return a tuple with labels `(value: ..., pullback: ...)`. + +For usage examples of the `@derivative` attribute, please see: +- [The custom differentiation tutorial](https://github.com/tensorflow/swift/blob/master/docs/site/tutorials/custom_differentiation.ipynb), which shows how to use the `@derivative` attribute to register a derivative for `e^x`. +- [This mailing list response](https://groups.google.com/a/tensorflow.org/d/msg/swift/k62Uwnc-EYc/Cncb7mxtCAAJ), which shows how to use the `@derivative` attribute to register a derivative for `ax^2 + bx + c`. +> NOTE: The custom differentiation tutorial does not reflect the current state of differentiation in Swift. You can use it as a general guide to differentiaion, but its code samples will not compile. + +Note that derivative functions are defined as “JVP/VJP functions taking original arguments”, rather than just the “returned differential/pullback” functions. This is because differential/pullback functions may need to refer to intermediate values computed by the original function - this is possible when they are returned closures that capture values. + +> TODO: Write a canonical explanation of JVP and VJP functions and a `@derivative` attribute usage guide. + +## Background + +### The Swift compilation pipeline + +The Swift compiler translates Swift source code into executable machine code. Below is an illustration of the compilation pipeline: + +![Diagram of the Swift compilation pipeline](./the-swift-compilation-pipeline.png) + +Here is a description of the main phases in compilation:[†](https://www.swift.org/swift-compiler/) +- **Parsing**: The parser takes Swift source code and generates an abstract syntax tree (AST) without type information. Warnings and errors are produced for grammatical problems in source code. +- **Type checking**: The type checker takes the parsed AST and transforms it into a fully type-checked form, performing type inference. Warnings and errors are produced for semantic problems in source code. +- **SIL generation**: The Swift Intermediate Language (SIL) is a high-level intermediate language for Swift suitable for analysis and optimization. The SIL generation phase lowers the type-checked AST into “raw” SIL. +- **SIL mandatory passes**: The SIL mandatory passes perform analyses and transformations that affect program correctness, including data flow diagnostics and mandatory inlining. The result is “canonical” SIL. +- **SIL optimizations passes**: The SIL optimization passes perform additional high-level optimizations to SIL. +- **LLVM IR generation**: IR generation lowers SIL to LLVM IR. LLVM performs further optimizations and generates machine code. + +### Differentiation in the compilation pipeline + +Here is how differentiation fits into each of the stages of compilation: +- **Parsing** + - `@differentiable` attributes are parsed. + - `@differentiable` function types are parsed. +- **Type checking** + - `@differentiable` attributes are type-checked and verified. + - `@differentiable` function types are type-checked: this includes conversions to and from normal function types. Conversion from a normal function to a differentiable function is represented as an explicit `DifferentiableFunctionExpr` expression. +- **SIL generation** + - `@differentiable` AST declaration attributes are lowered to [SIL differentiability witnesses](https://github.com/apple/swift/blob/master/docs/SIL.rst#differentiability-witnesses). + - `DifferentiableFunctionExpr` function conversion expressions are lowered to the `differentiable_function` SIL instruction. +- **SIL mandatory passes** + - The differentiation transform is a SIL mandatory pass that implements [automatic differentiation](https://en.wikipedia.org/wiki/Automatic_differentiation). + - **Invariant**: after the differentiation transform, all SIL differentiability witnesses are canonicalized (i.e. derivative functions are filled in). + - **Invariant**: after the differentiation transform, all `differentiable_function` SIL instructions are canonicalized (i.e. derivative function values are filled in). +- **LLVM IR generation** + - `@differentiable` function types are lowered to LLVM IR types. + - `differentiable_function` and `differentiable_function_extract` SIL instructions are lowered to LLVM IR. + - SIL differentiability witnesses are lowered to global variables in LLVM IR. + +> TODO: Explain differential operators and their implementation (builtins). + +## Two triggers of differentiation + +The differentiation system in Swift needs to handle two main things: `@differentiable` declaration attributes and differentiable function type conversion. + +Both of these trigger “differentiation” by the compiler: +- The compiler verifies that every declaration with `@differentiable` attributes is indeed differentiable (according to the parameter indices and generic requirements of the attributes). All lowered SIL differentiability witnesses should be “filled in” with corresponding derivative functions. +- The compiler ensures that every conversion from a normal function to a differentiable function is valid. + +This document will explain the internals of the differentiation system via illustrative examples of the two triggers. + +## The `@differentiable` declaration attribute + +### Syntax + +The `@differentiable` declaration attribute marks “function-like” declarations ([function declarations](https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID159), [initializers](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html), [properties](https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID608), and [subscripts](https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html)) as differentiable. + +> TODO: Add `@differentiable` declaration attribute examples. + +The `@differentiable` declaration attribute has a few components: +- Parameter indices clause (optional): `wrt: x, y`. + - This explicitly states that the declaration is to be differentiated with respect to specific parameters. + - If the parameter indices clause is omitted, then the parameters for differentiation are inferred to be all parameters that conform to `Differentiable`. +- Generic where clause (optional): `where T: Differentiable`. + - This states that the declaration is differentiable only when certain additional generic requirements are met. + +### Type checking + +`@differentiable` declaration attributes are type-checked: +- All `wrt` parameters of the declaring function must conform to `Differentiable` and must be specified in ascending order. If `wrt` parameters are inferred, there must be at least one `wrt` parameter. +- The result of the declaring function must conform to `Differentiable`. +- If JVP/VJP function names are specified, they must resolve to function declarations with the expected JVP/VJP function types (computed from the original function type, parameter indices, and generic where clause). + +### SIL generation + +`@differentiable` declaration attributes are lowered to SIL differentiability witnesses. SIL differentiability witnesses have similar components to `@differentiable` attributes, including parameter indices, result indices (a SIL implementation detail), JVP/VJP SIL function names, and an optional generic where clause. + +### Differentiation transform + +The differentiation transform canonicalizes SIL differentiability witnesses: all SIL differentiability witnesses are filled in with JVP/VJP functions. + +```swift +// Before: empty differentiability witness, lowered from a `@differentiable` +// declaration attribute. + +// differentiability witness for foo(_:) +sil_differentiability_witness hidden [parameters 0] [results 0] @$s12diff_witness3fooyS2fF : $@convention(thin) (Float) -> Float { +} + +// After: canonicalized differentiability witness. The differentiation transform +// fills in JVP/VJP functions. + +sil_differentiability_witness hidden [parameters 0] [results 0] @$s3fooAAyS2fF : $@convention(thin) (Float) -> Float { + jvp: @AD__$s3fooAAyS2fF__jvp_src_0_wrt_0 : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) + vjp: @AD__$s3fooAAyS2fF__vjp_src_0_wrt_0 : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) +} +``` + +## Differentiable function type conversion + +### Syntax + +Swift supports ergonomic implicit function conversions: + +```swift +// Takes a differentiable function argument. +func foo(_ x: @differentiable (Float) -> Float) {} + +// Calling `foo` with a function declaration reference triggers an implicit +// `@differentiable` function type conversion. +func identity(_ x: Float) -> Float { x } +silly(identity) + +// Calling `foo` with a closure literal also triggers an implicit +// `@differentiable` function type conversion. +silly({ x in x } ) +``` + +Explicit conversion is also possible: + +```swift +let function: (Float) -> Float = { x in x } +// Explicit conversion. +let diffFunction: @differentiable (Float) -> Float = function +``` + +### Type checking + +Differentiable function types are a subtype of normal function types. See [here](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#function-subtyping-and-runtime-representation) for more information about type checking rules. + +Differentiable function conversion is represented in the AST as an explicit [DifferentiableFunctionExpr](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/include/swift/AST/Expr.h#L2923) expression. Example output from `swiftc -dump-ast` for the explicit conversion example above: + +``` +(differentiable_function implicit + type='@differentiable (Float) -> Float' + location=example.swift:3:54 + range=[example.swift:3:54 - line:3:54] +(declref_expr type='(Float) -> Float' + location=example.swift:3:54 + range=[example.swift:3:54 - line:3:54] + decl=example.(file).function@example.swift:1:5 + function_ref=unapplied)) +``` + +### SIL generation + +The `DifferentiableFunctionExpr` function conversion expression is lowered to the `differentiable_function` SIL instruction. A raw `differentiable_function` instruction takes an original function operand and produces a differentiable function. Canonical `differentiable_function` instructions are also bundled with derivative functions: + +### Differentiation transform + +The differentiation transform canonicalizes `differentiable_function` instructions: all `differentiable_function` instructions are filled in with JVP/VJP function values. + +```swift +// Before: +%fn_ref = function_ref @fn : $@convention(thin) (Float) -> Float +%diff_fn = differentiable_function [wrt 0] %fn_ref + +// After differentiation transform: +%fn_ref = function_ref @fn : $@convention(thin) (Float) -> Float +%fn_jvp_ref = function_ref @fn_jvp + : $@convention(thin) (Float) -> (Float, (Float) -> Float) +%fn_vjp_ref = function_ref @fn_vjp + : $@convention(thin) (Float) -> (Float, (Float) -> Float) +%diff_fn = differentiable_function [wrt 0] %fn_ref with {%fn_jvp_ref, %fn_vjp_ref} +// `@fn_jvp` and `@fn_vjp` may be generated. +``` + +## The differentiation transform + +The differentiation transform is a SIL mandatory pass that implements automatic differentiation. This is the “magic” in the differentiation system that automatically generates derivative functions. This involves a few steps: +- **Activity analysis**: static analysis that answers what values need a derivative. +- **Differentiability checking**: errors are produced for non-differentiable operations and warnings are produced for accidental data flow mistakes. +- **Automatic differentiation**: generate derivative functions. + +### Activity analysis[†](https://www-sop.inria.fr/tropics/papers/supportCoursDA.pdf) + +Activity analysis is a static SIL data flow analysis that determines exactly what values need a derivative. Let’s walk through the following example: + +```swift +@differentiable +func foo(_ x: Float) -> Float { + let result = sin(x) * cos(3) + print(result) + return result +} +``` + +Activity analysis classifies values in a function into these categories: +- **Varied values**: values that depend on the input. +- **Useful values**: values that contribute to the output. +- **Active values**: values are both varied and useful. These are the values that need a derivative. + +Here is the result of activity analysis for this example: + +```swift +// Varied values are in all caps. +// These values depend on the input (`x`). +@differentiable +func foo(_ X: Float) -> Float { + let SINX = sin(X) + let cos3 = cos(3) + let RESULT = SINX * cos3 + print(RESULT) + return RESULT +} + +// Useful values are in all caps. +// These values contribute to the output (`result`). +@differentiable +func foo(_ X: Float) -> Float { + let SINX = sin(X) + let COS3 = cos(3) // 3 should be treated as if capitalized. + let RESULT = SINX * COS3 + print(RESULT) + return RESULT +} + +// Active values are in all caps. +// These values are varied and useful, and thus need a derivative. +// Non-active values are gray. They do not need a derivative. +@differentiable +func foo(_ X: Float) -> Float { + let SINX = sin(X) + let cos3 = cos(3) + let RESULT = SINX * cos3 + let void = print(result) + return RESULT +} +``` + +Active values tell us what function calls to differentiate. For example, since `cos3` and `void` (the result of `print`) are not active, it is not necessary to differentiate the function calls `cos(3)` (which would be unnecessary work) or `print(result)` (which is not a differentiable operation). + +Active values also tell us which function parameters to differentiate with respect to. For example, since `cos3` is not active, it is not necessary to differentiate `Float.*` with respect to the second parameter `cos3`. + +### Canonicalization + +The differentiation transform is triggered by: +1. SIL differentiability witnesses that are missing derivative functions. +2. SIL `differentiable_function` instructions that are missing derivative function operands. + +```swift +// 1. SIL differentiability witnesses attributes. +// +// `@differentiable` declaration attribute does not register `jvp:` or `vjp:` +// derivative functions. +// +// @differentiable(wrt: x) // no 'jvp:' or 'vjp:' functions specified +// func cubed(_ x: Float) -> Float +// +// It is lowered to a SIL differentiability witness that similarly is missing +// derivative functions: +// +// // missing 'jvp' and 'vjp' functions +// sil_differentiability_witness hidden [parameters 0] [results 0] +// @$s12diff_witness3fooyS2fF : $@convention(thin) (Float) -> Float { +// } +// +// The differentiation transform generates derivative functions to fill in the +// attribute: +// +// // `@cubed_jvp` and `@cubed_vjp` may be generated. +// sil hidden +// [differentiable source 0 wrt 0 jvp @cubed_jvp vjp @cubed_vjp] @cubed +@differentiable(wrt: x) +func cubed(_ x: Float) -> Float { + return x * x * x +} + +// 2. Differentiable function conversion. +// +// A function value (here, the closure `{ x in x * x * x }`) is converted to a +// differentiable function value. SILGen lowers the function conversion to a +// `differentiable_function` instruction: +// +// %closure_ref = function_ref @closure : $@convention(thin) (Float) -> Float +// %cubed = differentiable_function [wrt 0] %closure_ref +// +// The differentiation transform canonicalizes the `differentiable_function` instruction, +// filling in derivative function values: +// +// %closure_ref = function_ref @closure : $@convention(thin) (Float) -> Float +// // `@closure_jvp` and `@closure_vjp` may be generated. +// %closure_jvp_ref = function_ref @closure_jvp +// : $@convention(thin) (Float) -> (Float, (Float) -> Float) +// %closure_vjp_ref = function_ref @closure_vjp +// : $@convention(thin) (Float) -> (Float, (Float) -> Float) +// %cubed = differentiable_function [wrt 0] %closure_ref +// with {%closure_jvp_ref, %closure_vjp_ref} + +gradient(at: Float(4), in: { x in x * x * x }) + +// Swift supports implicit function conversions, which happens above. +// Below is what the conversion looks like explicitly: +// let foo: (Float) -> Float = { x in x * x * x } +// let cubed: @differentiable (Float) -> Float = foo +// gradient(at: Float(4), in: cubed) +``` + +> TODO: Update the \[differentiable\] attribute directly above the Swift declaration of `cubed(_:)` with a SIL differentiability witness. + +## Derivative code generation ([automatic differentiation](https://en.wikipedia.org/wiki/Automatic_differentiation)) + +For both triggers (1) and (2) above, the differentiation transform needs to generate derivative functions. This “derivative function generation” is the bulk of differentiation transform; it is [automatic differentiation](https://en.wikipedia.org/wiki/Automatic_differentiation) implemented as a SIL-to-SIL function transformation. + +Derivative code generation takes the following steps: +- JVP generation and differential generation. +- VJP generation and pullback generation. + +Eventually, after forward-mode differentiation and linear maps are implemented, we will switch to a final “JVP → differential → pullback generation” approach. See [Probabilistic & Differentiable Programming Summit '19 slides](https://drive.google.com/corp/drive/folders/1y1FeJenXhoz_8xPw0ftVPngJUO_MdmRX) for more information about that approach. For now, this document will describe the current derivative code generation approach. + +In the sections below, let us dig into derivative code generation for the following function-to-differentiate (“original function”): + +```swift +@differentiable +func foo(_ x: Float) -> Float { + return sin(x) * cos(x) +} + +// Simplified SIL pseudocode. +sil @foo : $(Float) -> Float { +bb0(%x): + %y1 = apply @sin(%x) + %y2 = apply @cos(%x) + %y3 = apply @mul(%y1, %y2) + return %y3 +} +``` + +## JVP and differential generation + +### Overview + +Generated JVP functions are clones of the original function, with function applications replaced with JVP applications. Each JVP application returns the original result of the application in addition to a differential value (named “callee differential” to distinguish it from the “generated differential function”). + +The generated differential function takes the partial derivative with respect to inputs and returns the partial derivative with respect to the output. There is a mapping between active values in the original function and their tangent values (i.e. partial derivatives) in the differential function. The differential captures the “callee differentials” from the JVP, and replaces original function applications using original values with “callee differential” applications using tangent values. + +Finally, the JVP returns a tuple of the original result and the generated differential function. + +```swift +// JVP: replaces all function applications with JVP applications. +sil @jvp_foo : $(Float) -> (Float, (Float) -> Float) { +bb0(%x): + (%y1, %df_sin) = apply @jvp_sin(%x) + (%y2, %df_cos) = apply @jvp_cos(%x) + (%y3, %df_mul) = apply @jvp_mul(%y1, %y2) + // Return tuple of original result and differential. + return (%y3, { %dx in + %dy1 = apply %df_sin(%dx) + %dy2 = apply %df_cos(%dx) + %dy3 = apply %df_mul(%dy1, %dy2) + return %dy3 + }) +} +``` + +### Visiting the original function to create a JVP + +In the Swift compiler, we have a class called [`JVPEmitter`](https://github.com/apple/swift/blob/tensorflow/lib/SILOptimizer/Mandatory/Differentiation.cpp) which subclasses [`TypeSubstCloner`](https://github.com/apple/swift/blob/master/include/swift/SIL/TypeSubstCloner.h). This uses the [visitor pattern](https://en.wikipedia.org/wiki/Visitor_pattern) to visit the original function and generate the JVP function. Taking a look at the `JVPEmitter` class, there are methods like `visitApplyInst`, `visitStructExtractInst`, etc. Each of these methods visit an instruction that is important in the generation of the JVP and differential, and emits a newly mapped version. We handle each type of instruction differently, explained below. + +One important note is that in the JVP, we visit every single instruction in the original function - sometimes it’s an exact copy, and other times there is some special logic we wrote to handle it differently (e.g. like control-flow discussed below). This is so that the JVP function behaves just like the original function. With this, if the original function has a print statement, the JVP will as well. However, when we consider the differential, we will only transform SIL instructions from the original that we deem to be fit (so no print statement in the differential!). These instructions are those that should be differentiated, which uses the activity analysis calculated earlier to determine which SIL instructions are important in computing the tangent values of a function. + +In Swift code, the generated differential function can be written as a closure, capturing the “callee differentials” from the JVP. But in SIL, all functions are top-level; closures are represented as top-level functions with captured values as an explicit argument. This requires a differential struct which will be discussed in the next section. What’s important here is that the `JVPEmitter` emits code both in a top level JVP function, but also a corresponding top level differential function. + +Here is what the more accurate, closure-free SIL pseudocode looks like: + +```swift +// Struct containing differential functions. +// Partially-applied to `@df_foo` in `@jvp_foo`. +struct foo_bb0_DF_src_0_wrt_0 { + var df_sin: (Float) -> Float + var df_cos: (Float) -> Float + var df_mul: (Float, Float) -> Float +} + +// JVP: replaces all function applications with JVP applications. +sil @jvp_foo : $(Float) -> (Float, (Float) -> Float) { +bb0(%x): + (%y1, %df_sin) = apply @jvp_sin(%x) + (%y2, %df_cos) = apply @jvp_cos(%x) + (%y3, %df_mul) = apply @jvp_mul(%y1, %y2) + // Partially-apply to get a differential. + %df_struct = struct $foo_bb0_DF_src_0_wrt_0 (%df_sin, %df_cos, %df_mul) + %df = partial_apply @df_foo(%df_struct) + // Return tuple of original result and differential. + %result = tuple (%y3, %df) + return %result +} + + +// Differential: apply differentials to tangent values. +sil @df_foo : $(Float, foo_bb0_DF_src_0_wrt_0) -> (Float) { +bb0(%dx, %df_struct): + %df_sin = struct_extract %df_struct, #df_sin + %dy1 = apply %df_sin(%dx) + %df_cos = struct_extract %df_struct, #df_cos + %dy2 = apply %df_cos(%dx) + %df_mul = struct_extract %df_struct, #df_mul + %dy3 = apply %df_mul(%dy1, %dy2) + return %dy3 +} +``` + +### Differential struct creation + +To dive deeper into the differential struct, the reason why we need these “callee differentials” is that not all differentials are linear, so they capture some sort of “state” from the original function call. For example, in multiplication, the differential is `dx * y + dy * x`. In the differential function, we don’t have access to the values of `x` and `y` - only `dx` and `dy`. Additionally, in the JVP call, the differential function it returned would have copied these values into the function so we only have `dx` and `dy`. So if we called the function with `x = 4`, `y = 5`, the differential would be `5 * dx + 4 * dy`. Thus, we need to pass these callee differentials into the overall/new differential function we generate by taking an additional “differential struct” argument, which represents a bundle of all of the “captured callee differentials”. The JVP then constructs an instance of the “differential struct” and [partially applies](https://en.wikipedia.org/wiki/Partial_application) them to the generated differential to get a differential value which it returns as part of the (original, diff) tuple in the JVP. + +These structs consist of two different types of values: the differential function that maps to the original function call which we got from the second element of the JVP call, and also branching enums. + +In order to define the differential struct type, we preemptively go over the entire function we are going to differentiate in order to generate the struct. Using the same approach as with `JVPEmitter` when emitting code in the differential, we visit all instructions that we deem are needed to take the derivative of. We then calculate the expected differential type of the function, and add that as a field to the struct. + +```swift +func foo(_ x: Float) -> Float { + let a = sin(x) + return 2 * x // only active in one result! +} + +struct foo_bb0_DF_src_0_wrt_0 { + var df_sin: (Float) -> Float + var df_mul: (Float) -> Float +} +``` + +In order to handle control flow, we need to create a struct for each basic block. In addition to this, we need an enum field that has the successor basic block struct as a payload value on the enum case. The reason this is required is that control flow is dynamic and what route we take down the control flow is determined during runtime. As such, we need to dynamically create instances of these structs, and be able to handle every control flow path. For example: + +```swift +func bar(_ x: Float) -> Float { + var retVal = f(x) // bb0 + if x < 5 { + retVal = g(retVal) // bb1 + } else { + retVal = h(retVal) // bb2 + } + return j(retVal) // bb3 +} +``` + +Diagram of control flow in differentiation + +There are 4 distinct basic blocks. For `bb0`, there are two basic blocks it can possibly branch to - `bb1` and `bb2`. And then `bb1` and `bb2` can only branch to `bb3`, finally with `bb3` not branching to any other basic blocks. Thus, we have the following enums: + +```swift +enum EnumBB0 { + case BB1(StructBB1) + case BB2(StructBB2) +} +enum EnumBB1 { + case BB3(StructBB3) +} +enum EnumBB2 { + case BB3(StructBB3) +} +``` + +With the following structs: + +```swift +struct StructBB0 { + var diff_f: (Float) -> (Float) { get set } + var succ: EnumBB0 { get set } +} +struct StructBB1 { + var diff_g: (Float) -> (Float) { get set } + var succ: EnumBB1 { get set } +} +struct StructBB2 { + var diff_h: (Float) -> (Float) { get set } + var succ: EnumBB2 { get set } +} +struct StructBB3 { + var diff_j: (Float) -> (Float) { get set } + // No successor. +} +``` + +So now, this differential struct is a nested data structure, which consists of a dynamic data structure that represents the basic blocks we visited and the derivative-affecting functions we need to call. + +Another additional transformation that is done in the JVP is the creation of trampoline blocks. These are basic blocks which deal with handling the transition from one basic block to another, specifically regarding the differential structs. For a concrete example, we would roughly have the following SIL code for the control flow function above: + +> NOTE: The SIL code below is simplified in both naming and how each instruction looks like. For more information regarding how each instruction looks like in actual code, refer to [SIL.rst](https://github.com/apple/swift/blob/tensorflow/docs/SIL.rst). + +```swift +func bar(_ x: Float) -> Float { + var retVal = f(x) + if x < 5 { + retVal = g(retVal) + } else { + retVal = h(retVal) + } + return j(retVal) +} + +bb0(args…): + // ... + // %diff_func is the differential of `f` gotten from a JVP call earlier in the + // basic block code. + // %condition is the `cond_br` condition calculated earlier. + %bb0_struct = alloc_stack $StructBB0 + %bb0_diff_field = struct_element_addr %bb0_struct.diff_f + store %diff_func to %bb0_diff_field // store diff func. + %bb0_payload_ptr = address_to_pointer %bb0_struct + cond_br %condition, bb0_bb1_tramp(args…, %bb0_payload_ptr), + bb0_bb2_tramp(args…, %bb0_payload_ptr) + +bb0_bb1_trampbb1(args…, %bb0_payload_ptr): + %bb0_succ = enum $EnumBB0.BB1 // bb0 succ inst. + %succ_addr = struct_element_addr %bb0_payload_ptr.succ // bb0 succ address. + // store the memory alloc’d struct to the succ field in bb0. + store %bb0_succ to %succ_addr + // Get a pointer to the memory of the field (the payload). + %bb1_payload_addr = init_enum_data_addr %succ_addr.BB1 + // Can’t pass addresses to basic blocks, need to convert to pointer. + %bb1_payload_ptr = address_to_pointer %bb1_payload_addr + br bb1(args…, %bb1_payload_ptr) + +bb0_bb2_tramp(args…, %bb0_struct): + %bb0_succ = enum $EnumBB0.BB2 // bb0 succ inst. + %succ_addr = struct_element_addr %bb0_struct.succ // bb0 succ address. + // store the memory alloc’d struct to the succ field in bb0. + store %bb0_succ to %succ_addr + // Get a pointer to the memory of the field (the payload). + %bb2_payload_addr = init_enum_data_addr %succ_addr.BB2 + // Can’t pass addresses to basic blocks, need to convert to pointer. + %bb2_payload_ptr = address_to_pointer %bb2_payload_addr + br bb2(args…, %bb2_payload_ptr) + +bb1(args…, %bb1_payload_ptr): + // ... + // %diff_func_ is the differential of `g` gotten from a JVP call earlier in the + // basic block code. + %bb1_diff_field = struct_element_addr %bb1_payload_ptr.diff_g + store %diff_func to %bb1_diff_field : $*(Float) -> Float // store diff func. + br bb1_bb3_tramp(args…, %bb1_payload_ptr) + +bb1_bb3_trampbb1(args…, %bb1_payload_ptr): + %succ_addr = enum $EnumBB1.BB3 // bb1 succ inst. + // get bb1 succ address from inside bb0 + %succ_addr = struct_element_addr %bb1_payload_ptr.succ // bb1 succ address. + // store the memory alloc’d struct to the succ field in bb0. + store %succ_addr to %bb1_payload_ptr : $*EnumBB1 + // Get a pointer to the memory of the field (the payload). + %bb3_payload_addr = init_enum_data_addr %succ_addr.BB3 + // Can’t pass addresses to basic blocks, need to convert to pointer. + %bb3_payload_ptr = address_to_pointer %bb3_payload_addr + br bb3(args…, %bb3_payload_ptr) + +bb2(args…, %bb2_payload_ptr): + // ... + // %diff_func_h is the differential of `h` gotten from a JVP call earlier in the + // basic block code. + %bb2_diff_field = struct_element_addr %bb2_payload_ptr.diff_h + store %diff_func_h to %bb2_diff_field // store diff func. + br bb2_bb3_tramp(args…, %bb2_payload_ptr) + +bb2_bb3_tramp(args…, %bb0_struct, %bb2_payload_ptr): + %55 = enum $EnumBB2, #EnumBB2.BB3!enumelt.1, undef : $StructBB3 // bb2 succ inst. + // get bb2 succ address from inside bb0. + %succ_addr = struct_element_addr %bb2_payload_ptr : $*StructBB2, #StructBB2.succ + // store the memory alloc’d struct to the succ field in bb0. + store %succ_addr to %bb2_payload_ptr + // Get a pointer to the memory of the field (the payload). + %bb3_payload_addr = init_enum_data_addr %succ_addr.BB3 + // Can’t pass addresses to basic blocks, need to convert to pointer. + %bb3_payload_ptr = address_to_pointer %bb3_payload_addr + br bb3(args…, %bb3_payload_ptr) + +bb3(args…, %bb3_payload_ptr): + // %diff_func_j is the differential of `j` gotten from a JVP call earlier in the + // basic block code. + %bb3_diff_field = struct_element_addr %bb3_payload_ptr.diff_j + store %diff_func_j to %bb3_diff_field // store diff func. + // Get the differential of bar and partially apply the struct to it so it can call + // the correct differentials in its body. + %diff_bar_instance = partial_apply diff_bar_func(%bb0_struct) + // %orig_result came from the same instruction where we got %diff_func + return (%orig_result, %diff_bar_instance) +``` + +- Here we do the same thing as we have been doing, which is partially applying the overall bb0 struct we created in bb0: + - `%bb0_struct = alloc_stack $StructBB0` + - This has the nested differential structs for all other relevant differential structs for all other basics blocks, and we partially apply it for the differential of `bar` and return the original result + differential tuple pair + +## VJP and pullback generation + +Similar to generated JVP functions, generated VJP functions are clones of the original function, with function applications replaced with VJP applications. Each VJP application returns the original result of application in addition to a pullback value (named “callee pullback” to distinguish it from the “generated pullback function”). + +The generated pullback function takes the partial derivatives with respect to outputs and returns the partial derivative with respect to the input. There is a mapping between _active values in the original function_ and their _adjoint values (i.e. partial derivatives) in the pullback function_. The pullback captures the “callee pullbacks” from the VJP, and replaces _original function applications using original values_ with _“callee pullback” applications using adjoint values_. + +Finally, the VJP returns a tuple of the original result and the generated pullback function. + +```swift +// VJP: replaces all function applications with VJP applications. +sil @vjp_foo : $(Float) -> (Float, (Float) -> Float) { +bb0(%x): + (%y1, %pb_sin) = apply @vjp_sin(%x) + (%y2, %pb_cos) = apply @vjp_cos(%x) + (%y3, %pb_mul) = apply @vjp_mul(%y1, %y2) + // Return tuple of original result and pullback. + return (%y3, { %dy3 in + // All "adjoint values" in the pullback are zero-initialized. + // %dx = 0, %dy1 = 0, %dy2 = 0 + (%dy1, %dy2) += %pb_mul(%dy3) + (%dx) += %pb_cos(%dy2) + (%dx) += %pb_sin(%dy1) + return %dx + }) +} + + +// VJP: replaces all function applications with VJP applications. +sil @vjp_foo : $(Float) -> (Float) -> Float { +bb0(%x): + (%pb_sin) = apply @vjp_sin(%x) + (%pb_cos) = apply @vjp_cos(%x) + (%pb_mul) = apply @vjp_mul(%y1, %y2) + // Return tuple of original result and pullback. + return (%y3, { %dy3 in + // All "adjoint values" in the pullback are zero-initialized. + // %dx = 0, %dy1 = 0, %dy2 = 0 + (%dy1, %dy2) += %pb_mul(%dy3) + (%dx) += %pb_cos(%dy2) + (%dx) += %pb_sin(%dy1) + return %dx + }) +} +``` + +As explained above in the “JVP and differential generation” section, closures do not exist in SIL. A more accurate, closure-free pseudocode looks like: + +```swift +// Struct containing pullback functions. +// Partially-applied to `@pb_foo` in `@vjp_foo`. +struct foo_bb0_PB_src_0_wrt_0 { + let pb_sin: (Float) -> Float + let pb_cos: (Float) -> Float + let pb_mul: (Float) -> (Float, Float) +} + +// VJP: replaces all function applications with VJP applications. +sil @vjp_foo : $(Float) -> (Float, (Float) -> Float) { +bb0(%x): + (%y1, %pb_sin) = apply @vjp_sin(%x) + (%y2, %pb_cos) = apply @vjp_cos(%x) + (%y3, %pb_mul) = apply @vjp_mul(%y1, %y2) + // Partially-apply to get a pullback. + %pb_struct = struct $foo_bb0_PB_src_0_wrt_0 (%pb_sin, %pb_cos, %pb_mul) + %pb = partial_apply @pb_foo(%pb_struct) + // Return tuple of original result and pullback. + %result = tuple (%y3, %pb) + return %result +} + +// Pullback: apply pullbacks to adjoint values. +sil @pb_foo : $(Float, foo_bb0_PB_src_0_wrt_0) -> (Float) { +bb0(%dy3, %pb_struct): + // All "adjoint values" in the pullback are zero-initialized. + // %dx = 0, %dy1 = 0, %dy2 = 0 + %pb_mul = struct_extract %pb_struct, #pb_mul + (%dy1, %dy2) += %pb_mul(%dy3) + %pb_cos = struct_extract %pb_struct, #pb_cos + (%dx) += %pb_cos(%dy2) + %pb_sin = struct_extract %pb_struct, #pb_sin + (%dx) += %pb_sin(%dy1) + return %dx +} +``` + +## Derivative code generation details + +The sections above explain derivative code generation, focusing on the transformation rules for function applications (i.e. the `apply` instruction). However, SIL functions are often more complex than just “a single basic block of function applications”: + +- Original functions may involve control flow (conditionals, loops, `guard` and `switch` statements, etc) to express conditional operations. Such functions in SIL have multiple basic blocks and control-flow-related instructions. + +Multiple basic blocks and control flow basic block terminators (`cond_br`, `switch_enum`, etc) require special derivative code generation rules. + +> TODO: **Explain the control flow differentiation approach.** The approach is novel and highly worth documenting. [See “Control Flow Differentiation” slides](https://drive.google.com/corp/drive/folders/1y1FeJenXhoz_8xPw0ftVPngJUO_MdmRX) for an overview. + +- Original functions may have instructions other than `apply`. This includes the entire SIL [instruction set](https://github.com/apple/swift/blob/master/docs/SIL.rst#instruction-set): + - Memory-related operations: `alloc_stack`, `dealloc_stack`, `load`, `store`, etc. + - Aggregate operations: `struct`, `tuple`, `enum`. + - Projections: `struct_extract`, `tuple_extract`, `struct_element_addr`, `tuple_element_addr`. + +Many of these instructions have well-defined corresponding tangent instructions (for the differential) and adjoint instructions (for the pullback). It turns out that supporting transformations of a few common instructions is sufficient for many use cases (e.g. [deep learning APIs](https://github.com/tensorflow/swift-apis)). Here is a short table listing some of these instruction transformation rules: + +| Original | Tangent (differential) | Adjoint (pullback) +| -------- | ---------------------- | ------------------ +| `y = load x` | `tan[y] = load tan[x]` | `adj[x] += adj[y]` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L5346) +| `store x to y` | `store tan[x] to tan[y]` | `adj[x] += load adj[y]; adj[y] = 0` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L5365) +| `copy_addr x to y` | `copy_addr tan[x] to tan[y]` | `adj[x] += adj[y]; adj[y] = 0` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L5382) +| `y = struct (x0, x1, ...)` | `tan[y] = struct (tan[x0], tan[x1], ...)` | `adj[x0] += struct_extract adj[y], #x0` `adj[x1] += struct_extract adj[y], #x1` `...` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L5110) +| `y = struct_extract x, #field` | `tan[y] = struct_extract tan[x], #field’` | `adj[x] += struct (0, ..., #field': adj[y], ..., 0)` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L5183) +| `y = struct_element_addr x, #field` | `tan[y] = struct_element_addr tan[x], #field’` | No generated code. `adj[y] = struct_element_addr adj[x], #field’` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L4157) +| `y = tuple (x0, x1, ...)` | `tan[y] = tuple (tan[x0], tan[x1], ...)` | `adj[x0] += tuple_extract adj[y], 0` `adj[x1] += tuple_extract adj[y], 1` `...` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L5257) +| `y = tuple_extract x, ` | `tan[y] = tuple_extract tan[x], ` | `adj[x] += tuple (0, ..., adj[y], ..., 0)` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L5298) +| `y = tuple_element_addr x, ` | `tan[y] = tuple_element_addr tan[x], ` | No generated code. `adj[y] = tuple_element_addr adj[x], ` [(code)](https://github.com/apple/swift/blob/8b7ab1143e260d7bb1db3b98e24f7fe28dc7f0f0/lib/SILOptimizer/Mandatory/Differentiation.cpp#L4169) + +In general, tangent transformation rules are simpler because the tangent transformation does not involve control flow reversal and because many instructions themselves are linear. + +### Modules and access levels + +Swift organizes code into [modules](https://github.com/apple/swift/blob/master/docs/Modules.rst). Modules enforce access controls on what code can be used outside of them. + +Differentiation is designed with modules and access levels in mind. `@differentiable` declaration attributes act like a “differentiability contract”: declarations marked with the attribute can be differentiated from other modules. This is because the differentiation transform is guaranteed to fill in all SIL differentiability witnesses with derivatives functions. Conversely, declarations not marked with `@differentiable` cannot be differentiated from other modules because they do not have registered derivative functions and are essentially opaque (their bodies may not be exposed). + +This design makes differentiation modular. The compiler does not need access to the bodies of cross-module declarations in order to differentiate them; it simply looks up their registered derivatives. + +### Pseudocode + +> TODO: Hyperlink pseudocode lines to actual code. + +Here is the pseudocode of the main logic of the differentiation transform. + +- For all differentiability witnesses in the current SIL module: + - If the witness is missing the JVP function, generate a JVP function and fill it in. + - If the witness is missing the VJP function, generate a VJP function and fill it in. +- Add all `differentiable_function` instructions from the current SIL module to a worklist. +- While the `differentiable_function` worklist is not empty, pop the next one. + - If `differentiable_function` has JVP and VJP values, do nothing. It is already canonical. + - If `differentiable_function` is missing JVP and VJP: + - If the `differentiable_function`’s original function operand is an `differentiable_function_extract [original]` instruction, get the operand of that instruction. Do `differentiable_function_extract [jvp/vjp]` instruction from that operand to get the JVP/VJP. Continue. + - Otherwise, get the “original function reference” (`function_ref`, `witness_method`, or `class_method` instruction) underlying the `differentiable_function`’s original function operand. + - Look up a `@differentiable` declaration attribute on the “original function reference” whose parameter indices are a minimal superset of the `differentiable_function`’s parameter indices. + - If no such attribute exists, create an empty attribute with the `differentiable_function`’s parameter indices. + - Process the minimal superset SIL differentiability witness: + - If the attribute is missing the JVP function, generate a JVP function. + - If the attribute is missing the VJP function, generate a VJP function. + - Produce a reference to the JVP/VJP to fill in the `differentiable_function` instruction. + +JVP/VJP function generation is explained above. The pseudocode above does not mention how [non-differentiability errors](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#static-analysis) are handled. If a non-differentiable operation is encountered while processing a SIL differentiability witness or a `differentiable_function` instruction, the transform stops processing the item, continues onto the next item, and finally stops compilation after all items are processed. + +## Special cases + +### Reabstraction thunk differentiation + +Reabstraction thunks currently require special differentiation support. +One common use case for reabstraction thunk differentiation is differentiating direct references to generic functions. Consider the following program: + +```swift +@_silgen_name("generic") +func generic(_ x: T) -> T { + return x +} +let _: @differentiable (Float) -> Float = generic +``` + +This generates the following code in SIL (`swiftc -emit-silgen`): + +``` swift +sil_stage raw + +import Builtin +import Swift +import SwiftShims + +func generic(_ x: T) -> T + +// main +sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { +bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>): + // function_ref generic(_:) + %2 = function_ref @$s4main7genericyxxlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0 // user: %3 + %3 = partial_apply [callee_guaranteed] %2() : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0 // user: %5 + // function_ref thunk for @escaping @callee_guaranteed (@in_guaranteed Float) -> (@out Float) + %4 = function_ref @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float // user: %5 + %5 = partial_apply [callee_guaranteed] %4(%3) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float // user: %6 + %6 = differentiable_function [parameters 0] %5 : $@callee_guaranteed (Float) -> Float // user: %7 + destroy_value %6 : $@differentiable @callee_guaranteed (Float) -> Float // id: %7 + %8 = integer_literal $Builtin.Int32, 0 // user: %9 + %9 = struct $Int32 (%8 : $Builtin.Int32) // user: %10 + return %9 : $Int32 // id: %10 +} // end sil function 'main' + +// generic(_:) +sil hidden [ossa] @$s4main7genericyxxlF : $@convention(thin) (@in_guaranteed T) -> @out T { +// %0 // user: %3 +// %1 // users: %3, %2 +bb0(%0 : $*T, %1 : $*T): + debug_value_addr %1 : $*T, let, name "x", argno 1 // id: %2 + copy_addr %1 to [initialization] %0 : $*T // id: %3 + %4 = tuple () // user: %5 + return %4 : $() // id: %5 +} // end sil function '$s4main7genericyxxlF' + +// thunk for @escaping @callee_guaranteed (@in_guaranteed Float) -> (@out Float) +sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float { +// %0 // user: %3 +// %1 // user: %5 +bb0(%0 : $Float, %1 : @guaranteed $@callee_guaranteed (@in_guaranteed Float) -> @out Float): + %2 = alloc_stack $Float // users: %8, %5, %3 + store %0 to [trivial] %2 : $*Float // id: %3 + %4 = alloc_stack $Float // users: %7, %6, %5 + %5 = apply %1(%4, %2) : $@callee_guaranteed (@in_guaranteed Float) -> @out Float + %6 = load [trivial] %4 : $*Float // user: %9 + dealloc_stack %4 : $*Float // id: %7 + dealloc_stack %2 : $*Float // id: %8 + return %6 : $Float // id: %9 +} // end sil function '$sS2fIegnr_S2fIegyd_TR' +``` + +Notice `%6 = differentiable_function [parameters 0] %5` in `@main`: this triggers the differentiation transform. The differentiation transform does the following: +- Attempts to canonicalize `%6 = differentiable_function [parameters 0] %5`. This starts by finding the underlying referenced original function. +- Peers through `partial_apply` to find `%4 = function_ref @$sS2fIegnr_S2fIegyd_TR` as the underlying original function (a reabstraction thunk). +- Generates derivative functions for the reabstraction thunk. This succeeds; the VJP is below: + +```swift +// AD__$sS2fIegnr_S2fIegyd_TR__vjp_src_0_wrt_0 +sil hidden [serializable] [ossa] @AD__$sS2fIegnr_S2fIegyd_TR__vjp_src_0_wrt_0 : $@conven +tion(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) +-> (Float, @owned @callee_guaranteed (Float) -> Float) { +// %0 // user: %3 +// %1 // user: %5 +bb0(%0 : $Float, %1 : @guaranteed $@callee_guaranteed (@in_guaranteed Float) -> @out Flo +at): + %2 = alloc_stack $Float // users: %19, %12, %3 + store %0 to [trivial] %2 : $*Float // id: %3 + %4 = alloc_stack $Float // users: %18, %17, %12 + %5 = copy_value %1 : $@callee_guaranteed (@in_guaranteed Float) -> @out Float // user: %6 +> %6 = differentiable_function [parameters 0] %5 : $@callee_guaranteed (@in_guaranteed Float) -> @out Float // users: %11, %7 + %7 = begin_borrow %6 : $@differentiable @callee_guaranteed (@in_guaranteed Float) -> @out Float // users: %10, %8 + %8 = differentiable_function_extract [vjp] %7 : $@differentiable @callee_guaranteed (@in_guaranteed Float) -> @out Float // user: %9 + %9 = copy_value %8 : $@callee_guaranteed (@in_guaranteed Float) -> (@out Float, @owned @callee_guaranteed (@in_guaranteed Float) -> @out Float) // users: %13, %12 + end_borrow %7 : $@differentiable @callee_guaranteed (@in_guaranteed Float) -> @out Float // id: %10 + destroy_value %6 : $@differentiable @callee_guaranteed (@in_guaranteed Float) -> @out Float // id: %11 + %12 = apply %9(%4, %2) : $@callee_guaranteed (@in_guaranteed Float) -> (@out Float, @owned @callee_guaranteed (@in_guaranteed Float) -> @out Float) // user: %16 + destroy_value %9 : $@callee_guaranteed (@in_guaranteed Float) -> (@out Float, @owned @callee_guaranteed (@in_guaranteed Float) -> @out Float) // id: %13 + %14 = tuple () + // function_ref thunk for @escaping @callee_guaranteed (@in_guaranteed Float) -> (@out Float) + %15 = function_ref @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float // user: %16 + %16 = partial_apply [callee_guaranteed] %15(%12) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float // user: %20 + %17 = load [trivial] %4 : $*Float // user: %23 + dealloc_stack %4 : $*Float // id: %18 + dealloc_stack %2 : $*Float // id: %19 + %20 = struct $_AD__$sS2fIegnr_S2fIegyd_TR_bb0__PB__src_0_wrt_0 (%16 : $@callee_guaranteed (Float) -> Float) // user: %22 + // function_ref AD__$sS2fIegnr_S2fIegyd_TR__pullback_src_0_wrt_0 + %21 = function_ref @AD__$sS2fIegnr_S2fIegyd_TR__pullback_src_0_wrt_0 : $@convention(thin) (Float, @owned _AD__$sS2fIegnr_S2fIegyd_TR_bb0__PB__src_0_wrt_0) -> Float // user: %22 + %22 = partial_apply [callee_guaranteed] %21(%20) : $@convention(thin) (Float, @owned _AD__$sS2fIegnr_S2fIegyd_TR_bb0__PB__src_0_wrt_0) -> Float // user: %23 + %23 = tuple (%17 : $Float, %22 : $@callee_guaranteed (Float) -> Float) // user: %24 + return %23 : $(Float, @callee_guaranteed (Float) -> Float) // id: %24 +} // end sil function 'AD__$sS2fIegnr_S2fIegyd_TR__vjp_src_0_wrt_0' +``` + +- The reabstraction thunk VJP contains `%6 = differentiable_function [parameters 0] %5`, which must now be canonicalized. This starts by finding the underlying referenced original function. +- 💥`%5` is a function argument, so there is no underlying referenced original function! Differentiation fails and produces a non-differentiability error: + +``` +:0: error: expression is not differentiable +:0: note: opaque non-'@differentiable' function is not differentiable +``` + +To support reabstraction thunk generation, we must find a way to avoid this “opaque non-@differentiable function” error. One straightforward solution is to change when the `@differentiable` function is formed: +- Make the reabstraction thunk JVP/VJP take a `@differentiable` function-typed argument. +- Make reabstraction thunk JVP/VJP callers construct and pass a `@differentiable` function-typed value. + +This involves: +- Adding a JVP/VJP type calculation special case for reabstraction thunks. +- Changing the differentiation transform so that reabstraction thunk JVP/VJP callers always construct and pass a `@differentiable` function-typed value. + +This approach is implemented in https://github.com/apple/swift/pull/28570. A partially-applied reabstraction thunk derivative matches the derivative type of the reabstracted original function. + +Alternatives: +- Make reabstraction thunk JVPs/VJPs take a “JVP/VJP” function-typed argument instead of a `@differentiable` function-typed argument. + - This seems more efficient because reabstraction thunk JVPs/VJPs only need to call the original function’s JVP/VJP - the other elements of the `@differentiable` function are not relevant. + - It may be possible that the derivative of a reabstraction thunk is simply a reabstraction thunk for the derivative function’s type. If so, this would be a significant simplification: within the reabstraction thunk derivative, we can simply call another reabstraction thunk and avoid other code generation (e.g. reabstraction thunk differential/pullback functions). + - `JVPEmitter::visitApplyInst` and `VJPEmitter::visitApplyInst` need special case logic to transform the single `apply` in reabstraction thunks into an `apply` of the “JVP/VJP” function-typed argument. + +## Future directions and infrastructural changes + +Below is a list of anticipated infrastructure changes to the Swift differentiation system. Non-core changes (e.g. API changes) are not listed here. + +### Differential-first (forward-mode) automatic differentiation + +Differential-first automatic differentiation is currently a work-in-progress. It is not yet at parity with the existing pullback-first (i.e. reverse-mode) automatic differentiation support. + +See [here](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#differential-operators) for more information about forward-mode differential operators in Swift. + +### Linear maps and transposition + +Linear maps are a fundamental concept in differentiation. Since differentiation is linear approximation, the derivative of a linear map is itself. + +We plan to add support for: +- Linear map function types (`@differentiable(linear)` function types), which are a subtype of `@differentiable` (and infinitely differentiable) function types. +- Linear map transposition as a first-class operation. This unlocks a correspondence between forward-mode and reverse-mode differentiation: `differentials and pullbacks are transposes of each other`. + +See [here](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#linear-maps) for more information about linear maps. With linear maps and transposition, the differentiation system will change in the following ways: +- All JVP functions will return a `@differentiable(linear)`-typed differential instead of a normal function-typed differential. +- VJP functions will be removed throughout the differentiation system. +- Pullback function generation will change to use transposition. + +## How to contribute? 🤔 + +[JIRA link to AutoDiff starter bugs](https://bugs.swift.org/issues/?jql=project%20%3D%20TF%20AND%20status%20%3D%20Open%20AND%20component%20in%20(Autodiff)%20AND%20labels%20in%20(StarterBug)). As of the time of this writing, there are no open starter bugs. If you are interested in helping with differentiable programming in Swift, please email [swift@tensorflow.org](mailto:swift@tensorflow.org) and we can help you find some starter tasks. + +## Acknowledgements + +Please see [here](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md#acknowledgements) for a list of people who have influenced the design and the implementation of differentiable programming in Swift. + +Some content is borrowed from the [Swift Differentiable Programming Manifesto](https://github.com/apple/swift/blob/main/docs/DifferentiableProgramming.md) by Richard Wei and [Probabilistic & Differentiable Programming Summit '19 slides](https://twitter.com/rxwei/status/1144688743468527617) - thank you Richard.