Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【快乐开源】Paddle 算子规范化任务 #69105

Open
gongshaotian opened this issue Nov 1, 2024 · 0 comments
Open

【快乐开源】Paddle 算子规范化任务 #69105

gongshaotian opened this issue Nov 1, 2024 · 0 comments
Assignees
Labels

Comments

@gongshaotian
Copy link
Contributor

gongshaotian commented Nov 1, 2024

任务划分🧾

Paddle 算子单测规范化任务分为两个阶段。

  • 第一阶段是单测状态统计阶段,需要通过搜索查看算子的单测状态,在任务表格中填写单测状态,无需提交PR。
  • 第二阶段是单测补充阶段,会根据一阶段统计结果发布需要添加单测的任务列表。

一阶段任务列表见算子单测规范化统计表

认领方式: 请大家直接在👆的excel表中认领任务:

  • 任务认领要求:一次最多同时认领 10 个统计任务
  • PR提交格式:无需提交PR,直接在表格中更新状态
  • 认领后,超过2周没有提交PR,将重新释放

二阶段任务列表::待一阶段完成后补充
认领方式: 请大家直接在👆的excel表中认领任务:

  • 任务认领要求:为了方便排查 Bug,一次最多同时认领5个任务,一个算子至少需要添加 3 个 OpTest 单测
  • PR提交格式:【Correctness TestCase No.xxx】开头,注明任务编号
  • 认领后,超过2周没有提交PR,将重新释放

1. 前置知识介绍

1.1 算子体系介绍

用户使用深度学习框架搭建的各类模型,本质上是在描述一个计算过程。在框架和深度学习编译器的内部,会将用户构建的模型转换成一个由 Tensor 和 Operator 构成的计算。其中 Tensor 是深度学习中的基本张量表示,Operator 是用于执行各类运算的函数或类。
image
用户使用飞桨开发神经网络模型时使用的 Python 接口(如 paddle.add(), paddle.relu()等) 我们一般称都为飞桨的 Python API,每个运算类的 Python API 在框架内部都会对应到一个或者多个 C++ 端算子,每个算子在不同硬件设备上(CPU, GPU 等)实现的运算逻辑代码又被称为 Kernel, 这里主要是由于不同硬件设备提供的编程接口不同,所以虽然同一个算子的不同硬件设备 Kernel 都实现了相同的数学运算逻辑,但在代码实现上却有所差异。算子 InferMeta 函数是在算子 kernel 执行前先将输出结果的维度、数据类型等信息进行处理,由于计算量较小所以可以直接在 CPU 上计算,因此每个算子只需要实现一个 InferMeta 函数,而不必像 Kernel 一样在不同硬件上实现多个。
image
Python API、算子 Yaml 配置、算子 InferMeta 函数 和算子 Kernel 之间的关系如上图所示,最上层为用户使用的飞桨 Python API 接口,Python API 执行时会进入到 C++ 端由框架进行调度并执行相应的算子逻辑,算子的执行主要包括两个过程:

(1)执行算子 InferMeta 函数完成输出结果的维度、数据类型等静态信息的推导。

(2)根据输入变量的设备信息选择对应的硬件设备来执行算子 Kernel,完成输出结果的数值计算。

Python API 到算子 InferMeta 函数和 Kernel 调用之间的框架调度部分的逻辑代码主要通过算子 Yaml 配置中的信息自动生成,也可以理解为算子 Yaml 配置的作用是通过自动代码生成将上层 Python API 与底层算子的 Kernel 建立连接。

paddle.trace 算子(计算输入 Tensor 在指定平面上的对角线元素之和)为例,下表展示了其算子相关的定义在代码仓库中的位置

内容 trace 示例代码仓库链接 查找方式
算子描述及定义 paddle/phi/ops/yaml/ops.yaml

paddle/phi/ops/yaml/inconsistent/static_ops.yaml
文件内搜索Op名(OpName),yaml定义总包含了除下方Python API和单测文件的所有信息
算子 InferMeta paddle/phi/infermeta/unary.cc infermeta 函数以OpName+InferMeta 命名,可以直接搜索拼接后的函数名
算子 Kernel paddle/phi/kernels目录下的如下文件:
/trace_kernel.h
/cpu/trace_kernel.cc
/gpu/trace_kernel.cu
kernel 函数以 OpName+Kernel 命名,可以直接搜索
Python API python/paddle/tensor/math.py 算子的Python接口定义,可直接搜索 'def OpName'
单元测试 test/legacy_test/test_trace_op.py Op单测文件一般以 test_OpName_op.py 命名,vscode环境下可直接用 command+p 搜索

推荐详细阅读 Paddle 官方文档中的算子添加过程加深对算子体系的理解:如何新增一个算子描述及定义

1.2 PIR&单测体系介绍

