Executor Design Doc

Motivation

In fluid, we encourage the user to use deep learning programming paradigms to describe the training process. When the user-written Python program is executed, it will first create a protobuf message ProgramDesc that describes the process and is conceptually like an abstract syntax tree.

The executor runs the ProgramDesc like an interpreter. ProgramDesc contains the intrinsics (operators in this case) and variables which will be used, executor explicitly executes the stored precompiled code.

Overview

An executor takes a ProgramDesc, a block_id and a Scope. The ProgramDesc is a list of blocks and each block contains the protobuf definition of all the parameters and operators in the block. The block_id specifies the entrance block. And the Scope is the container of all the variable instances, which is persistent throughout different runs.

Executor

The Executor explicitly executes all the intrinsics (operators here) in the block_idth block of a ProgramDesc. Essentially, it instantiates Variables and Operators, then runs all the operators in sequence one-by-one. It is very similar to how a push stack frame works when entering a block, following which it cleans up all the temporary variables when a mini-batch is finished. It does not however, have the stack frame pop process.

The interface

  Executor(places);

A executor does not own any computing resources, a user can only construct an executor using the specified places.

Running an Executor

  void Run(ProgramDesc, Scope, block_id, create_local_scope);

An Executor only provides a unified way to execute ProgramDesc. ProgramDesc is the target that will be executed, the Scope specifies the variable container, the block_id indicates the entrance block and create_local_scope is a boolean that states whether it will destroy the temporary variables after the execution is finished.