英仙座 是 PPQ 0.6.5 版本引入的全新调度器 基于新的 OpSocket, VProperty, VLink 数据类型抽象, 英仙座调度器能够以一种可扩展的、可控制的方式切分你的计算图。 英仙座调度器基于静态图分析与数值追踪, 借由 OpSocket 定义的 "接线器" 算子模型, 英仙座调度器可以对 Onnx中数据流的来源进行追踪,并进一步求解关于节点的数值传递闭包。 这一过程完全是静态完成的,不需要送入数据执行。 对于一个简单的 Reshape 算子而言,接线器模型定义了该算子内部的数据流动情况:
| 7 | |
| 8 | |
| 9 | class Perseus(GraphDispatcher): |
| 10 | """ 英仙座 是 PPQ 0.6.5 版本引入的全新调度器 |
| 11 | |
| 12 | 基于新的 OpSocket, VProperty, VLink 数据类型抽象, |
| 13 | 英仙座调度器能够以一种可扩展的、可控制的方式切分你的计算图。 |
| 14 | |
| 15 | 英仙座调度器基于静态图分析与数值追踪, |
| 16 | 借由 OpSocket 定义的 "接线器" 算子模型, 英仙座调度器可以对 |
| 17 | Onnx中数据流的来源进行追踪,并进一步求解关于节点的数值传递闭包。 |
| 18 | 这一过程完全是静态完成的,不需要送入数据执行。 |
| 19 | |
| 20 | 对于一个简单的 Reshape 算子而言,接线器模型定义了该算子内部的数据流动情况: |
| 21 | (对于Reshape算子而言, 其输出结果与第一个输入之间存在数值关联, 而与第二个输入直接不存在直接关联) |
| 22 | |
| 23 | Input(VALUE) Shape(SOI) |
| 24 | | | |
| 25 | * ---------------------- * |
| 26 | | | | |
| 27 | | * ----- * Reshape | |
| 28 | | | | |
| 29 | * ---------------------- * |
| 30 | | |
| 31 | Out(VALUE) |
| 32 | |
| 33 | 接线器模型在算子内部定义了这样的输入 - 输出关系网,从而调度器可以使用这样的关系网来划分子图。 |
| 34 | |
| 35 | """ |
| 36 | |
| 37 | def __init__(self, graph: BaseGraph, verbose: bool = False) -> None: |
| 38 | """ 初始化英仙座调度器 |
| 39 | 在这一过程中,英仙座调度器将为每一个算子生成它的 OpSocket 接线器 |
| 40 | 一旦算子接线器初始化完毕,你将不能对图结构进行进一步修改,否则调度将会失败 |
| 41 | |
| 42 | 在这一过程中,英仙座将为 onnx 算子生成预定义的 onnx 算子接线器, |
| 43 | 所有被列举在 ppq/scheduler/core/default.py 中的算子均有预定义的算子接线器实现 |
| 44 | 支持 opset 1 ~ 18 |
| 45 | |
| 46 | 如果你的网络具有自定义算子,或存在未在 default.py 列举的 onnx 算子 |
| 47 | 英仙座会为他们生成默认接线器,请知悉:这可能导致错误 |
| 48 | |
| 49 | 你应当为你的新算子注册新的接线器,从而英仙座调度器能够使用新定义的接线器模型完成调度 |
| 50 | 当英仙座调度器为你未知的算子生成默认接线器时,它将给出警报 |
| 51 | """ |
| 52 | self.sockets = {} |
| 53 | self.verbose = verbose |
| 54 | self.graph = graph |
| 55 | self._search_engine = SearchableGraph(graph) |
| 56 | self._precomputed_op_fanout = {} |
| 57 | self._precomputed_op_fanin = {} |
| 58 | |
| 59 | for op in self.graph.operations.values(): |
| 60 | socket = op.socket |
| 61 | fanin, fanout = set(), set() |
| 62 | for link in socket.links: |
| 63 | source_var = op.inputs[link.in_idx] |
| 64 | dest_var = op.outputs[link.out_idx] |
| 65 | source_op = source_var.source_op |
| 66 | dest_ops = dest_var.dest_ops |