中间件规范¶
文件结构和命名¶
DI-engine 中的中间件可以分为两类,一类我们称之为 function,它是一种原子操作方法,专注于用几行代码完成一件事,例如 train 中间件执行模型的训练;另一类我们称之为 module,它可能结合多个 functions 来执行更复杂的逻辑。这种分类参考了 pytorch 的 nn 和 nn.functional。
本质上它们都属于中间件,并且使用方法完全相同。
在目录结构中,module 直接放置在 middleware 目录中,以名词命名;
function 放置在 middleware/functional 目录中,以动词或名词命名。
可以在一个文件中编写多个相同类型的中间件。
ding/
framework/
middleware/
functional/collect.py # Function
collector.py # Module
类, 函数, 参数¶
在编写function时,推荐使用函数式风格的代码,因为代码简洁;在编写module时,推荐使用类。例如:
建议所有函数都显式传递命名参数,不推荐使用字典作为参数传递。对于参数过多的情况,我们建议使用TreeTensor。
构造函数¶
大多数中间件有两层方法,例如function的外部函数和module的__init__函数,这些方法用于传递中间件运行所需的参数和对象。
function的返回函数和module的__call__方法是在运行时循环调用的过程,并且只支持ctx作为一个参数。
建议在外部实例化对象以传递给中间件,而不是在中间件内部实例化,以确保无状态和过程化的中间件:
运行时函数¶
在编写function的返回函数或module的__call__方法时,有一些需要注意的事项:
如果方法中存在无限循环,请确保检查
task.finish条件以退出:
tasksupports two modes of sequential execution and asynchronous execution. The data passed byctxmay not be generated at the same time in the two modes.在中间件中需要注意判断,最好支持两种模式:
不建议在中间件内部打开多个进程,以避免由于前端实例化对象过多或进程的多级嵌套导致的不可预见的问题。如果需要使用多进程并行,可以将逻辑拆分为多个中间件,利用DI-engine的并行能力来执行:
事件命名规范¶
在使用DI-engine中的事件机制时,我们约定事件按照以下规范命名:
用于广播数据的事件使用
(emitting position)_(data name)[_(parameter name)_(parameter value)]命名,例如:league_job_actor_0(从联盟向执行者广播数据,传递任务)用于远程调用的事件被命名为
(receive location)_(method name),例如:league_get_job(调用league的get_job函数)。