Automatic differentiation plays a prominent role in scientific computing andin modern machine learning, often in the context of powerful programmingsystems. The relation of the various embodiments of automatic differentiationto the mathematical notion of derivative is not always entirelyclear---discrepancies can arise, sometimes inadvertently. In order to studyautomatic differentiation in such programming contexts, we define a small butexpressive programming language that includes a construct for reverse-modedifferentiation. We give operational and denotational semantics for thislanguage. The operational semantics employs popular implementation techniques,while the denotational semantics employs notions of differentiation familiarfrom real analysis. We establish that these semantics coincide.
Quick Read (beta)
A Simple Differentiable Programming Language
Automatic differentiation plays a prominent role in scientific computing and in modern machine learning, often in the context of powerful programming systems. The relation of the various embodiments of automatic differentiation to the mathematical notion of derivative is not always entirely clear—discrepancies can arise, sometimes inadvertently. In order to study automatic differentiation in such programming contexts, we define a small but expressive programming language that includes a construct for reverse-mode differentiation. We give operational and denotational semantics for this language. The operational semantics employs popular implementation techniques, while the denotational semantics employs notions of differentiation familiar from real analysis. We establish that these semantics coincide.
Automatic differentiation is a set of techniques for calculating the derivatives of functions described by computer programs (e.g., (Pearlmutter and Siskind, 2008; Hascoët and Pascual, 2013; Baydin et al., 2018; Griewank, 2000)). These techniques are not required to produce symbolic representations for derivatives as in classic symbolic differentiation; on the other hand, neither do they employ finite-difference approximation methods common in numerical differentiation. Instead, they rely on the chain rule from calculus to obtain the desired derivatives from those of the programs’s basic operations. Thus, automatic differentiation is at the intersection of calculus and programming. However, the programs of interest are more than chains of operations: they may include control-flow constructs, data structures, and computational effects (e.g., side-effects or exceptions). Calculus does not provide an immediate justification for the treatment of such programming-language features.
In the present work we help bridge the gap between rules for automatic differentiation in expressive programming languages and their mathematical justification in terms of denotational semantics. Specifically, we consider automatic differentiation from a programming-language perspective by defining and studying a small but powerful language. The language is a functional first-order language, with only rudimentary data structures, but with conditionals and recursively defined functions (from which loops can be constructed). Additionally, it contains a construct for reverse-mode differentiation, explained in detail below. Our language is thus inspired by modern systems for machine learning, which include standard programming constructs and support reverse-mode differentiation. Reverse-mode differentiation permits the computation of gradients, forward-mode derivatives, and more. Indeed as our differentiation construct is a language primitive, differentiations can be nested within differentiations, allowing the computation of higher-order derivatives.
In the setting of a language such as ours, we can consider some common approaches to implementing differentiation:
One approach relies on code transformation, whether on source code or intermediate representations. For example, for the derivative of a conditional expression , it would output , where and are the derivatives of and respectively. This approach is employed, for instance, in Theano (Bergstra et al., 2010), Tensorflow 1.0 (Abadi et al., 2016a; Yu et al., 2018), and Tangent (van Merrienboer et al., 2018).
Another approach relies on tracing, typically eliminating control structures to produce a simpler form of code, which we call an execution trace, that can more easily be differentiated. For example, to produce the derivative of , tracing would evaluate the conditional and produce a trace of the branch taken. Execution traces correspond to graphs of basic operations, and can be taken to be sequences of elementary assignments or else functional programs in A-normal form. Their derivatives can be calculated by applying the chain rule to those basic operations, perhaps via a code transformation (but now of a much simpler kind). Tracing may also record some intermediate values in an evaluation trace, to reduce, or eliminate, the need for recomputation.11 1 Terminology in the automatic differentiation literature varies. Here we follow (Griewank, 2000) for evaluation traces. Our execution traces are, perhaps in somewhat different manifestations, variously termed Wengert lists or tapes or evaluation traces (Baydin et al., 2018; Pearlmutter and Siskind, 2008). They can also be seen as combinations of the operation and index traces of (Griewank, 2000).
This approach thereby conveniently avoids the problem of defining code transformations for conditionals and many other language constructs. It can also be implemented efficiently, sometimes in part with JIT compilation. For these reasons, trace-based differentiation is of growing importance. It is employed, for instance, in Autograd (Maclaurin et al., 2015), TensorFlow Eager Mode (Shankar and Dobson, 2017), Chainer (Tokui, 2018), PyTorch (PyTorch, 2018), and JAX (Frostig et al., 2018).
We therefore focus on trace-based differentiation in this paper, and give an operational semantics for our language using the trace-based approach. To do so, we define a sublanguage of execution trace terms (called simply trace terms below). These terms have no conditionals, function definitions or calls, or reverse-mode differentiations. They do have local definitions, corresponding to fanout in the graphs, but are not necessarily in A-normal form. Tracing is modeled by a new kind of evaluation, called symbolic evaluation. This uses an environment for the free variables of a term to remove conditionals and function calls. Function derivatives at a given value are evaluated in three stages: first, the function is traced at that value; next, the resulting trace term is symbolically differentiated (largely just using the chain rule), resulting in another such trace term; and, finally, that term is evaluated.
We do not account for some of the optimizations used in practice. Doing so would have been a more complicated enterprise, possibly with more arbitrary choices tied to implementation details, and we wished to get a more straightforward formalization working first.
From a mathematical perspective, both approaches to implementing differentiation pose correctness problems. In particular, functions defined using conditionals need not be continuous, let alone differentiable. Consider, for example, the following definition
of the popular ReLU function (Goodfellow et al., 2016). This function is not differentiable at . Further, changing the function body to yields a non-continuous function. What is more, both approaches can produce wrong answers even for differentiable functions! Consider, for example, the following definition of the identity function on the reals:
The derivative of this function at is . However, differentiation “by branches” (whether by code transformation or tracing) would produce the wrong answer, .
In order to capture the mathematical perspective, in addition to its operational semantics we give our language a denotational semantics. This semantics is based on classical notions of differentiation from real analysis (see, for example, (Trench, 2003)). That theory concerns multivariate functions on the reals defined on open domains, i.e., partial such functions with open domains of definition. In our semantics, we make use of those that are smooth (that is, those that can be partially differentiated any number of times). A particularly pleasing aspect of this mathematical development is how well domain theory (needed to account for recursion) interacts with differentiation.
Partiality is necessary, as for any language with general recursion, but it also gives us useful flexibility in connection with differentiation. For example, let be the approximation to which is equal to it except on the diagonal (i.e., where both arguments are equal) where it is undefined. Then
defines an approximation to ReLU which is undefined at . The approximation to is (unlike ) continuous (i.e., the pre-images of and are open sets), and the approximation to ReLU is differentiable wherever it is defined. Therefore, we design the semantics of our language so that it forbids functions such as but allows related approximations such as . An interesting question is how satisfactory an idealization this is of programming practice (which in any case works with approximate reals). We return to this point in the final section.
Proceeding in this way, we obtain adequacy theorems (i.e., operational soundness and completeness theorems) connecting the operational semantics of our language with a denotational semantics based on the classical theory of differentiation of partially defined multivariate real functions. Our theorems apply not only to conditional expressions but to the full language.
In sum, the main contributions of this paper are: (1) a first-order language with conditionals, recursive function definitions, and a reverse-mode differentiation construct; (2) an operational semantics that models one form of trace-based differentiation; (3) a denotational semantics based on standard mathematical notions from real analysis and domain theory; and (4) theorems that show that the two semantics coincide, i.e., the derivatives computed by the operational semantics are indeed the correct derivatives in a mathematical sense. Beyond the specifics of these results, this paper aims to give some evidence of the relevance of ideas and techniques from the programming-languages literature for programming systems that include automatic differentiation, such as current systems for machine learning.
While traditionally associated with scientific computing, automatic differentiation is now a central component of many modern machine learning systems, and those for deep learning in particular (Goodfellow et al., 2016). These systems often employ automatic differentiation to compute the gradients of “loss functions” with respect to parameters, such as neural network weights. Loss functions measure the error resulting from particular values for the parameters. For example, when a machine-learning model is trained with a dataset consisting of pairs , aiming to learn a function that maps the ’s to the ’s, the loss function may be the distance between the ’s and the values the model predicts when presented with the ’s. By applying gradient descent to adjust the parameters, this error can be reduced, until convergence or (more commonly) until the error is tolerable enough. This simple approach has proven remarkably effective: it is at the core of many recent successes of machine learning in a variety of domains.
Whereas gradients are for functions of type , for , treating the more general functions of type , for , works better with function composition, and with the composite structures such as tensors of reals used in deep learning. The literature contains two basic “modes” for differentiating such functions. Forward-mode extends the computation of the function, step by step, with the computation of derivatives; it can be seen as evaluating the function on dual numbers of the form where is nilpotent. In contrast, reverse-mode propagates derivatives backwards from each output, typically after the computation of the function. Reverse-mode differentiation is often preferred because of its superior efficiency for functions of type with . In particular, systems for machine learning, which often deal with loss functions for which , generally rely on reverse-mode differentiation. We refer the reader to the useful recent survey (Baydin et al., 2018) for additional background on these two modes of differentiation; it also discusses the use of higher-order differentiation.
Applications to machine learning are our main motivation. Accordingly, our language is loosely inspired by systems for machine learning, and the implementation strategies that we consider are ones of current interest there. We also de-emphasize some concerns (e.g., numerical stability) that, at present, seem to play a larger role in scientific computing than in machine learning. As noted in (Baydin et al., 2016), the machine learning community has developed a mindset and a body of techniques distinct from those traditional in automatic differentiation.
The literature on scientific computing has addressed the correctness problem for conditionals (Beck and Fischer, 1994; Fischer, 2001), although not in the context of a formally defined programming language. In (Mayero, 2002) a formal proof of correctness was given in Coq (Bertot and Castéran, 2013) for an algorithm for the automatic differentiation of straight-line sequences of Fortran assignments. Closer to machine learning, (Selsam et al., 2017) consider a stochastic graphical formalism where the nodes are random variables, and use the Lean theorem prover (de Moura et al., 2015) to establish the correctness of stochastic backpropagation. However, overall, the literature does not seem to contain semantics and theorems for a language of the kind we consider here.
Our work is also related to important papers by by Ehrhard, Regnier, et al., and by Di Gianantonio and Edalat. Ehrhard and Regnier introduce the differential -calculus (see (Ehrhard and Regnier, 2003)); this is a simply-typed higher-order -calculus with a forward-mode differentiation construct which can be applied to functions of any type. As described in (Blute et al., 2010), the differential -calculus can be modeled using the category of convenient vector spaces and smooth functions between them (see (Kriegl and Michor, 1997)). They do not give an operational semantics but they do give rules for symbolic differentiation and it should not be too difficult to use them to give an operational semantics. However their language with its convenient vector space semantics only supports total functions. It therefore cannot be extended to include recursive function definitions or conditionals (even with total predicates, as continuous functions from to the booleans are constant). Di Gianantonio and Edalat (Di Gianantonio and Edalat, 2013) prove adequacy theorems for their language, as do we, but their work differs from ours in several respects. In particular, their language has first-order forward-mode but no reverse-mode differentiation: our language effectively supports both, and at all orders. On the other hand, their language allows recursively-defined higher-order functions and accommodates functions, such as the ReLU function, which are differentiable in only a weaker sense. As far as we know, no other work on differentiable programming languages (e.g., (Pearlmutter and Siskind, 2008; Elliott, 2018; Wang et al., 2018; Shaikhha et al., 2018; Manzyuk, 2012)) gives operational and denotational semantics and proves adequacy theorems. Further afield, there is a good deal of work in the categorical literature on categories equipped with differential structure, for example (Blute et al., 2009; Bucciarelli et al., 2010).
Section 2 defines our language. Section 3 gives it an operational semantics with rules for symbolically evaluating general terms to trace terms, and for symbolically differentiating these terms. Sections 4 and 5 cover the needed mathematical material and the denotational semantics. Sections 6 establishes the correspondence between operational and denotational semantics. Section 7 concludes with discussion and some suggestions for future work.
2. A simple language
The types of our language are given by the grammar:
We will make use of iterated products , defined to be when , when , and, recursively, , when ; we write for the -fold iterated product of . Note that this type system includes the types of tensors (multidimensional arrays) of a given shape: the type of tensors of shape is the iterated product . The terms and boolean terms of the language are built from operation symbols and predicate symbols . An example operation symbol could be for dot product of vectors of dimension (for ); an example predicate symbol could be .
The terms are given by the following grammar, where and range over disjoint countably infinite sets of ordinary and function variables, respectively (so we have disjoint alphabets of ordinary and function variables):
These constructs are all fairly standard, except for , which is for reverse-mode differentiation, and which we explain below. We treat addition separately from the operations to underline the fact that the commutative monoid it forms, together with zero, is basic for differentiation. For example, the rules for symbolic differentiation given below make essential use of this structure, but do not need more any more of the available vector space structure.
Note the type subscripts on pairing and projection terms. Below, we rely on these subscripts for symbolic differentiation. In practice they could, if needed, be added when type-checking.
The sets and of free ordinary variables and free function variables of a term are understood as usual (and similarly for boolean terms). As is also usual, we do not distinguish -equivalent terms (or boolean terms).
The useful abbreviation
provides an elimination construct for iterated products. When this is
where ; when it is the above let construct; otherwise, it is defined recursively by:
(where is chosen not free in ).
We have zero and addition only at type . At other types we proceed inductively:
Skating over the difference between terms and their denotations, is the reverse-mode derivative at , evaluated at , of the function , where . Reverse-mode differentiation includes gradients as a special case. When and , the gradient of at is given by:
For definitions of gradients, Jacobians, and derivatives see Section 4.1 below, particularly equations (1), (2), (3), and (4). More generally, for an introduction to real analysis including vector-valued functions of several variables and their differentials and Jacobians, see, for example, (Trench, 2003).
So our language effectively also has forward-mode differentiation.
Function definitions can be recursive. Indeed a function can even be defined in terms of its own derivative: in a recursive function definition , the language allows occurrences of within the term in a sub-term of . This generality may be useful—examples (Maclaurin, 2017, p22) have arisen in the context of Autograd (Maclaurin et al., 2015). Pleasantly, both our operational and denotational semantics accommodate it without special complications. When we define a function without recursion, we may abbreviate to .
Turning to typing, operation and predicate symbols have assumed arities, written and ; we write for the set of operation symbols of arity . As examples, we would have and . Figure 1 gives typing rules for sequents of the forms
where (type) environments have the form
( all different) and where function (type) environments have the form
( all different). We adopt the usual overwriting notations and for type environments.
The typing rule for function definitions forbids any global variable occurrences (i.e., free variables in function definitions). This restriction involves no loss in expressiveness: as in lambda lifting, one can just add any global variables to a function’s parameters, and then apply the function to the global variables wherever it is called. The restriction enabled us to prove part (2) of Theorem 6.2 (below), but we conjecture it is not needed.
Our various abbreviations have natural admissible typing rules:
We may write (or ) instead of if has no free ordinary (or function) variables (and similarly for boolean terms). Typing is unique: for any , , and there is at most one type such that holds.
As an example, we use our language to program a miniature version of an algorithm for training a machine learning model by gradient descent, loosely based on (Goodfellow et al., 2016, Algorithm 8.1). In such training, one often starts with an untrained model, which is a function from inputs (for example, images) and parameter values to output “predictions” (for example, image labels). Relying on a dataset of input/output pairs, one then picks values of the parameters by gradient descent, as indicated in the Introduction. In our miniature version, we treat inputs, parameter values, and outputs as reals, and we assume that the training data consists of only one fixed input/output pair . We also assume that we have real constants (for the initial value for gradient descent), (for the learning rate, which is fixed) and (for the desired maximum loss on the dataset), and the infix predicate symbol . We can then define the trained model from the untrained model and a loss function as follows:
The example above is typical of what can be expressed in our language, and many variants of machine learning techniques that rely on gradient descent (e.g., of the kind presented in (Goodfellow et al., 2016), and commonly used in systems like TensorFlow) are in scope as well. For instance, there is no difficulty in expressing optimization with momentum, or differentially private stochastic gradient descent (e.g., (Song et al., 2013; Abadi et al., 2016b)). Probabilistic choice may be treated via random number generators, as is done in practice. Architectures that rely on convolutions or RNN cells can be expressed, even conveniently, with a suitable choice of primitives.
3. Operational semantics
We give a big-step operational semantics, specified with Felleisen and Friedman’s method (Felleisen and Friedman, 1987) using evaluation contexts and redexes. Other styles of operational semantics accommodating differentiation are surely also possible.
Terms and boolean terms are (ordinarily) evaluated to closed values and (necessarily) closed boolean values. The most original aspect of our operational semantics concerns the evaluation of differential terms; this is based on the trace-based approach outlined in the Introduction, and uses a second mode of evaluation: symbolic evaluation.
The core idea is that to evaluate a differential term
one first evaluates and , and then performs differentiation before evaluating further. There are two differentiation stages. First, using the closed value of for the differentiation variable , is symbolically evaluated to a trace term , thereby removing all control constructs from , but possibly keeping the variable free in , as the derivative may well depend on it. For example, when is , the value allows us to evaluate the guard of the conditional, but we do not replace the occurrence of in the branch with . Second, is symbolically differentiated at with respect to .
However, this idea is not enough by itself as the differential term may occur inside yet another differential term. One therefore also needs to be able to symbolically evaluate the differential term. That is done much as in the case of ordinary evaluation, but now symbolically evaluating redexes in and until one is left with the problem of symbolically evaluating a term of the form
where and are values that may contain free variables. One then proceeds as above, symbolically evaluating (now using the closed value of ) and then performing symbolic differentiation. As there is some duplication between these two symbolic and ordinary evaluation processes, our rule for ordinarily evaluating a differential term is designed, when executed, to first symbolically evaluate the term, and then ordinarily evaluate the resulting trace term.
The need to keep track of differentiation variables and their values for symbolic evaluation leads us to use value environments for ordinary variables. It is convenient to also use them for ordinary evaluation and to use function environments for function variables for both modes of evaluation.
Values are terms given by the grammar:
Note that, as indicated above, values may have free variables for the purposes of differentiation. Boolean values are boolean terms given by:
Closed values have unique types ; the set of closed values of type is ; and the set of boolean values is . We assume available operation and predicate symbol evaluation functions
We also assume that for every operator of arity there is an operator of arity . The idea is that is the reverse-mode derivative of at evaluated at . We write for . For example, for we would have:
We next define (value) environments , function environments , and (recursive function) closures , the last two mutually recursively:
Value environments are finite functions
from ordinary variables to closed values.
Every finite function
from function variables to closures is a function environment.
If and then is a closure, written .
For any and with , is the closed value obtained by substituting for all free occurrences of in .
Trace terms , are defined as follows:
They are the terms with no conditionals, function definitions or applications, or differentiations.
We will define two ordinary evaluation relations, and one symbolic one:
For all and we define evaluation relations between terms and closed values and between boolean terms and closed boolean values via rules establishing sequents of the forms:
For all and we define a symbolic evaluation relation between terms and trace terms via rules establishing sequents of the form:
Evaluation contexts (boolean evaluation contexts), ranged over by (resp. ), are terms with a unique hole :
We write for the term obtained by replacing the hole in by the term and similarly; a context is trivial if it is ; and and are extended to contexts. We have and and similarly for boolean contexts.
Redexes, ranged over by , and boolean redexes, ranged over by , are given by:
Note that boolean expressions are useful here in that they enable separate conditional and predicate redexes, and so evaluating predicates and making choices are distinct in the operational semantics.
The next lemma is the basis of a division into cases that supports operational semantics using evaluation contexts in the style of Felleisen and Friedman.
Lemma 3.1 (Evaluation context analysis).
Every term , other than a value, has exactly one of the following two forms:
for a unique evaluation context and redex, or
for a unique, and non-trivial, evaluation context and boolean redex.
Every boolean term , other than a boolean value, has exactly one of the following two forms:
for a unique, and non-trivial, boolean evaluation context and redex, or
for a unique boolean evaluation context and boolean redex.
The next lemma is useful to track types when proving theorems about the operational semantics.
Lemma 3.2 (Evaluation context polymorphism).
Suppose that . Then, for some type we have and, whenever , we have .
Analogous results hold for typings of any of the forms or or .
By the uniqueness of types, the types whose existence is claimed in the above lemma are unique.
The rules for ordinary evaluation are given in Figures 2 and 3; those for symbolic evaluation are given in Figures 4 and 5. The definitions are mutually recursive. They make use of the symbolic differentiation of trace terms: given a trace term , and values and (not necessarily closed), we define a trace term
intended to denote the reverse-mode derivative of the function , at , evaluated at . A definition is given in Figure 6; in the definition we assume that , and, as is common, that all binding variables are different.
Proposition 3.3 ().
The following typing rule is admissible:
In large part because of the restrictions on trace terms, their symbolic differentiation is just a systematic, formal application of the chain rule. In our setting, this application requires a fair amount of attention to detail, for instance the use of the type decorations when giving derivatives of pairing and projection terms.
The reader may wish to try the following two evaluation examples with nested differentiation:
We need some basic results on our evaluation relations. Two are standard: determinacy and type safety, and are used implicitly throughout the rest of the paper. The third connects symbolic and ordinary evaluation: one can interpolate symbolic evaluation within ordinary evaluation. It is principally helpful to reduce the completeness part of symbolic evaluation to the completeness of ordinary evaluation (see Theorem 6.7).
Proposition 3.4 (Determinacy of evaluation).
The following hold:
For any , , and , there is at most one value s.t. .
For any , , and , there is at most one trace term s.t. .
The following interpolation proposition establishes a certain consistency between the ordinary and symbolic evaluation relations.
Proposition 3.5 (Operational interpolation).
For all , , and closed values , the following are equivalent:
and , for some .
For a type safety theorem, we need typing judgments , , and for environments, function environments, and closures (implicitly extending the notion of type). These are defined inductively by the following rules:
Unique typing extends to environments, to function environments, and to closures (indeed, a closure can only have type ).
Proposition 3.6 (Type safety).
Suppose , and . Then we have:
4. Mathematical preliminaries
We now turn to the mathematical facts needed for the denotational semantics of our language. These concern the two modes of differentiation and their interaction with domain theory. We follow (Abramsky and Jung, 1994) for domain theory, but write dcppo for pointed dcpo, and say a partial order is coherent iff every compatible subset has a lub. (A subset is compatible if any two of its elements have an upper bound.) Every coherent partial order is a dcppo.
The collection of partial functions with open domain between two topological spaces forms a partial order under graph inclusion:
equivalently, using the Kleene order 22 2 We write for two mathematical expressions and to mean that if is defined so is , and they are then equal.:
This partial order is a coherent dcppo with the everywhere undefined function and compatible sups given by unions. A partial function is continuous if is open whenever is; the subcollection of continuous partial functions forms a coherent subdcppo. This holds as, for any open set and compatible collection of partial functions , we have:
We write for the dcppo of partial continuous functions from to .
It is convenient to use a variation on cartesian product when working with powers of . We set:
This version of product is associative. Vector concatenation then serves as tupling; however, for clarity, we may use the usual notation instead of . There are evident definitions of the projections , and of the tupling
of . We may ignore the superscripts on the projections when they can be understood from the context.
4.1. Continuity, differentiability, and smoothness
Standard multivariate analysis of vector-valued real functions from to (with ) considers functions defined on an open domain of , see, e.g., (Trench, 2003). These are precisely the partial functions:
with open domain.
When , such a function has partial derivatives
viewing as a function of . Taken together, these partial derivatives form its gradient
We write for .
We say is continuously differentiable if all the are continuous with domain that of , equivalently if is continuous with domain that of . As an example, removing from the domain of definition of the non-differentiable ReLU function , we obtain a continuously differentiable partial function with domain ; its derivative also has domain , with value , if , and , if .
We now turn to the general case where . The Jacobian of at is the by matrix:
where the matrix is undefined if any of the are. These Jacobians form a partial function:
where is the collection of by matrices. Viewing as , we say is continuously differentiable if is continuous and has the same domain as (equivalently if each component of is continuously differentiable).
The differential 33 3 Differentials are discussed in (Trench, 2003) see: p325 for differentials of functions of several variables; p348 for higher-order differentials; p381 for differentials of vector-valued functions of several variables; and p388 for the chain rule in differential terms.
of is defined by:
and is continuously differentiable iff has domain and is continuous there.
We write for the partial function ; it is either or everywhere defined and linear, the latter occurring precisely when is defined. If is linear then , for all .
In the automatic differentiation literature, is called the forward-mode derivative of at . For the reverse-mode derivative we define:
and write for the partial function ; is continuously differentiable iff has domain and is continuous there.
In terms of the differentials, the two modes are related by:
(setting ). So, if is linear, then .
The semantic content of the definition of forward-mode from reverse-mode given in Section 2 is the following equality:
This holds as: (the first equality holds as is linear if ).
The continuously differentiable functions are closed under composition. If is the composition of two such functions and , then the chain rule expresses the derivative of in terms of those of and . In terms of Jacobians, the chain rule is:
(Note that iff and .) In terms of forward-mode derivatives the chain rule is:
and in terms of reverse-mode derivatives it is:
Derivatives with respect to two variables can be reduced to derivatives in each separately. Specifically suppose . Then, for and , we have:
These equations are useful for dealing with fan-in.
Our programming language has all finite product types of the reals. We will therefore need to work with partial functions with open domain where or is zero. To this end we regard as having as sole element the empty vector, the trivial topology, and the trivial vector space structure. Every such total function is linear, and this determines its adjoint.
We take such a function , where or is zero, to be continuously differentiable if it is continuous, and we define and by:
The derivative has domain and is continuous (and so continuously differentiable) iff is, and a similar remark applies to . We understand and similarly to before. In case is linear (i.e., total) we have and as before and equation (5) relating the two modes continues to hold, as does equation (6) and also equations (10) and (9) concerning derivatives with respect to two variables. In particular for we have:
Regarding compositions we note a useful fact:
Fact 1 ().
If is constant on its domain, then it is continuously differentiable iff it is continuous and then, for any in its domain, is the constantly function, as is .
It follows that the continuously differentiable functions, if taken in our wider sense, remain closed under composition and pointwise addition, and that the chain rule for forward derivatives continues to hold, as does that for reverse derivatives. From now on whenever we consider partial functions from an to an , we include the cases where or is .
The projections are total linear functions, so we have:
Regarding the tupling of we have:
For the semantics of our language we work with infinitely differentiable functions, i.e., smooth ones. First we define smoothness classes . We say that a partial function is if it is continuous, and, inductively, is if has domain and is . This defines a decreasing sequence of classes of functions, and we say that is smooth or if it is for all . The functions are precisely the continuously differentiable ones. Using the chain rule for differentials one shows that the functions, and so too the smooth ones, are closed under composition. The projections are smooth, as are all linear functions and the functions, and so too the smooth ones, are closed under tupling.
4.2. Cppos of differentiable functions
The subgraph partial order on partial functions between powers of interacts well with the differential structure. We have:
Proposition 4.1 ().
For any with open domain we have:
For any compatible family of functions with open domain , we have:
For the first part, if or is 0, the conclusion is immediate using Fact 1. Otherwise, as and agree on. an open set including we have:
and the conclusion follows. For the second part, set . For the forward-mode derivative, using the first part we calculate:
The proof for the reverse-mode derivative is similar.
Proposition 4.2 ().
Let be partial functions with open domain. Then is smooth if is.
Let be a compatible family of partial functions with open domain, and with sup . Then is smooth if all the are.
For the first part, we prove by induction that if is then so is . For we note that for any open , . For , as is , and is . From part (1) of Proposition 4.1 we have and . So and have open domain, , and is . It follows from the induction hypothesis that is . So is , as required.
For the second part we prove, by induction on that if all the are , then so is . For this is clear. For , we have, for all , that and is . From part (2) of Proposition 4.1 we have . So, first,
and second, also using the induction hypothesis, we have that is . So is , as required. ∎
We write for the coherent dcppo of smooth partial functions between and .
4.3. Conditionals and recursion
Differentiation and conditionals interact well. The conditional combinator is defined for and by:
where . The conditional combinator is continuous. For differentiability, with a discrete topological space, we have:
Proposition 4.3 ().
Suppose is continuous (equivalently: both and are open). Then:
Further, if are smooth so is .
Assume that is continuous. Set . The domain of is open, indeed so is defined.
To prove the equality, choose . There are three cases. First, if then and so ; the equality therefore holds at . Second if then, as and is open, we see that, by part (1) of Proposition 4.1, , and so the equality again holds at . The third case is similar to the second.
In less formal terms than the proof, equality holds because if, say, the condition holds at , it holds in a neighborhood of . So and the conditional are equal throughout , and therefore have the same derivative there. The equality justifies the approaches to the differentiation of conditionals described in the Introduction.
Differentiation and recursion also interact well. For any continuous ( a dcpo, a dcppo) we write for the least fixed-point (l.f.p.) of . It is the sup of the iterates , defined inductively by:
starting from . As functions of , the l.f.p. and the iterates are continuous. When , we write , etc.
Proposition 4.4 ().
Set and . Then if and are such that
Set and . Then if and
are such that
We only consider the forward-mode case as the reverse-mode case is similar. In one direction we prove by induction on that
This is evident for . For we calculate (missing out types):
In the other direction we prove by induction on that
This is evident for . For we calculate:
The conclusion then follows using the continuity of (Part 2 of Proposition 4.1).
Although we do not do so here, this proposition can be used to justify code transformations of recursive function definitions.
5. Denotational semantics
We begin with a denotational semantics of types as powers of the reals:
Note that , where, , and, recursively, . Then, for the semantics of environments we set
and for that of function environments we set
We use to range over and over .
The denotational semantics of terms will be a continuous function:
and that of boolean terms will be a continuous function:
When the environments and types are understood from the context, we may just write or .
For the semantics of operation and predicate symbols, for every we assume available a smooth function and for every a continuous function , such that:
for every closed value , and
for every closed value .
The denotational semantics is given in Figure 7. Note that it uses the no-free-variable assumption in the clause for recursive functions. Apart from the semantics of reverse differentiation, which uses the reverse-mode derivative , it is quite standard. However, the facts that the denotations of terms carry smooth functions to smooth functions, and that the denotations of boolean terms carry smooth functions to continuous ones, use the mathematics developed in the previous section, particularly: the chain rule, e.g., for function application and let constructs; the preservation of smooth functions by the conditional combinator; the remarks on products; and, for recursive function definitions, the fact that the lub of an increasing sequence of smooth functions is smooth.
If a term contains no function variables (or variables), is independent of (and ), and we write (resp., ) for it. Trace terms have no function variables, and closed values have no function variables or variables.
Using the semantics of terms, we can define the denotational semantics of value environments, function environments, and closures, the latter two by a mutual structural induction.
For every , where , we define by:
For every , where , we define by:
For every we define by:
We omit and from and when they can be understood from the context.
Lemma 5.1 ().
For any type we have:
The denotation of any value exists.
For any there is a unique value such that .
The following two fairly standard results about evaluation contexts are needed to show adequacy.
Lemma 5.2 (Evaluation context compositionality).
Suppose , , and . Then:
Analogous results hold for: boolean terms in evaluation contexts, ; terms in boolean evaluation contexts ; and boolean terms in boolean evaluation contexts .
Lemma 5.3 (Evaluation context strictness).
Suppose that and . Then, for any , we have:
The analogous result holds for terms in boolean contexts .
Suppose that and . Then:
The analogous result holds for boolean terms in boolean contexts .
We present our main results, on the correspondence between operational and denotational semantics. Taken together these are our adequacy theorems. As well as the usual correctness and completeness theorems, there are results peculiar to differentiation, both of interest in themselves and also necessary for the others. Theorem 6.1 shows the correctness of our source code transformation of trace terms, in that formal differentiation corresponds to actual differentiation. Theorem 6.2 has two parts. The first is the usual statement of correctness for the ordinary evaluation relation. The second is a statement of correctness of symbolic evaluation. This states that the trace term resulting from symbolic evaluation of a term has the same denotation not only at the environment used for the symbolic evaluation but on a whole open set including it. This, and Theorem 6.1, are needed to prove the ordinary correctness of the ordinary evaluation relation in the case of differentiation as in that case ordinary evaluation proceeds by first symbolically differentiating and then applying our source code transformation. Finally Theorem 6.7 is the expected completeness theorem, that if the semantics of a term is defined, then both its ordinary and symbolic evaluation terminate. Its proof makes use of Proposition 3.5 which interpolates a symbolic evaluation inside any ordinary (non-boolean) evaluation.
6.1. Operational correctness
Theorem 6.1 (Reverse-mode differentiation).
Suppose that , and (and so ). Then, for any , we have:
The proof is by structural induction on . We give a representative case. Suppose is . Set , for any , , and . Then
with , , and . We calculate:
Note the use of Equation (10) in the the fourth step. ∎
Theorem 6.2 (Operational correctness).
Suppose that , , and . Then:
(and similarly for boolean terms).
Symbolic operational semantics.
The two parts are proved by mutual induction on the size of the proofs that establish the given operational relations, and by cases on the form of . As an example case of the second part, suppose has the form . Then for some and we have a smaller proof of , where , and has the form .
By the induction hypothesis there is an open set such that and, for all , we have . Set . As is continuous, is open. We show it is the required open set.
First, as we have: .
Second, for any we have:
with the second equality holding as .
The following corollary shows that our strategy of first symbolically reducing to produce a trace term, then symbolically differentiating, is correct.
Corollary 6.3 ().
Suppose that , , and . Then, for any and we have:
6.2. Operational completeness
We turn to proving operational completeness, that the evaluation, or symbolic evaluation, of a term terminates when it should, i.e., when its denotation is defined. For terms write when, for some , and, assuming and known from the context, say that terminates, and adopt similar terminology for boolean terms.
To prove operational completeness we use a standard strategy: first proving operational completeness for an auxiliary “approximation language” in which recursive definitions are replaced by approximations to them, which we call limited recursive definitions, and then lifting that result to the main language. Specifically we replace the syntactic form for recursive definitions by the family of syntactic forms:
with the evident typing rule, and make analogous consequential changes in the various definitions.
In the definition of function environments and closures, the clause for closures becomes:
If , , and , then
is a closure, written as: .
The limited recursive definition redexes are ; their evaluation rules are in Figure 8. There, and below, we write for limited recursion language judgements.
For the closure typing judgement we substitute:
As regards the denotational semantics, the clause for limited recursive definitions is:
The results for the operational and denotational semantics carry over to the restricted setting, and we refer to them in the same way as we do to the unrestricted versions.
Relating the two languages, the -th approximant of a language term is obtained by replacing every recursive definition in by an -limited one (similarly for boolean terms) and -th approximants of closures and function environments are defined by structural recursion:
The terms can be defined by structural recursion; we just give one clause of the definition:
Approximation preserves typing judgments.
Termination is proved for the approximation language by structural induction via a suitable notion of computability.
is computable iff or and, for all we have:
A function environment is computable iff is a computable closure, for every .
A term is computable iff for every computable and every
(and similarly for boolean terms).
Strictly speaking, in the above we should say that it is the sequent that is computable and similarly for closures and function environments.
Lemma 6.4 ().
Every closure is computable.
Every function environment is computable.
Every well-typed term is computable.
Every well-typed boolean term is computable.
The next two lemmas enable us to lift completeness from the approximation language to the main one. The first lets us pass from semantic existence in the main language to semantic existence in the approximation language; the second allows us to pass in the opposite direction from termination in the approximation language to termination in the main one.
Lemma 6.5 ().
For any well-typed term we have:
and similarly for boolean terms, closures and function environments.
Lemma 6.6 ().
For any well-typed term we have:
and similarly for boolean terms.
Operational completeness follows straightforwardly from these three lemmas:
Theorem 6.7 (Operational completeness).
Suppose that , , and , then:
(and similarly for boolean terms).
Symbolic operational semantics.
There is much more to do on the theory of differentiable programming languages, even at a basic level; we briefly suggest some possibilities. Trace-based automatic differentiation systems generally work with A-normal forms, or equivalent structures. They also employ optimizations. For example, as mentioned in the Introduction, they may record auxiliary information in evaluation traces to reduce recomputation. Other automatic differentiation systems rely on code transformations for differentiation. It would be interesting to define and study such optimizations and alternative approaches, perhaps in the setting of our language.
Another direction of interest would be to deal with non-differentiable functions used in practice like ReLU or with non-smooth functions. For the former, one might use Clarke sub-gradients (Clarke, 1990), following (Di Gianantonio and Edalat, 2013) (the Clarke sub-gradient of ReLU at is the interval ); for the latter, one may use functions. Still another possible such direction of research would be to work with approximate reals, rather than reals, and to seek numerical accuracy theorems. Here it would be natural to work with Scott’s interval domain and, generalizing the Clarke sub-gradient, a domain-theoretic notion of sub-differentiation of functions over the interval domain, as discussed in (Edalat and Lieutier, 2004; Edalat and Maleki, 2018).
One would like results for richer languages, with a wider range of types or with computational effects. The problem then to be solved is how these additional features interact with differentiation. An extension to side-effects would make contact with the literature on the automatic differentiation of imperative languages, such as Fortran. An extension to probability, in some form, would make contact with stochastic optimization and, further, with probabilistic languages for statistical learning. For higher-order types, there may be a domain-theoretic analogue of convenient vector spaces that supports the combination of higher-order types and recursion. Further, one might, as suggested in (Vákár et al., 2018), seek a domain-theoretic analogue of diffeological spaces (see (Iglesias-Zemmour, 2013)); that would also accommodate sum and recursive types. One might also wish to program with Riemannian manifolds, to accommodate natural gradient descent (Amari, 1996); these too should fit into a diffeological framework. In another direction, the work on categories with differential structure may yield an axiomatic version of adequacy theorems for programming languages with differentiation constructs; such categories further equipped with structure to model partiality (Cockett et al., 2011), are of particular interest.
Finally, if perhaps orthogonally, it is important to add explicit tensor (multi-dimensional array) types, with accompanying shape analysis. There is a long history of programming-language design in this area; a salient example is the design of Remora (Slepak et al., 2014).
- Abadi et al. (2016a) Martín Abadi, Paul Barham, Jianmin Chen, Zhifeng Chen, Andy Davis, Jeffrey Dean, Matthieu Devin, Sanjay Ghemawat, Geoffrey Irving, Michael Isard, Manjunath Kudlur, Josh Levenberg, Rajat Monga, Sherry Moore, Derek G. Murray, Benoit Steiner, Paul Tucker, Vijay Vasudevan, Pete Warden, Martin Wicke, Yuan Yu, and Xiaoqiang Zheng. 2016a. TensorFlow: a system for large-scale machine learning. In 12th USENIX Symposium on Operating Systems Design and Implementation (OSDI 16). USENIX Association, 265–283. https://www.usenix.org/conference/osdi16/technical-sessions/presentation/abadi
- Abadi et al. (2016b) Martin Abadi, Andy Chu, Ian Goodfellow, H. Brendan McMahan, Ilya Mironov, Kunal Talwar, and Li Zhang. 2016b. Deep learning with differential privacy. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security (CCS ’16). ACM, 308–318. https://doi.org/10.1145/2976749.2978318
- Abramsky and Jung (1994) Samson Abramsky and Achim Jung. 1994. Domain theory. In Handbook of Logic in Computer Science (Vol. 3), Samson Abramsky, Dov M. Gabbay, and T. S. E. Maibaum (Eds.). Oxford University Press, Inc., 1–168. http://dl.acm.org/citation.cfm?id=218742.218744
- Amari (1996) Shun-ichi Amari. 1996. Neural learning in structured parameter spaces — natural Riemannian gradient. In Advances in Neural Information Processing Systems 9, NIPS, Michael Mozer, Michael I. Jordan, and Thomas Petsche (Eds.). MIT Press, 127–133. http://papers.nips.cc/paper/1248-neural-learning-in-structured-parameter-spaces-natural-riemannian-gradient
- Baydin et al. (2018) Atilim Gunes Baydin, Barak A. Pearlmutter, Alexey Andreyevich Radul, and Jeffrey Mark Siskind. 2018. Automatic differentiation in machine learning: a survey. Journal of Machine Learning Research 18, 153 (2018), 1–43. http://jmlr.org/papers/v18/17-468.html
- Baydin et al. (2016) Atilim Günes Baydin, Barak A. Pearlmutter, and Jeffrey Mark Siskind. 2016. Tricks from deep learning. CoRR abs/1611.03777 (2016). http://arxiv.org/abs/1611.03777
- Beck and Fischer (1994) Thomas Beck and Herbert Fischer. 1994. The if-problem in automatic differentiation. J. Comput. Appl. Math. 50, 1-3 (May 1994), 119–131. https://doi.org/10.1016/0377-0427(94)90294-1
- Bergstra et al. (2010) James Bergstra, Olivier Breuleux, Frédéric Bastien, Pascal Lamblin, Razvan Pascanu, Guillaume Desjardins, Joseph Turian, David Warde-Farley, and Yoshua Bengio. 2010. Theano: A CPU and GPU math expression compiler. In Proceedings of the Python for scientific computing conference (SciPy), Vol. 4. http://www-etud.iro.umontreal.ca/~wardefar/publications/theano_scipy2010.pdf
- Bertot and Castéran (2013) Yves Bertot and Pierre Castéran. 2013. Interactive theorem proving and program development: Coq’Art: the calculus of inductive constructions. Springer Science & Business Media.
- Blute et al. (2010) Richard Blute, Thomas Ehrhard, and Christine Tasson. 2010. A convenient differential category. arXiv preprint arXiv:1006.3140 (2010).
- Blute et al. (2009) Richard F Blute, J Robin B Cockett, and Robert AG Seely. 2009. Cartesian differential categories. Theory and Applications of Categories 22, 23 (2009), 622–672.
- Bucciarelli et al. (2010) Antonio Bucciarelli, Thomas Ehrhard, and Giulio Manzonetto. 2010. Categorical models for simply typed resource calculi. Electronic Notes in Theoretical Computer Science 265 (2010), 213–230.
- Christianson (2012) Bruce Christianson. 2012. A Leibniz notation for automatic differentiation. In Recent Advances in Algorithmic Differentiation, Shaun Forth, Paul Hovland, Eric Phipps, Jean Utke, and Andrea Walther (Eds.). Lecture Notes in Computational Science and Engineering, Vol. 87. Springer, 1–9.
- Clarke (1990) Frank H. Clarke. 1990. Optimization and nonsmooth analysis. Classics in Applied Mathematics, Vol. 5. SIAM.
- Cockett et al. (2011) J Robin B Cockett, Geoff SH Cruttwell, and Jonathan D Gallagher. 2011. Differential restriction categories. Theory and Applications of Categories 25, 21 (2011), 537–613.
- de Moura et al. (2015) Leonardo Mendonça de Moura, Soonho Kong, Jeremy Avigad, Floris van Doorn, and Jakob von Raumer. 2015. The Lean Theorem Prover (System Description). In Automated Deduction - CADE-25 - 25th International Conference on Automated Deduction, Berlin, Germany, August 1-7, 2015, Proceedings (Lecture Notes in Computer Science), Amy P. Felty and Aart Middeldorp (Eds.), Vol. 9195. Springer, 378–388. https://doi.org/10.1007/978-3-319-21401-6_26
- Di Gianantonio and Edalat (2013) Pietro Di Gianantonio and Abbas Edalat. 2013. A language for differentiable functions. In Foundations of Software Science and Computation Structures, Frank Pfenning (Ed.). Springer, 337–352.
- Edalat and Lieutier (2004) Abbas Edalat and André Lieutier. 2004. Domain theory and differential calculus (functions of one variable). Mathematical Structures in Computer Science 14, 6 (2004), 771–802. https://doi.org/10.1017/S0960129504004359
- Edalat and Maleki (2018) Abbas Edalat and Mehrdad Maleki. 2018. Differential calculus with imprecise input and Its logical framework. In Foundations of Software Science and Computation Structures - 21st International Conference, FOSSACS 2018. 459–475. https://doi.org/10.1007/978-3-319-89366-2_25
- Ehrhard and Regnier (2003) Thomas Ehrhard and Laurent Regnier. 2003. The differential lambda-calculus. Theoretical Computer Science 309, 1-3 (2003), 1–41.
- Elliott (2018) Conal Elliott. 2018. The simple essence of automatic differentiation. In Proceedings of the ACM on Programming Languages (ICFP). http://conal.net/papers/essence-of-ad/
- Felleisen and Friedman (1987) Matthias Felleisen and Daniel P. Friedman. 1987. Control operators, the SECD-machine and the -calculus. In Formal Description of Programming Concepts III, M. Wirsing (Ed.). Elsevier, 193–217.
- Fischer (2001) H. Fischer. 2001. Automatic differentiation: root problem and branch problem. In Encyclopedia of Optimization, C. A. Floudas and P. M. Pardalos (Eds.). Vol. I. Kluwer Academic Publishers, 118–122.
- Frostig et al. (2018) Roy Frostig, Matthew James Johnson, and Chris Leary. 2018. Compiling machine learning programs via high-level tracing. Presented at SysML 2018, available at https://www.sysml.cc/doc/146.pdf.
- Goodfellow et al. (2016) Ian Goodfellow, Yoshua Bengio, and Aaron Courville. 2016. Deep Learning. MIT Press. https://www.deeplearningbook.org Available at https://www.deeplearningbook.org.
- Griewank (2000) Andreas Griewank. 2000. Evaluating derivatives - principles and techniques of algorithmic differentiation. Frontiers in applied mathematics, Vol. 19. SIAM.
- Hascoët and Pascual (2013) L. Hascoët and V. Pascual. 2013. The Tapenade automatic differentiation tool: principles, model, and specification. ACM Transactions On Mathematical Software 39, 3 (2013). http://dx.doi.org/10.1145/2450153.2450158
- Iglesias-Zemmour (2013) P. Iglesias-Zemmour. 2013. Diffeology. American Mathematical Society. Available at https://books.google.com/books?id=Nb0xAAAAQBAJ.
- Kriegl and Michor (1997) Andreas Kriegl and Peter W Michor. 1997. The convenient setting of global analysis. Vol. 53. American Mathematical Soc.
- Maclaurin (2017) Dougal Maclaurin. 2017. The chain rule unchained: modeling, optimization and inference with Autograd. Slides of a talk based on joint work with David Duvenaud and Matthew J. Johnson, available at https://dougalmaclaurin.com/talk.pdf.
- Maclaurin et al. (2015) Dougal Maclaurin, David Duvenaud, and Ryan P Adams. 2015. Autograd: effortless gradients in Numpy. In ICML 2015 AutoML Workshop, Vol. 238.
- Manzyuk (2012) Oleksandr Manzyuk. 2012. A simply typed -calculus of forward automatic differentiation. Electronic Notes in Theoretical Computer Science 286 (2012), 257 – 272. https://doi.org/10.1016/j.entcs.2012.08.017 Proceedings of the 28th Conference on the Mathematical Foundations of Programming Semantics (MFPS XXVIII).
- Mayero (2002) Micaela Mayero. 2002. Using theorem proving for numerical analysis (correctness proof of an automatic differentiation algorithm). In Theorem Proving in Higher Order Logics, 15th International Conference, TPHOLs 2002, Hampton, VA, USA, August 20-23, 2002, Proceedings (Lecture Notes in Computer Science), Victor Carreño, César A. Muñoz, and Sofiène Tahar (Eds.), Vol. 2410. Springer, 246–262. https://doi.org/10.1007/3-540-45685-6_17
- Pearlmutter and Siskind (2008) Barak A. Pearlmutter and Jeffrey Mark Siskind. 2008. Reverse-mode AD in a functional framework: lambda the ultimate backpropagator. ACM Trans. Program. Lang. Syst. 30, 2 (2008), 7:1–7:36. https://doi.org/10.1145/1330017.1330018
- PyTorch (2018) PyTorch. 2018. http://pytorch.org http://pytorch.org.
- Selsam et al. (2017) Daniel Selsam, Percy Liang, and David L. Dill. 2017. Developing bug-free machine learning systems with formal mathematics. In Proceedings of the 34th International Conference on Machine Learning, ICML 2017, Sydney, NSW, Australia, 6-11 August 2017 (Proceedings of Machine Learning Research), Doina Precup and Yee Whye Teh (Eds.), Vol. 70. PMLR, 3047–3056. http://proceedings.mlr.press/v70/selsam17a.html
- Shaikhha et al. (2018) Amir Shaikhha, Andrew Fitzgibbon, Dimitrios Vytiniotis, Simon Peyton Jones, and Christoph Koch. 2018. Efficient differentiable programming in a functional array-processing language. CoRR abs/1806.02136 (2018). arXiv:1806.02136 http://arxiv.org/abs/1806.02136 http://arxiv.org/abs/1806.02136.
- Shankar and Dobson (2017) Asim Shankar and Wolff Dobson. 2017. Eager execution: an imperative, define-by-run interface to TensorFlow. https://research.googleblog.com/2017/10/eager-execution-imperative-define-by.html https://research.googleblog.com/2017/10/eager-execution-imperative-define-by.html.
- Siskind and Pearlmutter (2005) Jeffrey Mark Siskind and Barak A. Pearlmutter. 2005. Perturbation confusion and referential transparency: correct functional implementation of forward-mode AD. In Implementation and Application of Functional Languages—17th International Workshop, IFL’05, Andrew Butterfield (Ed.). 1–9. Trinity College Dublin, Computer Science Department Technical Report TCD-CS-2005-60.
- Siskind and Pearlmutter (2008) Jeffrey Mark Siskind and Barak A. Pearlmutter. 2008. Nesting forward-mode AD in a functional framework. Higher-Order and Symbolic Computation 21, 4 (2008), 361–376. https://doi.org/10.1007/s10990-008-9037-1
- Slepak et al. (2014) Justin Slepak, Olin Shivers, and Panagiotis Manolios. 2014. An array-oriented language with static rank polymorphism. In Proceedings of the 23rd European Symposium on Programming Languages and Systems - Volume 8410. Springer-Verlag New York, Inc., 27–46. https://doi.org/10.1007/978-3-642-54833-8_3
- Song et al. (2013) Shuang Song, Kamalika Chaudhuri, and Anand D. Sarwate. 2013. Stochastic gradient descent with differentially private updates. In IEEE Global Conference on Signal and Information Processing, GlobalSIP 2013, Austin, TX, USA, December 3-5, 2013. IEEE, 245–248. https://doi.org/10.1109/GlobalSIP.2013.6736861
- Tokui (2018) Seiya Tokui. 2018. Chainer: a powerful, flexible and intuitive framework of neural networks. http://chainer.org http://chainer.org.
- Trench (2003) W.F. Trench. 2003. Introduction to Real Analysis. Prentice Hall/Pearson Education. Available at https://books.google.com/books?id=NkFkQgAACAAJ.
- Vákár et al. (2018) M. Vákár, O. Kammar, and S. Staton. 2018. Diffeological spaces and semantics for differential programming. https://andrejbauer.github.io/domains-floc-2018/slides/Matthijs-Kammar-Staton.pdf. Presented at Domains XIII Workshop.
- van Merrienboer et al. (2018) Bart van Merrienboer, Dan Moldovan, and Alexander B. Wiltschko. 2018. Tangent: automatic differentiation using source-code transformation for dynamically typed array programming. In Advances in Neural Information Processing Systems 31: Annual Conference on Neural Information Processing Systems 2018, NeurIPS 2018, 3-8 December 2018, Montréal, Canada., Samy Bengio, Hanna M. Wallach, Hugo Larochelle, Kristen Grauman, Nicolò Cesa-Bianchi, and Roman Garnett (Eds.). 6259–6268. http://papers.nips.cc/paper/7863-tangent-automatic-differentiation-using-source-code-transformation-for-dynamically-typed-array-programming
- Wang et al. (2018) Fei Wang, Xilun Wu, Grégory M. Essertel, James M. Decker, and Tiark Rompf. 2018. Demystifying differentiable programming: shift/reset the penultimate backpropagator. CoRR abs/1803.10228 (2018). arXiv:1803.10228 http://arxiv.org/abs/1803.10228 http://arxiv.org/abs/1803.10228.
- Yu et al. (2018) Yuan Yu, Martín Abadi, Paul Barham, Eugene Brevdo, Mike Burrows, Andy Davis, Jeff Dean, Sanjay Ghemawat, Tim Harley, Peter Hawkins, Michael Isard, Manjunath Kudlur, Rajat Monga, Derek Murray, and Xiaoqiang Zheng. 2018. Dynamic control flow in large-scale machine learning. In Proceedings of the Thirteenth EuroSys Conference (EuroSys ’18). ACM, Article 18, 15 pages. https://doi.org/10.1145/3190508.3190551