You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
//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)
任务划分🧾
Paddle 算子单测规范化任务分为两个阶段。
一阶段任务列表见:算子单测规范化统计表
认领方式: 请大家直接在👆的excel表中认领任务:
二阶段任务列表::待一阶段完成后补充
认领方式: 请大家直接在👆的excel表中认领任务:
1. 前置知识介绍
1.1 算子体系介绍
用户使用深度学习框架搭建的各类模型,本质上是在描述一个计算过程。在框架和深度学习编译器的内部,会将用户构建的模型转换成一个由 Tensor 和 Operator 构成的计算。其中 Tensor 是深度学习中的基本张量表示,Operator 是用于执行各类运算的函数或类。
用户使用飞桨开发神经网络模型时使用的 Python 接口(如 paddle.add(), paddle.relu()等) 我们一般称都为飞桨的 Python API,每个运算类的 Python API 在框架内部都会对应到一个或者多个 C++ 端算子,每个算子在不同硬件设备上(CPU, GPU 等)实现的运算逻辑代码又被称为 Kernel, 这里主要是由于不同硬件设备提供的编程接口不同,所以虽然同一个算子的不同硬件设备 Kernel 都实现了相同的数学运算逻辑,但在代码实现上却有所差异。算子 InferMeta 函数是在算子 kernel 执行前先将输出结果的维度、数据类型等信息进行处理,由于计算量较小所以可以直接在 CPU 上计算,因此每个算子只需要实现一个 InferMeta 函数,而不必像 Kernel 一样在不同硬件上实现多个。
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 在指定平面上的对角线元素之和)为例,下表展示了其算子相关的定义在代码仓库中的位置
paddle/phi/ops/yaml/inconsistent/static_ops.yaml
/trace_kernel.h
/cpu/trace_kernel.cc
/gpu/trace_kernel.cu
推荐详细阅读 Paddle 官方文档中的算子添加过程加深对算子体系的理解:如何新增一个算子描述及定义
1.2 PIR&单测体系介绍
在深度学习模型构建上,有动态图和静态图两种模式,二者各有优势。动态图采用 Python 的编程风格,解析式地执行每一行网络代码,并同时返回计算结果,具备很强的灵活性。静态图需先在代码中预定义完整的神经网络结构,采用先编译后执行的方式,可优化的空间更多,性能更佳。飞桨框架采用了『动静统一』的设计方案,支持动态图编程和静态图编程两种方式,能同时兼顾动态图的高易用性和静态图的高性能优势:
在某些对模型训练性能有更高要求的场景,也可以使用动转静训练,即在动态图组网代码中添加一行装饰器 @to_static ,便可在底层转为性能更优的静态图模式下训练。
计算图中间表示(Intermediate Representation,即 IR)的概念起源于传统编译器,是介于源代码与目标代码之间的中间表示。在深度学习领域,它是从高层模型定义转换为底层可执行计算图的中间形式,是深度学习框架性能优化、推理部署、编译器等方向的重要基石。飞桨静态图核心架构分为Python前端和C++后端两个部分。在静态图模式中,Paddle框架会先根据用户的Python代码构造出模型的Program,C++后端会将Python端的Program转换为统一的中间表达(IR),以便于进行相应的编译优化(算子融合和存储优化)。
飞桨历史上在架构层面并存着多套不同的中间表示体系,其表达能力各不相同、Pass 开发维护成本较高,代码复用性较差,缺乏统一规范,存在严重的框架稳定性问题。在 3.0 版本下,飞桨研发了基于 MLIR 范式的新一代中间表示技术,即 Paddle IR(下简称 PIR)。PIR是Paddle的新版静态图IR表达,替代了旧版静态图的IR。PIR是Paddle的一次重大基础机制升级,目前进入推全、收尾阶段。
当前PIR核心机制基本健全, 在PIR的提供的灵活的基础组件的基础上Paddle框架和CINN编译器实现了服务于不同功能组件开发,如“组合算子”、“符号推导”等组件。算子单测是保障Paddle代码质量、正确性、计算精度的重要机制。在继承OpTest类实现的单测中,用户可以通过控制 Flag 灵活的开启或关闭算子的各类功能检查,是保证Paddle框架和编译器正确性的第一道防线。
2. 任务划分
2.1 任务背景
目前算子的单测有两种实现方式,分别是继承 OpTest 类和继承 unittest.TestCase 类的实现。
unittest 是更底层的类,OpTest是基于unittest开发的。相比于unittest,OpTest 有更强的扩展性,除了能做基本的算子功能检查外,还封装了用于各类检查的Checker,例如用于老静态图检查的StaticChecker、用于动态图检查的DygraphChecker、PIR模式下的PirChecker、用于检查算子符号推导功能的SymbolInferChecker。因此在Paddle功能不断扩展的过程中,算子的OpTest单测对我们来说具有十分重要的意义。下面以eye op为例,展示了该算子的一个OpTest单测实现。
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 本任务的开发流程
找到 yaml 文件中的该算子定义,根据文档、Kernel了解该算子的功能
搜索该 Op 单测文件以及定义
a. 根据 Op 单测文件命名搜索,参考1.1
b. 根据 self.op_type = "op_name" 搜索,参考2.1
查看是否有该 Op 的 OpTest 单测实现
补充 OpTest 单测
a. 编写 OpTest 单测的各项执行配置
b. 使用 Numpy 实现该配置下算子的预期输出
c. 配置 test_check_output() 中的各项Flag
本地测试
整理代码、执行pre-commit、提交PR
申请代码 review、根据 review 意见讨论/修改
合入代码
4. 常见问题
待补充
The text was updated successfully, but these errors were encountered: