• Docs >
  • Component Best Practices
Shortcuts

组件最佳实践

这里列出了您可能希望对组件执行的一些常见操作以及这些操作的最佳实践。组件设计为灵活,因此如有必要,您可以偏离这些实践,但这些是我们为内置TorchX组件使用的最佳实践。

请参阅应用最佳实践了解如何使用TorchX编写应用程序的信息。

入口点

如果可能的话,最好通过python -m 调用您的可重用组件,而不是指定主模块的路径。这样可以通过依赖Python模块解析而不是目录结构,使其可以在多个不同的环境中使用,例如docker和slurm。

如果你的应用程序不是基于python的,你可以将你的应用程序放在PATH上的一个文件夹中,这样无论目录结构如何都可以访问它。

def trainer(img_name: str, img_version: str) -> AppDef:
    return AppDef(roles=[
        Role(
            entrypoint="python",
            args=[
                "-m",
                "your.app",
            ],
        )
    ])

简化

在编写组件时,您希望尽可能保持每个组件的简单性,以便其他人更容易重用和理解。

参数处理

参数处理使得在其他环境中使用组件变得困难。特别是对于图像,我们希望直接将图像字段传递给AppDef,因为任何形式的操作都会使其无法在具有不同图像命名约定的其他环境中使用。

def trainer(image: str):
    return AppDef(roles=[Role(image=image)...)

分支逻辑

你应该避免在组件中使用分支逻辑。如果你遇到一种情况,觉得在组件中需要使用if语句,你应该更倾向于创建多个共享逻辑的组件。复杂的参数会使其他人难以理解如何使用它。

def trainer_test():
    return _trainer(num_replicas=1)

def trainer_prod() -> AppDef:
    return _trainer(num_replicas=10)

# not a component just a function
def _trainer(num_replicas: int) -> AppDef:
     return AppDef(roles=[Role(..., num_replicas=num_replicas)])

文档

文档是可选的,但保持组件函数的文档化是最佳实践,特别是如果你想分享你的组件。有关更多详细信息,请参阅:Component Authoring

命名资源

在编写组件时,最好使用TorchX的命名资源支持,而不是手动指定CPU和内存分配。命名资源使您的组件与环境无关,并通过使用T恤尺寸实现更好的调度行为。

查看 torchx.specs.get_named_resources() 获取更多信息。

组合组件

对于常见的组件样式,我们提供了基础组件定义。这些可以从您的自定义组件定义中调用,并且是创建完整AppDef的替代方案。

参见:

对于更复杂的组件,可以将多个现有组件合并为一个。例如,您可以使用一个指标UI组件,并将其角色合并到训练组件角色中,以便为主要的训练任务提供一个辅助服务。

分布式组件

如果您正在编写一个用于分布式训练或其他类似分布式计算的组件,我们建议使用 torchx.components.dist.ddp() 组件,因为它提供了对 torch.distributed.elastic 作业的开箱即用支持。

你可以通过编写一个自定义组件来扩展ddp组件,该组件只需导入ddp组件并使用你的应用配置调用它。

定义所有参数

最好将所有组件参数定义为函数参数,而不是使用参数字典。这使得用户更容易理解选项,并且在与pyremypy一起使用时可以提供静态类型检查。

单元测试

您可以像测试普通Python代码一样对组件定义进行单元测试,因为它们是有效的Python定义。

我们确实建议使用ComponentTestCase来确保您的组件可以被TorchX CLI解析。CLI对文档字符串的格式要求比纯Python更严格,因为文档字符串用于解析CLI参数。

class torchx.components.component_test_base.ComponentTestCase(methodName='runTest')[来源]
run_component(component: Callable[[...], AppDef], args: Optional[Dict[str, Any]] = None, scheduler_params: Optional[Dict[str, Any]] = None, scheduler: str = 'local_cwd', interval: float = 0.1, timeout: float = 1) Optional[AppStatus][来源]

帮助函数,隐藏了设置运行器和轮询结果的复杂性。 注意:该方法会阻塞,直到调度程序退出或达到超时(对于非阻塞调度程序)。

Parameters:
  • components – 组件函数,AppDef的工厂

  • args – 可选的组件工厂参数

  • scheduler_params – 调度器工厂方法的可选参数

  • scheduler – 调度器名称

  • interval – 调度器完成轮询间隔

  • timeout – 调度器完成的最大时间

setUp() None[来源]

在测试之前设置测试夹具的钩子方法。

tearDown() None[source]

用于在测试后解构测试装置的钩子方法。

validate(module: module, function_name: str) None[source]

通过有效运行来验证组件:

$ torchx run COMPONENT.py:FN --help

集成测试

您可以通过使用编程运行器API或编写bash脚本来调用CLI来设置组件的集成测试。

你可以在核心的TorchX调度器集成测试中看到这两种风格的使用。