Backpropagation

Last but not least, KeOps fully supports automatic differentiation. Most of the magic required is implemented by the F::DiffT attributes of KeOps formulas and reductions, as discussed in previous pages.

Backprop through a Sum reduction

Then, to implement the PyTorch backward of the KeOps Genred operator, we simply have to remember that if (gi)RM×E is a “gradient to backpropagate” with respect to the output (ai)RM×E of a Genred call with a Sum reduction, we can write that for all variations (δp,δxi,δyj) of the parameters, i- and j-variables, at order 1:

j=1NF(p+δp,xi+δxi,yj+δyj)F(p,xi,yj) , giRM×E = i=1Mj=1N(pF()gi,δp+xiF()gi,δxi+yjF()gi,δyj).

Consequently, performing the appropriate permutations of sums:

xi[j=1NF(p,xi,yj)](gi) = i=1Mj=1N(xi[F(p,xi,yj)]gi),yj[j=1NF(p,xi,yj)](gi) = i=1Mi=1M(yj[F(p,xi,yj)]gi),p[j=1NF(p,xi,yj)](gi) = i=1Mj=1N(p[F(p,xi,yj)]gi).

Backprop through a Log-Sum-Exp reduction

Similarly, when (ai) is given through a Log-Sum-Exp reduction:

ai = logj=1NexpF(p,xi,yj),

straightforward computations show that:

xi[logj=1NexpF(p,xi,yj)](gi) = i=1Mj=1NeF(p,xi,yj)ai(xi[F(p,xi,yj)]gi),yj[logj=1NexpF(p,xi,yj)](gi) = i=1Mi=1MeF(p,xi,yj)ai(yj[F(p,xi,yj)]gi),p[logj=1NexpF(p,xi,yj)](gi) = i=1Mj=1NeF(p,xi,yj)ai(p[F(p,xi,yj)]gi).

In other words, a backward pass through a Genred call that involves a Sum or a Log-Sum-Exp reduction can always be written as a symbolic Map-Reduce computation.

Bootstrapping derivatives of arbitrary order

Applying these commutation rules between the differential operator V and the Sum or Log-Sum-Exp reductions, the pykeops/torch/generic/generic_red.py module provides full compatibility between KeOps LazyTensors and the torch.autograd package. Thanks to recursive calls to the Genred operator and to our symbolic math engine, everything works just fine – even high-order derivatives.