• W
    GeneratePass for Python Pass (#35708) · f6db9806
    wuhuanzhou 提交于
    #### 背景
    
    #35602 提供Python侧开发子图替换类Pass的方式:
    
    - 利用Paddle Python API或者辅助类型定义子图program用来匹配/替换图;
    - Python侧注册Pass时,将注册函数最终转换为protobuf定义的PassDesc数据形式,供C++侧进行解析完成Pass实例注册。
    
    本PR即为根据PassDesc规则描述解析生成Pass实例。
    
    #### 方案设计
    
    ##### Pass规则验证
    
    在以往的Pass开发中,会存在随着算子迭代引发的匹配失效或者错误匹配的问题,该问题可以通过扫描算子支持的参数设置及参数类型等来判断是否应该使用该Pass或者给出提示需要修改Pass代码。
    
    当前Pass开发中提供了算子兼容性OpCompatSensiblePass用于解决上述问题。但同时还存在不足:由于以往Pass开发在运行时才能获取到pattern信息,所以需要在执行Pass时才可以判断。
    
    使用PassDesc表示的Pass可以在执行Pass前验证上述问题,这个过程在VerifyDesc中完成。
    
    ##### 根据匹配子图构造pattern
    
    GeneratePass对于图匹配和替换使用GraphPatternDecetor完成,构造匹配pattern实际上就是将对应对象成员PDPattern中添加PDNode和边关系。该过程在函数`InitGeneratePattern`中完成,该函数没有作为GeneratePass的成员方法,主要出于后续可能开发新的Decetor考虑,GeneratePass与Decetor的操作是没有关联的。
    
    初始化pattern主要通过遍历匹配子图program的全部算子实现:
    
    1. 添加当前算子对应PDNode及限制条件(算子类型、属性限制等);
    2. 遍历当前算子对应输入并从pattern中尝试获取PDNode:
       - 在pattern中获取到PDNode且为输出节点:表示属于匹配子图的中间节点,将该PDNode设置为中间节点;
       - 在pattern中没有获取到PDNode:添加该输入PDNode并设置作为输入节点;
       - 设置输入到算子的边关系;
    3. 遍历当前算子对应输出:
       - 在pattern中获取到PDNode且为输入节点:表示属于匹配子图的中间节点,将该PDNode设置为中间节点;
       - 在pattern中没有获取到PDNode:添加该输入PDNode并设置作为输出节点;
       - 设置算子到输出的边关系;
    
    ##### 根据替换子图操作graph
    
    替换子图操作的过程在`GetGenerateRewrite`函数中完成,与`InitGeneratePattern`类似没有作为GeneratePass的成员方法。
    
    生成替换子图操作过程如下:
    
    1. 判断冗余替换子图;
    2. 遍历替换子图program的全部算子添加替换子图Node:
       1. 添加当前算子的Node及属性设置;
       2. 遍历当前算子对应输入,添加中间variable节点;
       3. 遍历当前算子对应输出,添加中间variable节点;
       4. 添加输入/输出节点与算子节点的边关系;
    3. 删除匹配图中属于中间节点的Node;
    
    ##### 优化子图验证
    
    对于替换子图或者替换后的计算图是否可以正确运行等,可以在执行Pass时验证,从而防止在后续执行计算图时出现异常。
    
    当前Pass执行直接修改计算图,验证失败时无法很好的完成还原操作,目前子图验证暂时默认成功,留到后续改进。
    f6db9806
generate_pass_tester.cc 15.8 KB