CoDiPack  2.2.0
A Code Differentiation Package
SciComp TU Kaiserslautern
Loading...
Searching...
No Matches
Tutorial 2 - Reverse mode AD

Goal: Introduction to reverse mode AD with CoDiPack.

Prerequisite: AD reverse mode. See Reverse AD Equation

Function: Simple real valued function

Real func(const Real& x) {
return x * x * x;
}
Represents a concrete lvalue in the CoDiPack expression tree.
Definition: activeType.hpp:52

Full code:

#include <codi.hpp>
#include <iostream>
using Tape = typename Real::Tape;
Real func(const Real& x) {
return x * x * x;
}
int main(int nargs, char** args) {
Real x = 4.0;
Tape& tape = Real::getTape();
tape.setActive(); // Step 1: Start recording
tape.registerInput(x); // Step 2: Register inputs
Real y = func(x); // Step 3: Call function
tape.registerOutput(y); // Step 4: Register outputs
tape.setPassive(); // Step 5: Stop recording
y.setGradient(1.0); // Step 6: Set seeding
tape.evaluate(); // Step 7: Perform reverse evaluation
// Step 8: Access gradients
std::cout << "f(4.0) = " << y << std::endl;
std::cout << "df/dx(4.0) = " << x.getGradient() << std::endl;
tape.reset(); // Step 9: Clean tape and adjoints
return 0;
}
RealReverseGen< double > RealReverse
Definition: codi.hpp:120
static Tape & getTape()
Get a reference to the tape which manages this expression.
Definition: activeType.hpp:99
T_Tape Tape
See ActiveType.
Definition: activeType.hpp:55
void setGradient(Gradient const &g)
Set the gradient of this lvalue in the tape.
Definition: lhsExpressionInterface.hpp:120
Gradient getGradient() const
Get the gradient of this lvalue from the tape.
Definition: lhsExpressionInterface.hpp:115

The derivative computation with the reverse mode of CoDiPack needs in total nine steps:

  • Start the recording
  • A definition of the input variables.
  • Record the function evaluation on the tape.
  • A definition of the output variables.
  • Stop the recording.
  • Setting the direction of the derivative.
  • Evaluate the tape recorded by CoDiPack.
  • Get the results of the derivatives.
  • Clear the tape and adjoints.

Most of these steps need to call functions on the global tape structure of CoDiPack. This structure can be accessed with the function getTape.

Step 1: Start the recording

For this step, it is sufficient to call the method setActive. This will enable the recording in CoDiPack for all statements evaluated after the setActive call.

Step 2: Defining the input variables

In the reverse AD equation, the variable $x$ describes the vector of input variables. CoDiPack needs to know about all these values. On each one, the method registerInput needs to be called.

Step 3: Recording the function evaluation

In this step, CoDiPack is only indirectly involved. The function $f$ needs to be evaluated in the program and CoDiPack needs to record the statements that are called during the evaluation. It is therefore necessary to write the function $f$ such that it uses the CoDiPack type. How this is done depends on the program that is differentiated. The best option is to write the function as a template function such that the calculation type is flexible. The second option is most of the time used when software with a large code base is differentiated. Here, a global typedef like using Real = codi::RealReverse is used and all doubles in the program are changed to this typedef. The calculation type can then be changed during compile time and different executables can be generated.

Step 4: Defining the output variables

In the reverse AD equation, the variable $y$ describes the vector of output variables. CoDiPack needs to know about all these values. On each one, the method registerOutput needs to be called.

Step 5: Stop the recording

For this step it is sufficient to call the method setPassive. This will disable the recording in CoDiPack for all statements evaluated after the setPassive call.

Step 6: Setting the direction of the derivative

In the reverse AD equation, the variable $\bar y$ is the vector of adjoint output variables. Since these variables serve in the reverse mode of AD as inputs, they need to be defined before the reverse evaluation is started. The ''bar'' values of the variables can be accessed via the functions gradient and setGradient. The default value is zero for the gradients.

For an access to the gradient data for variables which run out of scope, see Direct data access (Identifier management).

Step 7: Evaluating the tape

The simplest way to evaluate the full tape is to call the method evaluate. This will evaluate the full tape from the last recorded statement to the first one.

For a partial evaluation of the tape see Example 3 - Positional tape evaluations. There are also other evaluation possibilities available, which are described in other Tutorials.

Step 8: Get the resulting derivatives

In the reverse AD equation, the variable $\bar x$ is the vector of adjoint input variables. After an evaluation of the tape, these values are populated with the derivative data. The ''bar'' values of the variables can be accessed via the functions gradient and getGradient.

CoDiPack will clear these values only when the tape is reset or the adjoints are cleared. If these calls are forgotten and multiples evaluations are performed, then the derivative data will be accumulated.

Step 9: Clear the tape and adjoints

The last step is very important when multiple tape evaluations or recordings are performed during one program execution. A tape can be reset via the function reset.

Depending on the use case, a full tape reset might not be necessary. See Tutorial 3 - Full Jacobian computation (Multiple reverse evaluations) and Tutorial 5 - Repeated tape recordings for more details.