Trace

目标

Trace 可以追踪记录 Python 代码执行过程,生成 Graph,并支持一键打包,方便分发部署到任意地方执行。

能够记录哪些执行过程?

Trace 机制是依赖 Python 执行才能记录,换句话说,能够记录的逻辑需要在运行时被执行到!
  • 当前只能正常记录 Matx Op 的调用,其他语句的执行结果会被当成常量

  • IF 语句只能记录一个 branch,需要灵活把握

  • For/While 循环会根据当时的输入条件强制展开,通常这意味着 BUG

  • Return 之后的逻辑会被丢弃,需要灵活把握

约束设计模式

使用 Trace 机制是有代价的,需要遵守以下约定:

  • 业务需要进行模块设计,每个模块视为一个 Operator(Op)

    比如一个文本分类的 pipeline,分词可以认为是一个 Op,文本 ID 化也是一个 Op 等等。

  • 由 Op 集合组成一个 DAG,即为业务的 Pipeline

    比如下图的文本分类的 pipeline,每个框均是一个 Op,这些 Op 串联起来是一个简单的 DAG

  • Op 可以由 C++ 或 Python 开发,不受 Trace 约束

    使用 Python 编写的 类或函数 需要使用 matx.script 编译成 Op,具体请参照 Script 章节

第三方库支持

在被 trace 的函数中如果调用了第三方库比如 requests,那么本次的结果将被当做常量保存并且会在之后执行时使用。换句话说,第三方库执行的结果被固化成常量了。

自动打包本地文件

MATXScript 预期可以打包用于初始化 OP 的文件或者目录,并且会自动修改成相对路径。因此,我们可以将打包后的目录移动到任意地方都可以加载执行,这为服务热更新提供了较大的便利。

  • 哪些文件和目录会被一起打包保存?

MATXScript 仅打包 class.__init__ 函数中参数对应的本地文件,举例如下,

import matx
from typing import Any

CONFIG_FN = "configs/my_config.json"

class MyOperator:
   def __init__(self, vocab_fn: str, model_name: str) -> None:
      self.vocab = self.load_vocab(vocab_fn)
      self.config = self.load_config(CONFIG_FN)
      self.sub_model = MyModel("models/" + model_name)

   def load_vocab(self, fn: str) -> Any:
      ...

   def load_config(self, fn: str) -> Any:
      ...

   def __call__(self, input: Any) -> Any:
      ...

op = matx.script(MyOperator)("assets/vocab.txt", "bert1225")

def pipeline(input):
   return op(input)

mod = matx.trace(pipeline, "query")
mod.save(...)

在这个例子中,assets/vocab.txt 会被打包,但是 configs/my_config.json 和 models/bert1225 不会。

这主要是因为在 Trace 时 MyOperator.__init__ 参数中,只有 vocab_fn 被赋值为一个有效的文件路径,CONFIG_FN 是一个全局变量,并不会分析它, model_name 初始值并不是一个有效路径,因此这两个都不会被打包。

简而言之,我们会分析 Op.__init__ 的参数,如果是字符串类型,并且是一个有效的路径,则会打包。

集成样例