詹荣瑞@zrr1999
Paddle Committer, PFCC Member, PPDE
设计思路
后续工作
项目演示
项目介绍
詹荣瑞@zrr1999
Paddle Committer, PFCC Member, PPDE
项目介绍
设计思路
后续工作
项目演示
PaddleFX 是一个 Python 层的运行时编译器项目。可以在 Python 代码执行前通过分析 Python 字节码来产出计算子图对子图进行图优化,并在某个计算后端上进行执行。PaddleFX 是一个社区项目,用于实验新技术的可行性。
詹荣瑞@zrr1999
Paddle Committer, PFCC Member, PPDE
项目介绍
设计思路
后续工作
项目演示
PaddleFX 是一个 Python 层的运行时编译器项目。可以在 Python 代码执行前通过分析 Python 字节码来产出计算子图对子图进行图优化,并在某个计算后端上进行执行。PaddleFX 是一个社区项目,用于实验新技术的可行性。
1. 分析 Python 字节码来产出计算子图。
2. 对子图进行图优化。
3. 在某个计算后端上进行执行。
PaddleSOT是Paddle 用于提升动转静训练成功率和和接入AI编译器CINN提升性能的子项目,已处于预发布状态。Python 3.11的支持是项目近期最重要的内容。
项目介绍
设计思路
后续工作
项目演示
PaddleFX 是一个 Python 层的运行时编译器项目。可以在 Python 代码执行前通过分析 Python 字节码来产出计算子图对子图进行图优化,并在某个计算后端上进行执行。PaddleFX 是一个社区项目,用于实验新技术的可行性。
1. 分析 Python 字节码来产出计算子图。
2. 对子图进行图优化。
3. 在某个计算后端上进行执行。
与 PaddleFX 相同,PaddleSOT 也是一个 Python 层的运行时编译器项目。不同的是 PaddleSOT 是 Paddle 的一个子项目,仅用于将 Paddle 的动态图转为静态图。
项目介绍
设计思路
后续工作
项目演示
新IR底层核心逻辑已经成熟,需要进一步推广验证。当前新IR仅限于在C++底层进行操作,为了能够尽快让新 IR 替代现有的 IR 体系,需要打通 Python 端到C++端的新IR链路。
项目介绍
设计思路
后续工作
项目演示
新IR底层核心逻辑已经成熟,需要进一步推广验证。当前新IR仅限于在C++底层进行操作,为了能够尽快让新 IR 替代现有的 IR 体系,需要打通 Python 端到C++端的新IR链路。
计算图中间表达
生成字节码
原始字节码
执行后端
项目介绍
设计思路
后续工作
项目演示
计算图中间表达
字节码生成器
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
生成字节码
原始字节码
PaddleFX 执行后端
项目介绍
设计思路
后续工作
项目演示
计算图中间表达
字节码生成器
字节码指令执行器
生成字节码
原始字节码
PaddleFX 执行后端
可执行模块
缓存管理器
后端编译器
命中
未命中
项目介绍
设计思路
后续工作
项目演示
import paddle
import paddlefx
from paddle.vision.models import resnet18
net = resnet18(pretrained=True, num_classes=2)
net.eval()
compiled_func = paddlefx.optimize(net)
x = paddle.rand([1, 3, 224, 224], dtype="float32")
out = comiled_func(x)
项目介绍
设计思路
后续工作
项目演示
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
字节码指令执行器
字节码生成器
自定义后端机制
字节码生成器
自定义后端机制
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
x
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
x
y
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
x
y
tmp
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
x
y
tmp
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
x
tmp
out
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
x
tmp
out
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
TensorVariable(x)
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
TensorVariable(x)
TensorVariable(y)
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
TensorVariable(...)
TensorVariable(x)
TensorVariable(y)
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
x
y
TensorVariable(...)
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
| BINARY_MULTIPLY |
| RETURN_VALUE |
TensorVariable(...)
TensorVariable(x)
TensorVariable(...)
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
TensorVariable(...)
TensorVariable(x)
TensorVariable(...)
def func(x, y):
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
def func(x, y):
print()
out = (x + y)*x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| LOAD_GLOBAL print |
|---|
| CALL_FUNCTION |
| POP_TOP |
def func(x, y):
z = x + y
print()
out = z * x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
TensorVariable(x)
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
项目介绍
设计思路
后续工作
项目演示
字节码指令执行器
| POP_TOP |
|---|
def func(x, y):
z = x + y
print()
out = z * x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
TensorVariable(x)
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_GLOBAL print |
| CALL_FUNCTION |
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
TensorVariable(z)
项目介绍
设计思路
后续工作
项目演示
TensorVariable(z)
| POP_TOP |
|---|
TensorVariable(x)
| LOAD_FAST x |
|---|
| LOAD_FAST y |
| BINARY_ADD |
| LOAD_GLOBAL print |
| CALL_FUNCTION |
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
| POP_TOP |
|---|
| LOAD_FAST x |
|---|
| BINARY_MULTIPLY |
| RETURN_VALUE |
| LOAD_FAST z |
|---|
| ... |
def func(x, y):
z = x + y
print()
out = z * x
return out
compiled_func = paddlefx.optimize(func)
in_a = paddle.rand([8, 16])
in_b = paddle.rand([8, 16])
out = comiled_func(in_a, in_b)
项目介绍
设计思路
后续工作
项目演示
| 4 POP_TOP |
|---|
| 6 LOAD_FAST x |
|---|
| 8 BINARY_MULTIPLY |
| 10 RETURN_VALUE |
| 0 LOAD_FAST z |
|---|
| ... |
| 2 JUMP_ABSOLUTE 4 |
|---|
| ... |
| 4 POP_TOP |
|---|
| 6 LOAD_FAST x |
| 8 BINARY_OP * |
|---|
| 12 RETURN_VALUE |
| 0 LOAD_FAST z |
|---|
| ... |
| 2 JUMP_FOWWARD 2 |
|---|
| ... |
Python 3.11
Python 3.10
项目介绍
设计思路
后续工作
项目演示
子图打断
eval_frame 适配
闭包支持
其他内容
| BINARY_OP * |
|---|
| ... |
| JUMP_FOWWARD |
| ... |
| JUMP_ABSOLUTE |
| ... |
| BINARY_MULTIPLY |
| ... |
| 无 |
| ... |
| MAKE_CELL |
| ... |
修改 eval_frame.c 的内容以对齐 Python 官方
| 4 POP_TOP |
| 6 LOAD_FAST x |
| 0 LOAD_FAST z |
| ... |
Python 3.11
| 4 POP_TOP |
|---|
| 0 LOAD_FAST z |
| ... |
Python 3.10
项目介绍
设计思路
后续工作
项目演示
子图打断
eval_frame 适配
闭包支持
其他内容
| BINARY_OP * |
|---|
| ... |
| JUMP_FOWWARD JUMP_BACKWARD |
| POP_JUMP_FORWARD_IF_TRUE POP_JUMP_BACKWARD_IF_TRUE |
| ... |
| JUMP_ABSOLUTE |
| POP_JUMP_IF_TRUE |
| JUMP_IF_TRUE_OR_POP |
| ... |
| BINARY_MULTIPLY |
| ... |
| 无 |
| ... |
| MAKE_CELL |
| ... |
对 Paddle 主仓库中的 eval_frame.c 进行修改
绝对跳转 ➡️ 相对跳转
等长指令 ➡️ 变长指令
项目介绍
设计思路
后续工作
项目演示
其他内容
| BINARY_OP * |
|---|
| ... |
| BINARY_MULTIPLY |
| ... |
闭包支持
| 无 |
| 无 |
| LOAD_CLOSURE |
| LOAD_DEREF |
| ... |
| COPY_FREE_VARS |
| MAKE_CELL |
| LOAD_CLOSURE |
| LOAD_DEREF |
| ... |
Python3.11 有更细化的闭包指令,减少了间接寻址。
通过优化现有指令的实现和对新指令的支持,支持新版本的闭包。
子图打断
| JUMP_FOWWARD JUMP_BACKWARD |
| POP_JUMP_FORWARD_IF_TRUE POP_JUMP_BACKWARD_IF_TRUE |
| ... |
| JUMP_ABSOLUTE |
| POP_JUMP_IF_TRUE |
| JUMP_IF_TRUE_OR_POP |
| ... |
绝对跳转 ➡️ 相对跳转
等长指令 ➡️ 变长指令
项目介绍
设计思路
后续工作
项目演示
其他内容
| BINARY_OP * |
|---|
| BINARY_OP + |
| PRECALL CALL |
| PUSH_NULL |
| ... |
| BINARY_MULTIPLY |
| BINARY_ADD |
| CALL_FUNCTION CALL_METHOD |
| 无 |
| ... |
支持新指令
优化原有逻辑
闭包支持
| 无 |
| 无 |
| LOAD_CLOSURE |
| LOAD_DEREF |
| ... |
| MAKE_CELL |
| COPY_FREE_VARS |
| LOAD_CLOSURE |
| LOAD_DEREF |
| ... |
Python3.11 有更细化的闭包指令,减少了间接寻址。
通过优化现有指令的实现和对新指令的支持,支持新版本的闭包。
项目介绍
设计思路
后续工作
项目演示
PaddleFX 执行后端
方案一
使用 Paddle 的动转静功能将子图(GraphLayer)转为静态图,再接入第三方生态,适用于已经支持 Paddle 的计算后端,例如 TVM Relay 等。
FX IR
Paddle 静态图
TVM Relay
| BINARY_OP * |
|---|
| BINARY_OP + |
| PRECALL CALL |
| PUSH_NULL |
| ... |
其他内容
| BINARY_MULTIPLY |
| BINARY_ADD |
| CALL_FUNCTION CALL_METHOD |
| 无 |
| ... |
支持新指令
优化原有逻辑
项目介绍
设计思路
后续工作
项目演示
方案一
FX IR
Paddle 静态图
TVM Relay
TVM TIR
MLIR
方案二
通过遍历子图(GraphLayer)中的每一个节点,进行自定义后端的组网,
适用于不支持 Paddle 的计算后端,例如 LLVM/MLIR、triton 等。
SIR
Paddle 静态图
PaddleFX 执行后端
项目介绍
设计思路
后续工作
项目演示
缓存管理器
...
cls_results = []
for img in images:
cls_results.append(compiled_net(img))
...
| shape |
| dtype |
| ... |
方案一
FX IR
Paddle 静态图
TVM Relay
TVM TIR
MLIR
方案二
通过遍历子图(GraphLayer)中的每一个节点,进行自定义后端的组网,
适用于不支持 Paddle 的计算后端,例如 LLVM/MLIR、triton 等。
PaddleFX 执行后端
项目介绍
设计思路
后续工作
项目演示
缓存管理器
...
cls_results = []
for img in images:
cls_results.append(compiled_net(img))
...
| shape |
| dtype |
| ... |
输入变量
执行
后端构建
缓存未命中
缓存命中
PaddleFX 执行后端
设计思路
后续工作
项目演示
import paddle
from paddle.vision.models import resnet18
from paddlefx import optimize
from paddlefx.compiler.tvm import TVMCompiler
net = resnet18(pretrained=True, num_classes=2)
net.eval()
compiler = TVMCompiler(
full_graph=True,
print_tabular_mode="rich",
tune_mode="auto_scheduler",
target="llvm -mcpu=core-avx2"
)
net = optimize(net, backend=compiler)
x = [paddle.rand([1, 3, 224, 224], dtype="float32") for _ in range(4)]
out = net(x[0])
out = net(x[1])
out = net(x[2])
out = net(x[3])
设计思路
后续工作
项目演示
import paddle
from paddle.vision.models import resnet18
from paddlefx import optimize
from paddlefx.compiler.tvm import TVMCompiler
net = resnet18(pretrained=True, num_classes=2)
net.eval()
compiler = TVMCompiler(
full_graph=True,
print_tabular_mode="rich",
tune_mode="auto_scheduler",
target="llvm -mcpu=core-avx2"
)
net = optimize(net, backend=compiler)
x = [paddle.rand([1, 3, 224, 224], dtype="float32") for _ in range(4)]
out = net(x[0])
out = net(x[1])
out = net(x[2])
out = net(x[3])
| 工作内容 | 工作目的 | 目前进度 | 优先级 |
|---|---|---|---|
| 本地缓存 | 提高多次运行速度 | 高 | |
| 网络缓存 | 提高首次运行速度 | 低 | |
| 编译期检查 | 提高用户开发效率 | 中 | |
| 支持更多后端 | 提高受众范围 | 高 |
设计思路
后续工作
项目演示
优化整体机制:paddlefx#40、paddlefx#41、paddlefx#43
实现 Variable 体系:paddlefx#68、paddlefx#72
优化 Python3.11 支持:paddlefx#73
支持 TVM 后端:paddlefx#75、paddlefx#79
支持 MLIR 后端:paddlefx#58(WIP)
支持 TVM TIR 后端:paddlefx#76(WIP)
设计思路
后续工作
项目演示
实现自定义变量栈:PaddleSOT#343、PaddleSOT#353
跳转子图打断:PaddleSOT#361、PaddleSOT#368
调用子图打断:PaddleSOT#369 循环子图打断:PaddleSOT#371
迁移 paddle.gather_nd 到 PIR :Paddle#57562
设计思路
后续工作
项目演示
| 工作内容 | 工作目的 | 目前进度 | 优先级 |
|---|---|---|---|
| 本地缓存 | 提高多次运行速度 | 计划 | 高 |
| 网络缓存 | 提高首次运行速度 | 讨论 | 低 |
| 编译期检查 | 提高用户开发效率 | 计划 | 中 |
| 支持更多后端 | 提高受众范围 | 进行中 | 高 |
import paddle
from paddle.vision.models import resnet18
from paddlefx import optimize
from paddlefx.compiler.tvm import TVMCompiler
net = resnet18(pretrained=True, num_classes=2)
net.eval()
compiler = TVMCompiler(
full_graph=True,
print_tabular_mode="rich",
tune_mode="auto_scheduler",
target="llvm -mcpu=core-avx2"
)
net = optimize(net, backend=compiler)
x = [paddle.rand([1, 3, 224, 224], dtype="float32") for _ in range(4)]
out = net(x[0])
out = net(x[1])
out = net(x[2])
out = net(x[3])
设计思路
后续工作
项目演示
| 工作内容 | 工作目的 | 目前进度 | 优先级 |
|---|---|---|---|
| 本地缓存 | 提高多次运行速度 | 高 | |
| 网络缓存 | 提高首次运行速度 | 低 | |
| 编译期检查 | 提高用户开发效率 | 中 | |
| 支持更多后端 | 提高受众范围 | 高 |
PaddleFX 与 PaddleSOT 都是针对 Paddle 的,PyTorch Dynamo 是针对 PyTorch,但是当前深度学习框架种类繁多,单独对每个框架都实现一套系统似乎并不是必要的,在开发和学习 PaddleFX 与 PaddleSOT 项目中,我认为实现一个不与特定深度学习框架绑定运行时编译器是很有意义的。
在参与 PaddleSOT 的 Python 3.11支持任务中,我们了解到了更多 Python 新特性,这也包括最近新发布的 Python 3.12,在 Python 3.12 中,出现了更加方便的范型编写语法,但是我们很难去在一个需要兼容 老版本的 Python 项目中去使用新特性,因此我们计划尝试去构建一个自动降级工具,达到使用 Python3.12 的新特性,但能兼容老版本 Python 的目的。
詹荣瑞@zrr1999