MMCV Registry 공부

권유진·2022년 10월 8일
0

MMCV

  • MMCV는 유사한 기능을 공유하는 서로 다른 모듈(backbone, head, necks)을 관리하기 위해 레지스트리(Registry) 구현
  • OpenMMLab의 대부분의 프로젝트는 레지스트리를 사용해 MMDetection, MMDetection3D, MMClassification, MMEditing 등과 같은 데이터 세트 및 모델의 모듈을 관리

Registry

  • 클래스나 함수를 문자열에 매핑
  • 단일 레지스트리에 포함된 클래스 또는 함수는 일반적으로 유사한 API를 갖지만 다른 알고리즘이나 데이터셋을 지원
    • ex) PoseEstimator: HRNet, ViTPose, RSN 등…
  • 레지스트리를 통해 문자열을 통해 클래스, 함수를 찾고 해당 모듈을 인스턴스화하거나 함수 호출해 결과 얻음
  • api

사용법

  1. 빌드 방법 만듦
  2. 레지스트리 만듦
  3. 레지스트리를 활용해 모듈 관리
  • 예시 1
    • 다양한 형식의 데이터를 특정 형식으로 변환하기 위해 Dataset Converter 구현한다고 가정

      # builder.py
      from mmcv.utils import Registry
      
      # create a registry for converters
      CONVERTERS = Registry('converters')
    • converters/builder.py에서 빌더를 구현하는 파일 만듦
      - 핵심 단계는 모듈을 생성할 때 구현된 모듈을 레지스트리에 등록하는 것
      - @CONVERTERS.register_module()
      - 문자열과 클래스(함수) 간의 매핑은 다음과 같이 빌드되고 유지
      - Converter1 → <class ‘Converter1’>
      - converter2 → <function ‘converter2’>

      # converter1.py
      from .builder import CONVERTERS
      
      # use the registry to manage the module
      @CONVERTERS.register_module()
      class Converter1(object):
      	def __init__(self, a, b):
      		self.a = a
      		self.b = b
      # converter2.py
      from .builder import CONVERTERS
      from .converter1 import Converter1
      
      @CONVERTERS.register_module()
      def converter2(a, b):
      	return Converter1(a, b)
    • 모듈이 성공적으로 등록되면 구성을 통해 converter를 다음과 같이 사용 가능

      converter1_cfg = dict(type='Converter1', a=a_value, b=b_value)
      converter2_cfg = dict(type='converter2', a=a_value, b=b_value)
      converter1 = CONVERTERS.build(converter1_cfg)
      result = CONVERTERS.build(converter2_cfg)
  • 예시 2: 빌드 기능 사용자 정의
    from mmcv.utils import Registry
    
    def build_converters(cfg, registry, *args, **kwargs):
    	cfg_ = cfg.copy()
    	converter_type = cfg_.pop('type')
    	if converter_type not in registry:
    		raise KeyError(f'Unrecognized converter type {converter_type}')
    	else:
    		converter_cls = registry.get(converter_type)
    
    	converter = converter_cls(*args, **kwargs, **cfg_)
    	return converter
    
    CONVERTERS = Registry('converter', build_func=build_converter)
  • 예시 3: 계층 레지스트리
    • 둘 이상의 OpenMMLab 프레임워크에서 모듈 빌드
      • ex) MMdetection 객체 탐지기에 대해 MMClassification의 모든 백본과 MMDetection의 탐지 모델과 MMSegmentation의 시맨틱 분할 모델 결합 가능
      1. child registry에서 빌드

        from mmcv.utils import Registry
        from mmcv.cnn import MODELS as MMCV_MODELS
        MODELS = Registry('model', parent=MMCV_MODELS)
        
        @MODELS.register_module()
        class NetA(nn.Module):
        	def forawrd(self, x):
        		return x
        from mmcv.utils import Registry
        from mmcv.cnn import MODELS as MMCV_MODELS
        MODELS = Registry('model', parent=MMCV_MODELS)
        
        @MODELS.register_module()
        class NetB(nn.Module):
        	def forward(self, x):
        		return x+1
        from mmdet.models import MODELS
        
        net_a = MODELS.build(cfg=dict(type='NetA'))
        net_b = MODELS.build(cfg=dict(type='mmcls.NetB'))
        
        # 아래도 동일한 코드
        net_a = MODELS.build(cfg=dict(type='mmdet.NetA'))
        net_b = MODELS.build(cfg=dict(type='NetB'))
      2. 상위 레지스트리에서 빌드

        from mmcv.cnn import MODELS as MMCV_MODELS
        net_a = MMCV_MODELS.build(cfg=dict(type='mmdet.NetA'))
        net_b = MMCV_MODELS.build(cfg=dict(type='mmcls.NetB'))

@ in python

- 클래스 및 함수 decorator
- decorator: 함수, 메소드, 클래스 수정에 사용되는 python object
    - original object를 입력받아 modified object를 반환
    - java에서 영감 받음
- 함수 속에 함수를 입력하는 꼴
- 예시 1
    
    ```python
    @viking_chorus
    def menu_item():
    	print("spam")
    
    # 위 함수는 코드와 동일
    def menu_item():
    	print("spam")
    menu_item = viking_chorus(menu_item)
    
    # viking_chorus는 아래와 같이 정의되어 있다고 가정
    def viking_chorus(myfunc):
    	def inner_func(*args, **kwargs):
    		for i in range(8):
    			myfunc(*args, @@kwargs)
    	return inner_func
    ```
    
- 예시 2
    
    ```python
    @invincible
    @favourite_colour("Blue")
    def black_knight():
    	pass
    
    # 아래와 동일
    def favourite_colour(colour):
    	def decorator(func):
    		def wrapper():
    			print(colour)
    			func()
    		return wrapper
    	return decorator
    
    def black_knight():
    	pass
    
    blacknight = invincible(favourite_colour("Blue")(black_knight))
    
    # 아래와도 동일
    blue_decorator = favourite_colour("Blue")
    decorated_by_blue = blue_decorator(black_knight)
    black_knight = invincible(decorated_by_blue)
    ```
    

모듈화

- 폴더로 패키지를 작성할 때 참조하지 못하는 문제를 해결하기 위해 `__init__.py` 사용
    - 해당 디렉토리가 패키지의 일부임을 알려주는 역할 수행
    - 해당 디렉토리의 모듈을 `*`을 활용해 import할 때 `__all__`이라는 변수 설정하고 import 가능한 모듈 정의

```python
# __init__.py

__all__ = ['hi', 'bye', 'hello']
```

참고
https://better-tomorrow.tistory.com/entry/MMCV-의-Registry
https://mmcv.readthedocs.io/en/latest/understand_mmcv/registry.html
https://wiki.python.org/moin/PythonDecorators#head-f22ccf491766760d15b371b8ed27c8a81b7cde2f
https://nesoy.github.io/articles/2018-07/Python-init-all

profile
데이터사이언스를 공부하는 권유진입니다.

0개의 댓글