1. Make it easy for external contributors to write new elementory computaiton operations.
1. Making it easy for external contributors to write new elementary computation operations.
1. Make the codebase clean and readable.
1. Making the codebase clean and readable.
1. Introduce a new design of computation representation -- a computation graph of operators and variables.
1. Designing a new computation representation -- a computation graph of operators and variables.
1. The graph representation helps implementing auto-scalable and auto fault recoverable distributed computing.
1. Implementing auto-scalability and auto fault recoverable distributed computing with the help of computation graphs.
## Computation Graphs
## Computation Graphs
1. PaddlePaddle represent the computation, training and inference of DL models, by computation graphs.
1. PaddlePaddle represents the computation, training and inference of Deep Learning models, by computation graphs.
1. Please dig into [computation graphs](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/graph.md) for a solid example.
1. Please refer to [computation graphs](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/graph.md) for a concrete example.
1. Users write Python programs to describe the graphs and run it (locally or remotely).
1. Users write Python programs to describe the graphs and run them (locally or remotely).
1. A graph is composed of *variables* and *operators*.
1. A graph is composed of *variables* and *operators*.
1. The description of graphs must be able to be serialized/deserialized, so it
1. The description of graphs must be capable of being serialized/deserialized, so that
1. could to be sent to the cloud for distributed execution, and
1. It can to be sent to the cloud for distributed execution, and
1. be sent to clients for mobile or enterprise deployment.
1. It can be sent to clients for mobile or enterprise deployment.
1. The Python program do
1. The Python program does the following steps
1. *compilation*: runs a Python program to generate a protobuf message representation of the graph and send it to
1. *compilation*: run a Python program to generate a protobuf message representation of the graph and send it to
1. the C++ library `libpaddle.so` for local execution,
1. the C++ library `libpaddle.so` for local execution,
1. the master process of a distributed training job for training, or
1. the master process of a distributed training job for training, or
1. the server process of a Kubernetes serving job for distributed serving.
1. the server process of a Kubernetes serving job for distributed serving.
1. *execution*: according to the protobuf message, constructs instances of class `Variable` and `OperatorBase`, and run them.
1. *execution*: execute the graph by constructing instances of class [`Variable`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/framework/variable.h#L24) and [`OperatorBase`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/framework/operator.h#L70), according to the protobuf message.
## Description and Realization
## Description and Realization of Computation Graph
At compile time, the Python program generates protobuf message representation of the graph, or the description of the graph.
At compile time, the Python program generates a protobuf message representation of the graph, or the description of the graph.
At runtime, the C++ program realizes the graph and run it.
At runtime, the C++ program realizes the graph and runs it.
The word *graph* is exchangable with *block* in this document. A graph represent computation steps and local variables as a C++/Java program block, or a pair of { and }.
The word *graph* is interchangeable with *block* in this document. A graph represents computation steps and local variables similar to a C++/Java program block, or a pair of parentheses(`{` and `}`).
## Compilation and Execution
## Compilation and Execution
1. Run an applicaton Python program to describe the graph. In particular,
1. Run an application Python program to describe the graph. In particular, the Python application program does the following:
1. create VarDesc to represent local/intermediate variables,
1. Create `VarDesc` to represent local/intermediate variables,
1. create operators and set attributes,
1. Create operators and set attributes,
1. validate attribute values,
1. Validate attribute values,
1. inference the type and the shape of variables,
1. Infer the type and the shape of variables,
1. plan for memory-reuse for variables,
1. Plan memory-reuse for variables,
1. generate backward and optimization part of the Graph.
1. Generate the backward graph
1. possiblly split the graph for distributed training.
1. Optimize the computation graph.
1. Potentially, split the graph for distributed training.
1. The invocation of `train` or `infer` in the application Python program:
1. The invocation of `train` or [`infer`](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/inference.py#L108) methods in the application Python program does the following:
1. create a new Scope instance in the [scope hierarchy](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/scope.md) for each run of a block,
1. Create a new Scope instance in the [scope hierarchy](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/scope.md) for each run of a block,
1. realize local variables defined in the BlockDesc message in the new scope,
1. realize local variables defined in the BlockDesc message in the new scope,
1. a scope is similar to the stack frame in programming languages,
1. a scope is similar to the stack frame in programming languages,
1. create an instance of class `Block`, in which,
1. Create an instance of class `Block`, in which,
1. realize operators in the BlockDesc message,
1. realize operators in the BlockDesc message,
1. run the Block by calling
1. Run the Block by calling
1. `Block::Eval(vector<Variable>* targets)` for forward and backward computations, or
1. `Block::Eval(vector<Variable>* targets)` for forward and backward computations, or
1. `Block::Eval(vector<Operator>* targets)` for optimization.
1. `Block::Eval(vector<Operator>* targets)` for optimization.
...
@@ -76,14 +77,14 @@ The word *graph* is exchangable with *block* in this document. A graph represen
...
@@ -76,14 +77,14 @@ The word *graph* is exchangable with *block* in this document. A graph represen
Compile Time -> IR -> Runtime
Compile Time -> IR -> Runtime
```
```
### Benefit
### Benefits of IR
- Optimization
- Optimization
```text
```text
Compile Time -> IR -> Optimized IR -> Runtime
Compile Time -> IR -> Optimized IR -> Runtime
```
```
- Send automatically partitioned IR to different nodes.
- Automatically send partitioned IR to different nodes.
- Automatic data parallel
- Automatic Data Parallelism
```text
```text
Compile Time
Compile Time
|-> Single GPU IR
|-> Single GPU IR
...
@@ -92,7 +93,7 @@ Compile Time -> IR -> Runtime
...
@@ -92,7 +93,7 @@ Compile Time -> IR -> Runtime
|-> Node-1 (runs trainer-IR-1)
|-> Node-1 (runs trainer-IR-1)
|-> Node-2 (runs pserver-IR)
|-> Node-2 (runs pserver-IR)
```
```
- Automatic model parallel (planned for future)
- Automatic Model Parallelism (planned for future)
---
---
...
@@ -105,10 +106,10 @@ Compile Time -> IR -> Runtime
...
@@ -105,10 +106,10 @@ Compile Time -> IR -> Runtime
* `Operator` is the fundamental building block as the user interface.
* `Operator` is the fundamental building block of the user interface.
* Operator stores input/output variable name, and attributes.
* Operator stores input/output variable names, and attributes.
* The `InferShape` interface is used to infer output variable shapes by its input shapes.
* The `InferShape` interface is used to infer the shape of the output variable shapes based on the shapes of the input variables.
* Use `Run` to compute `input variables` to `output variables`.
* Use `Run` to compute the `output` variables from the `input` variables.
---
---
...
@@ -126,30 +127,30 @@ Compile Time -> IR -> Runtime
...
@@ -126,30 +127,30 @@ Compile Time -> IR -> Runtime
# Why separate Kernel and Operator
# Why separate Kernel and Operator
* Separate GPU and CPU code.
* Separate GPU and CPU code.
* Make Paddle can run without GPU.
* Make Paddle capable of running without GPU.
* Make one operator (which is user interface) can contain many implementations.
* Make one operator (which is a user interface) and create many implementations.
* Same mul op, different FP16, FP32 Kernel. different MKL, eigen kernel.
* For example, same multiplication op can have different implementations kernels such as FP16 kernel, FP32 kernel, MKL, eigen kernel.
---
---
# Libraries for Kernel development
# Libraries for Kernel development
* `Eigen::Tensor` contains basic math and element-wise functions.
* `Eigen::Tensor` contains basic math and element-wise functions.
* Note that `Eigen::Tensor` has broadcast implementation.
* Note that `Eigen::Tensor` has broadcast implementation.
* Limit number of `tensor.device(dev) = ` in your code.
* Limit the number of `tensor.device(dev) = ` in your code.
* `thrust::tranform` and `std::transform`.
* `thrust::tranform` and `std::transform`.
* `thrust` has the same API as C++ standard library. Using `transform` can quickly implement a customized elementwise kernel.
* `thrust` has the same API as C++ standard library. Using `transform`, one can quickly implement customized elementwise kernels.
* `thrust` has more complex API, like `scan`, `reduce`, `reduce_by_key`.
* `thrust` also has more complex APIs, like `scan`, `reduce`, `reduce_by_key`.
* Hand-writing `GPUKernel` and `CPU` code
* Hand-writing `GPUKernel` and `CPU` code
* Do not write `.h`. CPU Kernel should be in `.cc`. GPU kernel should be in `.cu`. (`GCC` cannot compile GPU code.)
* Do not write in header (`.h`) files. CPU Kernel should be in cpp source (`.cc`) and GPU kernels should be in cuda (`.cu`) files. (GCC cannot compile GPU code.)
---
---
# Operator Register
# Operator Registration
## Why register is necessary?
## Why registration is necessary?
We need a method to build mappings between Op type names and Op classes.
We need a method to build mappings between Op type names and Op classes.
## How to do the register?
## How is registration implemented?
Maintain a map, whose key is the type name and value is corresponding Op constructor.
Maintaining a map, whose key is the type name and the value is the corresponding Op constructor.
1. Make it easy for external contributors to write new elementory computaiton operations.
1. Making it easy for external contributors to write new elementary computation operations.
1. Make the codebase clean and readable.
1. Making the codebase clean and readable.
1. Introduce a new design of computation representation -- a computation graph of operators and variables.
1. Designing a new computation representation -- a computation graph of operators and variables.
1. The graph representation helps implementing auto-scalable and auto fault recoverable distributed computing.
1. Implementing auto-scalability and auto fault recoverable distributed computing with the help of computation graphs.
## Computation Graphs
## Computation Graphs
1. PaddlePaddle represent the computation, training and inference of DL models, by computation graphs.
1. PaddlePaddle represents the computation, training and inference of Deep Learning models, by computation graphs.
1. Please dig into [computation graphs](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/graph.md) for a solid example.
1. Please refer to [computation graphs](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/graph.md) for a concrete example.
1. Users write Python programs to describe the graphs and run it (locally or remotely).
1. Users write Python programs to describe the graphs and run them (locally or remotely).
1. A graph is composed of *variables* and *operators*.
1. A graph is composed of *variables* and *operators*.
1. The description of graphs must be able to be serialized/deserialized, so it
1. The description of graphs must be capable of being serialized/deserialized, so that
1. could to be sent to the cloud for distributed execution, and
1. It can to be sent to the cloud for distributed execution, and
1. be sent to clients for mobile or enterprise deployment.
1. It can be sent to clients for mobile or enterprise deployment.
1. The Python program do
1. The Python program does the following steps
1. *compilation*: runs a Python program to generate a protobuf message representation of the graph and send it to
1. *compilation*: run a Python program to generate a protobuf message representation of the graph and send it to
1. the C++ library `libpaddle.so` for local execution,
1. the C++ library `libpaddle.so` for local execution,
1. the master process of a distributed training job for training, or
1. the master process of a distributed training job for training, or
1. the server process of a Kubernetes serving job for distributed serving.
1. the server process of a Kubernetes serving job for distributed serving.
1. *execution*: according to the protobuf message, constructs instances of class `Variable` and `OperatorBase`, and run them.
1. *execution*: execute the graph by constructing instances of class [`Variable`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/framework/variable.h#L24) and [`OperatorBase`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/framework/operator.h#L70), according to the protobuf message.
## Description and Realization
## Description and Realization of Computation Graph
At compile time, the Python program generates protobuf message representation of the graph, or the description of the graph.
At compile time, the Python program generates a protobuf message representation of the graph, or the description of the graph.
At runtime, the C++ program realizes the graph and run it.
At runtime, the C++ program realizes the graph and runs it.
The word *graph* is exchangable with *block* in this document. A graph represent computation steps and local variables as a C++/Java program block, or a pair of { and }.
The word *graph* is interchangeable with *block* in this document. A graph represents computation steps and local variables similar to a C++/Java program block, or a pair of parentheses(`{` and `}`).
## Compilation and Execution
## Compilation and Execution
1. Run an applicaton Python program to describe the graph. In particular,
1. Run an application Python program to describe the graph. In particular, the Python application program does the following:
1. create VarDesc to represent local/intermediate variables,
1. Create `VarDesc` to represent local/intermediate variables,
1. create operators and set attributes,
1. Create operators and set attributes,
1. validate attribute values,
1. Validate attribute values,
1. inference the type and the shape of variables,
1. Infer the type and the shape of variables,
1. plan for memory-reuse for variables,
1. Plan memory-reuse for variables,
1. generate backward and optimization part of the Graph.
1. Generate the backward graph
1. possiblly split the graph for distributed training.
1. Optimize the computation graph.
1. Potentially, split the graph for distributed training.
1. The invocation of `train` or `infer` in the application Python program:
1. The invocation of `train` or [`infer`](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/inference.py#L108) methods in the application Python program does the following:
1. create a new Scope instance in the [scope hierarchy](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/scope.md) for each run of a block,
1. Create a new Scope instance in the [scope hierarchy](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/scope.md) for each run of a block,
1. realize local variables defined in the BlockDesc message in the new scope,
1. realize local variables defined in the BlockDesc message in the new scope,
1. a scope is similar to the stack frame in programming languages,
1. a scope is similar to the stack frame in programming languages,
1. create an instance of class `Block`, in which,
1. Create an instance of class `Block`, in which,
1. realize operators in the BlockDesc message,
1. realize operators in the BlockDesc message,
1. run the Block by calling
1. Run the Block by calling
1. `Block::Eval(vector<Variable>* targets)` for forward and backward computations, or
1. `Block::Eval(vector<Variable>* targets)` for forward and backward computations, or
1. `Block::Eval(vector<Operator>* targets)` for optimization.
1. `Block::Eval(vector<Operator>* targets)` for optimization.
...
@@ -76,14 +77,14 @@ The word *graph* is exchangable with *block* in this document. A graph represen
...
@@ -76,14 +77,14 @@ The word *graph* is exchangable with *block* in this document. A graph represen
Compile Time -> IR -> Runtime
Compile Time -> IR -> Runtime
```
```
### Benefit
### Benefits of IR
- Optimization
- Optimization
```text
```text
Compile Time -> IR -> Optimized IR -> Runtime
Compile Time -> IR -> Optimized IR -> Runtime
```
```
- Send automatically partitioned IR to different nodes.
- Automatically send partitioned IR to different nodes.
- Automatic data parallel
- Automatic Data Parallelism
```text
```text
Compile Time
Compile Time
|-> Single GPU IR
|-> Single GPU IR
...
@@ -92,7 +93,7 @@ Compile Time -> IR -> Runtime
...
@@ -92,7 +93,7 @@ Compile Time -> IR -> Runtime
|-> Node-1 (runs trainer-IR-1)
|-> Node-1 (runs trainer-IR-1)
|-> Node-2 (runs pserver-IR)
|-> Node-2 (runs pserver-IR)
```
```
- Automatic model parallel (planned for future)
- Automatic Model Parallelism (planned for future)
---
---
...
@@ -105,10 +106,10 @@ Compile Time -> IR -> Runtime
...
@@ -105,10 +106,10 @@ Compile Time -> IR -> Runtime
* `Operator` is the fundamental building block as the user interface.
* `Operator` is the fundamental building block of the user interface.
* Operator stores input/output variable name, and attributes.
* Operator stores input/output variable names, and attributes.
* The `InferShape` interface is used to infer output variable shapes by its input shapes.
* The `InferShape` interface is used to infer the shape of the output variable shapes based on the shapes of the input variables.
* Use `Run` to compute `input variables` to `output variables`.
* Use `Run` to compute the `output` variables from the `input` variables.
---
---
...
@@ -126,30 +127,30 @@ Compile Time -> IR -> Runtime
...
@@ -126,30 +127,30 @@ Compile Time -> IR -> Runtime
# Why separate Kernel and Operator
# Why separate Kernel and Operator
* Separate GPU and CPU code.
* Separate GPU and CPU code.
* Make Paddle can run without GPU.
* Make Paddle capable of running without GPU.
* Make one operator (which is user interface) can contain many implementations.
* Make one operator (which is a user interface) and create many implementations.
* Same mul op, different FP16, FP32 Kernel. different MKL, eigen kernel.
* For example, same multiplication op can have different implementations kernels such as FP16 kernel, FP32 kernel, MKL, eigen kernel.
---
---
# Libraries for Kernel development
# Libraries for Kernel development
* `Eigen::Tensor` contains basic math and element-wise functions.
* `Eigen::Tensor` contains basic math and element-wise functions.
* Note that `Eigen::Tensor` has broadcast implementation.
* Note that `Eigen::Tensor` has broadcast implementation.
* Limit number of `tensor.device(dev) = ` in your code.
* Limit the number of `tensor.device(dev) = ` in your code.
* `thrust::tranform` and `std::transform`.
* `thrust::tranform` and `std::transform`.
* `thrust` has the same API as C++ standard library. Using `transform` can quickly implement a customized elementwise kernel.
* `thrust` has the same API as C++ standard library. Using `transform`, one can quickly implement customized elementwise kernels.
* `thrust` has more complex API, like `scan`, `reduce`, `reduce_by_key`.
* `thrust` also has more complex APIs, like `scan`, `reduce`, `reduce_by_key`.
* Hand-writing `GPUKernel` and `CPU` code
* Hand-writing `GPUKernel` and `CPU` code
* Do not write `.h`. CPU Kernel should be in `.cc`. GPU kernel should be in `.cu`. (`GCC` cannot compile GPU code.)
* Do not write in header (`.h`) files. CPU Kernel should be in cpp source (`.cc`) and GPU kernels should be in cuda (`.cu`) files. (GCC cannot compile GPU code.)
---
---
# Operator Register
# Operator Registration
## Why register is necessary?
## Why registration is necessary?
We need a method to build mappings between Op type names and Op classes.
We need a method to build mappings between Op type names and Op classes.
## How to do the register?
## How is registration implemented?
Maintain a map, whose key is the type name and value is corresponding Op constructor.
Maintaining a map, whose key is the type name and the value is the corresponding Op constructor.