实施luigi动态图配置

时间:2018-06-26 15:51:07

标签: python python-3.x luigi data-pipeline

我是luigi的新手,在为我们的ML工作设计管道时遇到了它。尽管它不适合我的特定用例,但它具有很多额外的功能,我决定使其适合。

基本上,我要寻找的是一种能够保留定制构建的管道,从而使其结果可重复且易于部署的方法,在阅读了大部分在线教程后,我尝试使用现有的{{ 1}}配置和命令行机制,它可能足以满足任务的参数,但是它无法序列化管道的DAG连接,因此我决定要有一个WrapperTask,它收到了luigi.cfg创建所有任务实例,并连接luigi任务的所有输入输出通道(执行所有管道操作)。

在此,我附上一个小型测试程序供您仔细检查:

json config file

因此,基本上,正如问题标题所述,它着眼于动态依赖关系,并使用import random import luigi import time import os class TaskNode(luigi.Task): i = luigi.IntParameter() # node ID def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.required = [] def set_required(self, required=None): self.required = required # set the dependencies return self def requires(self): return self.required def output(self): return luigi.LocalTarget('{0}{1}.txt'.format(self.__class__.__name__, self.i)) def run(self): with self.output().open('w') as outfile: outfile.write('inside {0}{1}\n'.format(self.__class__.__name__, self.i)) self.process() def process(self): raise NotImplementedError(self.__class__.__name__ + " must implement this method") class FastNode(TaskNode): def process(self): time.sleep(1) class SlowNode(TaskNode): def process(self): time.sleep(2) # This WrapperTask builds all the nodes class All(luigi.WrapperTask): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) num_nodes = 513 classes = TaskNode.__subclasses__() self.nodes = [] for i in reversed(range(num_nodes)): cls = random.choice(classes) dependencies = random.sample(self.nodes, (num_nodes - i) // 35) obj = cls(i=i) if dependencies: obj.set_required(required=dependencies) else: obj.set_required(required=None) # delete existing output causing a build all if obj.output().exists(): obj.output().remove() self.nodes.append(obj) def requires(self): return self.nodes if __name__ == '__main__': luigi.run() 生成a 513 node dependency DAG,并且还将All(与make all一样)类定义为WrapperTask需要构建所有节点才能将其视为已完成(我有一个版本仅将其连接到已连接的DAG组件的头部,但我不想过分复杂)。

是否有更标准的(Luigic)实施方式?特别要注意与TaskNode init 和set_required方法不太复杂的情况,我之所以这样做是因为在init方法中接收参数与luigi注册参数的方式有些冲突。我还尝试了其他几种方法,但这基本上是最有效的方法(有效)

如果没有一种标准的方法,我仍然希望在完成框架之前听取您对我打算采取的方式的见解。

1 个答案:

答案 0 :(得分:1)

我昨天answered a similar question进行了演示。我几乎完全基于example in the docs.。在文档中,通过yeild分配任务来分配动态依赖项似乎是他们喜欢的方式。

luigi.Config和动态依赖项可以为您提供几乎无限的灵活性。他们还描述了一个伪Task,它调用了多个依赖项链here,,可以给您更多的控制权。