在深度学习模型构建上,有动态图和静态图两种模式,二者各有优势。动态图采用 Python 的编程风格,解析式地执行每一行网络代码,并同时返回计算结果,具备很强的灵活性。静态图需先在代码中预定义完整的神经网络结构,采用先编译后执行的方式,可优化的空间更多,性能更佳。飞桨框架采用了『动静统一』的设计方案,支持动态图编程和静态图编程两种方式,能同时兼顾动态图的高易用性和静态图的高性能优势:

  • 在模型开发和训练时,推荐采用动态图编程。 可获得更好的编程体验、更易用的接口、更友好的调试交互机制。
  • 在模型推理部署时,推荐采用动态图转静态图(以下简称:动转静)。平滑衔接将训好的动态图模型自动保存为静态图模型,可获得更好的模型运行性能。
    在某些对模型训练性能有更高要求的场景,也可以使用动转静训练,即在动态图组网代码中添加一行装饰器 @to_static ,便可在底层转为性能更优的静态图模式下训练。
    image
    计算图中间表示(Intermediate Representation,即 IR)的概念起源于传统编译器,是介于源代码与目标代码之间的中间表示。在深度学习领域,它是从高层模型定义转换为底层可执行计算图的中间形式,是深度学习框架性能优化、推理部署、编译器等方向的重要基石。飞桨静态图核心架构分为Python前端和C++后端两个部分。在静态图模式中,Paddle框架会先根据用户的Python代码构造出模型的Program,C++后端会将Python端的Program转换为统一的中间表达(IR),以便于进行相应的编译优化(算子融合和存储优化)。
    image
    飞桨历史上在架构层面并存着多套不同的中间表示体系,其表达能力各不相同、Pass 开发维护成本较高,代码复用性较差,缺乏统一规范,存在严重的框架稳定性问题。在 3.0 版本下,飞桨研发了基于 MLIR 范式的新一代中间表示技术,即 Paddle IR(下简称 PIR)。PIR是Paddle的新版静态图IR表达,替代了旧版静态图的IR。PIR是Paddle的一次重大基础机制升级,目前进入推全、收尾阶段。
    image
    当前PIR核心机制基本健全, 在PIR的提供的灵活的基础组件的基础上Paddle框架和CINN编译器实现了服务于不同功能组件开发,如“组合算子”、“符号推导”等组件。算子单测是保障Paddle代码质量、正确性、计算精度的重要机制。在继承OpTest类实现的单测中,用户可以通过控制 Flag 灵活的开启或关闭算子的各类功能检查,是保证Paddle框架和编译器正确性的第一道防线。

2. 任务划分

2.1 任务背景

目前算子的单测有两种实现方式,分别是继承 OpTest 类和继承 unittest.TestCase 类的实现。

//test/legacy_test/test_eye_op.py

import numpy as np
from op_test import OpTest
import unittest

class TestEyeOp(OpTest)  
class API_TestTensorEye(unittest.TestCase)

unittest 是更底层的类,OpTest是基于unittest开发的。相比于unittest,OpTest 有更强的扩展性,除了能做基本的算子功能检查外,还封装了用于各类检查的Checker,例如用于老静态图检查的StaticChecker、用于动态图检查的DygraphChecker、PIR模式下的PirChecker、用于检查算子符号推导功能的SymbolInferChecker。因此在Paddle功能不断扩展的过程中,算子的OpTest单测对我们来说具有十分重要的意义。下面以eye op为例,展示了该算子的一个OpTest单测实现。

class TestEyeOp(OpTest):
    def setUp(self):    // 执行单测的配置函数 
        '''
        Test eye op with default shape
        '''
        self.python_api = paddle.eye    // 指明该算子 Python 层的api
        self.op_type = "eye"            // 指明算子的 'name', 与yaml文件中对应
        self.init_dtype()               // 调用初始化数据类型函数   
        self.init_attrs()               // 调用初始化属性参数函数 

        self.inputs = {}                // 指定算子的运行时输入
        self.attrs = {                  // 指定算子的属性列表
            'num_rows': self.num_columns,
            'num_columns': self.num_columns,
            'dtype': framework.convert_np_dtype_to_proto_type(self.dtype),
        }
        self.outputs = {                // 给出使用 numpy 实现的该算子同功能的输出,用于校验Paddle算子执行结果是否正确
            'Out': np.eye(self.num_rows, self.num_columns, dtype=self.dtype)
        }

    def test_check_output(self):       // 执行各类 Checker 的检查入口,各类检查可以通过 Flag 控制
        self.check_output(check_pir=True)

    def init_dtype(self):              // 初始化tensor type
        self.dtype = np.int32

    def init_attrs(self):              // 初始化 op 的属性值
        self.num_rows = 319
        self.num_columns = 319

3. 开发流程和示例

3.1 贡献 Paddle 代码的基本流程

算子单测添加示例:https://www.paddlepaddle.org.cn/documentation/docs/zh/dev_guides/api_contributing_guides/new_cpp_op_cn.html#liutianjiadanyuanceshi

Paddle 代码基本贡献流程:https://www.paddlepaddle.org.cn/documentation/docs/zh/dev_guides/api_contributing_guides/new_cpp_op_cn.html#liutianjiadanyuanceshi

3.2 本任务的开发流程

  1. 找到 yaml 文件中的该算子定义,根据文档、Kernel了解该算子的功能

  2. 搜索该 Op 单测文件以及定义
    a. 根据 Op 单测文件命名搜索,参考1.1
    b. 根据 self.op_type = "op_name" 搜索,参考2.1

  3. 查看是否有该 Op 的 OpTest 单测实现

  4. 补充 OpTest 单测
    a. 编写 OpTest 单测的各项执行配置
    b. 使用 Numpy 实现该配置下算子的预期输出
    c. 配置 test_check_output() 中的各项Flag

  5. 本地测试

  6. 整理代码、执行pre-commit、提交PR

  7. 申请代码 review、根据 review 意见讨论/修改

  8. 合入代码

4. 常见问题

待补充

@gongshaotian gongshaotian changed the title 【快乐开源】Paddle 算子单测规范化 【快乐开源】Paddle 算子规范化任务 Nov 1, 2024
@luotao1 luotao1 assigned luotao1 and gongshaotian and unassigned LiYuRio Nov 1, 2024
@luotao1 luotao1 moved this to In Progress in Call for Contributions Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: In Progress
Development

No branches or pull requests

3 participants