顶层核心概念:模块
Module 是 LazyLLM 中的顶层组件,也是 LazyLLM 最核心的概念之一。Module 具备训练、部署、推理和评测四项关键能力,每个模块可以选择实现其中的部分或者全部的能力, 每项能力都可以由一到多个函数、Component 或其他 Module 组成。本章我们会详细介绍 Module 的使用方式。
API Reference
Module的API文档可以参考 module
定义一个模块( Module
)
通过继承
若想定义一个 Module
,只需要自定义一个类,继承自 lazyllm.module.ModuleBase
即可。自定义的模块需要实现下列三个方法之一:
_get_train_tasks
: 定义训练 / 微调任务,返回一个训练 / 微调任务的pipeline
,在调用update
方法时执行任务;_get_deploy_tasks
: 定义部署任务,返回一个部署任务的pipeline
,在调用start
方法时执行部署任务;或者在调用update
方法时执行完训练任务后执行部署任务;forward
: 定义Module
的具体执行过程,会被Module.__call__
调用。
下面给出一个例子:
>>> import lazyllm
>>> class MyModule(lazyllm.module.ModuleBase):
...
... def __init__(self, name, return_trace=True):
... super(__class__, self).__init__(return_trace=return_trace)
... self.name = name
...
... def _get_train_tasks(self):
... return lazyllm.pipeline(lambda : print(f'Module {self.name} trained!'))
...
... def _get_deploy_tasks(self):
... return lazyllm.pipeline(lambda : print(f'Module {self.name} deployed!'))
...
... def forward(self, input):
... return f'[Module {self.name} get input: {input}]'
...
>>> m = MyModule('example')
>>> m('hello world')
'[Module example get input: hello world]'
>>> m.update()
Module example trained!
Module example deployed!
<Module type=MyModule name=example>
>>> m.start()
Module example deployed!
<Module type=MyModule name=example>
>>> m.evalset(['hello', 'world'])
>>> m.update().eval_result
Module example trained!
Module example deployed!
['[Module example get input: hello]', '[Module example get input: world]']
注意
- 测试集是通过调用
evalset
来设置的,不需要显式的重写某个函数。所有的Module
均可以设置测试集。
通过内置的注册器
LazyLLM 实现了一个 Module
的注册器,利用它可以很方便的将函数注册成 Module
。下面给出一个具体的例子:
>>> import lazyllm
>>> lazyllm.module_register.new_group('mymodules')
>>> @lazyllm.module_register('mymodules')
... def m(input):
... return f'module m get input: {input}'
...
>>> lazyllm.mymodules.m()(1)
'module m get input: 1'
>>> m = lazyllm.mymodules.m()
>>> m.evalset([1, 2, 3])
>>> m.eval().eval_result
['module m get input: 1', 'module m get input: 2', 'module m get input: 3']
Submodules
Submodules 的概念
与 PyTorch 的 Module
类似,LazyLLM 的 Module
也有层级的概念,一个 Module
可以有一个到多个 Submodule
。
当使用 update
函数更新一个 Module
时,也会对应对其 Submodule
进行更新,除非显式设置不更新 Submodule
。
类似的,当使用 start
函数启动一个 Module
的部署任务时,也会对应对其 Submodule
进行部署,除非显式设置不部署 Submodule
。
下面给出一个例子:
如何构建 Submodules
您可以通过以下几种方式,让一个 Module
成为另一个 Module
的 Submodule
:
-
作为构造参数传入
ActionModule
或ServerModule
等,下面给出一个例子>>> m1 = MyModule('m1') >>> m2 = MyModule('m2') >>> am = lazyllm.ActionModule(m1, m2) >>> am.submodules [<Module type=MyModule name=m1>, <Module type=MyModule name=m2>] >>> sm = lazyllm.ServerModule(m1) >>> sm.submodules [<Module type=MyModule name=m1>]
注意
-
当 flow 作为
ActionModule
或ServerModule
的构造参数时,若其中的存在Module
,也会变成ActionModule
或ServerModule
的SubModule
。下面给出一个例子:>>> m1 = MyModule('m1') >>> m2 = MyModule('m2') >>> m3 = MyModule('m3') >>> am = lazyllm.ActionModule(lazyllm.pipeline(m1, lazyllm.parallel(m2, m3))) >>> am.submodules [<Module type=MyModule name=m1>, <Module type=MyModule name=m2>, <Module type=MyModule name=m3>] >>> sm = lazyllm.ServerModule(lazyllm.pipeline(m1, lazyllm.parallel(m2, m3))) >>> sm.submodules [<Module type=_ServerModuleImpl>] >>> sm.submodules[0].submodules [<Module type=Action return_trace=False sub-category=Flow type=Pipeline items=[]> └- <Flow type=Pipeline items=[]> |- <Module type=MyModule name=m1> └- <Flow type=Parallel items=[]> |- <Module type=MyModule name=m2> └- <Module type=MyModule name=m3> ]
-
直接对
Module
打印repr
时,会以层级结构的形式展示其所有的submodule。接上一个例子:>>> sm <Module type=Server stream=False return_trace=False> └- <Module type=Action return_trace=False sub-category=Flow type=Pipeline items=[]> └- <Flow type=Pipeline items=[]> |- <Module type=MyModule name=m1> └- <Flow type=Parallel items=[]> |- <Module type=MyModule name=m2> └- <Module type=MyModule name=m3>
-
-
在一个
Module
中设置另一个Module
为成员变量,即可以让另一个Module
变成自己是submodule
,下面给出一个例子>>> class MyModule2(lazyllm.module.ModuleBase): ... ... def __init__(self, name, return_trace=True): ... super(__class__, self).__init__(return_trace=return_trace) ... self.name = name ... self.m1_1 = MyModule('m1-1') ... self.m1_2 = MyModule('m1-2') ... >>> m2 = MyModule2('m2') >>> m2.submodules [<Module type=MyModule name=m1-1>, <Module type=MyModule name=m1-2>]
利用 Submodules 实现应用的联合部署
当训练/微调或部署一个 Module
时,会通过深度优先的策略查找其所有的 SubModule
,并逐一部署。示例如下:
>>> class MyModule2(lazyllm.module.ModuleBase):
...
... def __init__(self, name, return_trace=True):
... super(__class__, self).__init__(return_trace=return_trace)
... self.name = name
... self.m1_1 = MyModule(f'{name} m1-1')
... self.m1_2 = MyModule(f'{name} m1-2')
...
... def _get_deploy_tasks(self):
... return lazyllm.pipeline(lambda : print(f'Module {self.name} deployed!'))
...
... def __repr__(self):
... return lazyllm.make_repr('Module', self.__class__, subs=[repr(self.m1_1), repr(self.m1_2)])
...
>>> am = lazyllm.ActionModule(MyModule2('m2-1'), MyModule2('m2-2'))
>>> am
<Module type=Action return_trace=False sub-category=Flow type=Pipeline items=[]>
|- <Module type=MyModule2>
| |- <Module type=MyModule name=m2-1 m1-1>
| └- <Module type=MyModule name=m2-1 m1-2>
└- <Module type=MyModule2>
|- <Module type=MyModule name=m2-2 m1-1>
└- <Module type=MyModule name=m2-2 m1-2>
>>> am.update()
Module m2-1 m1-1 trained!
Module m2-1 m1-2 trained!
Module m2-2 m1-1 trained!
Module m2-2 m1-2 trained!
Module m2-1 m1-1 deployed!
Module m2-1 m1-2 deployed!
Module m2-1 deployed!
Module m2-2 m1-1 deployed!
Module m2-2 m1-2 deployed!
Module m2-2 deployed!
注意
-
可以看出,当更新
ActionModule
时,会将其所有的SubModule
一并进行更新;然后若有部署任务,则会在全部的训练/微调任务执行完毕之后,执行所有的部署任务。因为可能存在父模块对子模块的依赖,因此在部署时,会优先部署子模块,然后部署父模块。 -
当配置了
Redis
服务时,便可以利用LazyLLM提供的轻量级网关的机制,实现所有服务的并行部署。