MONAI-LayerFactory设计与实现

LayerFactory

用于创建图层的工厂对象,这使用给定的工厂函数来实际产生类型或构建可调用程序。这些函数是通过名称来参考的,可以在任何时候添加。

用到的关键技术点:

  • 装饰器(Decorators),
    例如:@property装饰器,创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改
  • 几个特殊的函数:__getitem__,__getattr__

LayerFactory 类中的方法

  • def add_factory_callable(self, name: str, func: Callable) -> None:
    在给定的名称下将工厂函数添加到此对象中。

  • def factory_function(self, name: str) -> Callable:
    装饰器,用于添加一个具有给定名称的工厂函数。

  • def get_constructor(self, factory_name: str, *args) -> Any:
    获取给定工厂名称和参数的构造函数。 TypeError: When ``factory_name`` is not a ``str``.

  • def __getitem__(self, args) -> Any:
    获取给定的名称或名称/参数对。如果args是一个可调用的,它被认为是构造函数本身,并被返回。
    本身并被返回,否则它应该是工厂名称或包含名称和参数的一对。

  • def __getattr__(self, key):
    如果key是一个工厂名称,则返回它,否则表现为继承。这允许将工厂名称作为常量来引用
    例如,Fact.FOO表示一个带有工厂函数foo的工厂因子。

为这些层类型定义工厂

Dropout = LayerFactory()
Norm = LayerFactory()
Act = LayerFactory()
Conv = LayerFactory()
Pool = LayerFactory()
Pad = LayerFactory()

利用装饰器函数注册函数实例

Droupt 工厂注册相关的工厂方法,其中参考代码如下

@Dropout.factory_function("dropout")
def dropout_factory(dim: int) -> Type[Union[nn.Dropout, nn.Dropout2d, nn.Dropout3d]]:
    types = (nn.Dropout, nn.Dropout2d, nn.Dropout3d)
    return types[dim - 1]

Act 工厂注册方法

Act.add_factory_callable("elu", lambda: nn.modules.ELU)
Act.add_factory_callable("relu", lambda: nn.modules.ReLU)
Act.add_factory_callable("leakyrelu", lambda: nn.modules.LeakyReLU)

调用流程分析

调用卷积工厂如下

from monai.networks.layers.factories import Conv
def test_factories():
    dimension = 3
    #当我们访问一个不存在的属性的时候,就会进入__getattr__
    #Conv.CONVTRANS 这个属性是不存在的,所以作者重写了__getattr__方法
    # 会从self.factories查找注册方法的key
    name = Conv.CONVTRANS
    #[] 会调用__getitem__,作者重写了__gettitem__
    # __gettitem__ 会判断是否是一个可调用的对象,如果不是可调用的对象,则调用其构造函数
    conv = Conv[name, dimension]
if __name__ == "__main__":
    test_factories()

CONVTRANS的构造函数如下:

@Conv.factory_function("convtrans")
def convtrans_factory(dim: int) -> Type[Union[nn.ConvTranspose1d, nn.ConvTranspose2d, nn.ConvTranspose3d]]:
    types = (nn.ConvTranspose1d, nn.ConvTranspose2d, nn.ConvTranspose3d)

在调用convtrans_factory方法之前通过装饰器已经把{“CONVTRANS”,convtrans_factory} 注册到 self.factories: Dict[str, Callable] 中。

源码

import warnings
from typing import Any, Callable, Dict, Tuple, Type, Union

import torch
import torch.nn as nn

from monai.utils import look_up_option, optional_import

InstanceNorm3dNVFuser, has_nvfuser = optional_import("apex.normalization", name="InstanceNorm3dNVFuser")

__all__ = ["LayerFactory", "Dropout", "Norm", "Act", "Conv", "Pool", "Pad", "split_args"]


class LayerFactory:
    """
    Factory object for creating layers, this uses given factory functions to actually produce the types or constructing
    callables. These functions are referred to by name and can be added at any time.
    """

    def __init__(self) -> None:
        self.factories: Dict[str, Callable] = {}

    @property
    def names(self) -> Tuple[str, ...]:
        """
        Produces all factory names.
        """

        return tuple(self.factories)

    def add_factory_callable(self, name: str, func: Callable) -> None:
        """
        Add the factory function to this object under the given name.
        """

        self.factories[name.upper()] = func
        self.__doc__ = (
            "The supported member"
            + ("s are: " if len(self.names) > 1 else " is: ")
            + ", ".join(f"``{name}``" for name in self.names)
            + ".\nPlease see :py:class:`monai.networks.layers.split_args` for additional args parsing."
        )

    def factory_function(self, name: str) -> Callable:
        """
        Decorator for adding a factory function with the given name.
        """

        def _add(func: Callable) -> Callable:
            self.add_factory_callable(name, func)
            return func

        return _add

    def get_constructor(self, factory_name: str, *args) -> Any:
        """
        Get the constructor for the given factory name and arguments.

        Raises:
            TypeError: When ``factory_name`` is not a ``str``.

        """

        if not isinstance(factory_name, str):
            raise TypeError(f"factory_name must a str but is {type(factory_name).__name__}.")

        func = look_up_option(factory_name.upper(), self.factories)
        return func(*args)

    def __getitem__(self, args) -> Any:
        """
        Get the given name or name/arguments pair. If `args` is a callable it is assumed to be the constructor
        itself and is returned, otherwise it should be the factory name or a pair containing the name and arguments.
        """

        # `args[0]` is actually a type or constructor
        if callable(args):
            return args

        # `args` is a factory name or a name with arguments
        if isinstance(args, str):
            name_obj, args = args, ()
        else:
            name_obj, *args = args

        return self.get_constructor(name_obj, *args)

    def __getattr__(self, key):
        """
        If `key` is a factory name, return it, otherwise behave as inherited. This allows referring to factory names
        as if they were constants, eg. `Fact.FOO` for a factory Fact with factory function foo.
        """

        if key in self.factories:
            return key

        return super().__getattribute__(key)

参考链接

LayerFactory 源码文件
Python 魔法方法(三) getattrsetattrdelattr
装饰器博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MONAI label是指使用MONAI库进行医学图像分析时,对图像中的不同区域进行标记的过程。在MONAI中,可以使用自定义的标签来表示不同的区域或结构。可以通过在代码中使用el-tree组件来自定义树型结构上的标签名称。例如,可以使用以下代码来自定义标签名称: ```javascript <el-tree> <span slot-scope="{node}" :title="node.label" class="el-tree-node__label node-label"> {{node.label}} </span> </el-tree> ``` 同时,可以使用CSS样式来定义标签的外观。例如,可以使用以下CSS代码来设置标签的宽度、溢出处理和文本省略: ```css .node-label { width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } ``` 这样可以实现自定义的标签名称和外观效果。如果需要使用CPU版本的MONAI,可以参考\[3\]中提供的链接。如果需要使用GPU版本的MONAI,可以参考\[4\]中提供的链接。 #### 引用[.reference_title] - *1* *2* [「Element」el-tree文字显示不全,解决办法](https://blog.csdn.net/zora_55/article/details/129447833)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [爬虫 + CNN(卷积神经网络)实现名家画作识别与分类](https://blog.csdn.net/zaf0516/article/details/100777824)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值