Skip to content

base_dataset

data.dataset.base_dataset

모든 데이터셋 구현에 사용되는 기본 클래스를 정의합니다.

logger module-attribute

logger = getLogger('SaigeResearch')

Transform

Transform(image_mode: Union[str, List[str]] = 'RGB', inspection_size_wh: Optional[ImageSizeType] = None, roi: Optional[Dict] = None, resize: Optional[Dict] = None, augmentation: Optional[Dict] = None, roi_mask_first: bool = True)
Source code in SaigeToolkit/data/transform/transform.py
def __init__(
    self,
    image_mode: Union[str, List[str]] = "RGB",
    inspection_size_wh: Optional[ImageSizeType] = None,
    roi: Optional[Dict] = None,
    resize: Optional[Dict] = None,
    augmentation: Optional[Dict] = None,
    roi_mask_first: bool = True,  # 하위 호환성을 위해 roi_mask_first=True를 기본값으로 설정
):
    self.roi_mask_first = roi_mask_first
    self.image_loader = ImageLoader(image_mode=image_mode)
    self.roi_handler = ROIHandler(**roi) if roi is not None else None
    self.base_resizer = Resizer(**resize) if resize is not None else None

    # inspection_size_wh 설정 시 그 값에 따라 초기화
    self.inspection_size_resizer: Optional[InspectionSizeResizer] = None
    self.stacked_resizer_handler: StackedResizerHandler = None

    # inspection_size_wh setter에서 inspection_size_resizer와 stacked_resizer_handler 생성
    self.inspection_size_wh = inspection_size_wh

    if augmentation is None:
        self.augmentation = None
    elif "_target_" in augmentation:
        self.augmentation = build_augmentation(augmentation)
    else:
        raise NotImplementedError("Old version of augmentation config is not supported.")

roi_mask_first instance-attribute

roi_mask_first = roi_mask_first

image_loader instance-attribute

image_loader = ImageLoader(image_mode=image_mode)

roi_handler instance-attribute

roi_handler = ROIHandler(**roi) if roi is not None else None

base_resizer instance-attribute

base_resizer = Resizer(**resize) if resize is not None else None

inspection_size_resizer instance-attribute

inspection_size_resizer: Optional[InspectionSizeResizer] = None

stacked_resizer_handler instance-attribute

stacked_resizer_handler: StackedResizerHandler = None

inspection_size_wh property writable

inspection_size_wh: Optional[ImageSizeType]

augmentation instance-attribute

augmentation = None

Operation

Bases: str, Enum

ROI class-attribute instance-attribute
ROI = auto()
InspectionSize class-attribute instance-attribute
InspectionSize = auto()
Resize class-attribute instance-attribute
Resize = auto()

__call__

__call__(data: Dict, warmup: bool = False) -> Dict

data Dict에 transform을 적용합니다.

Parameters:

  • data (Dict) –

    data Dictionary

  • warmup (bool, default: False ) –

    InferenceHandler warmup시에 사용하는 파라미터 입니다. True일 경우, 현재 transform을 적용했을 때 나올 수 있는 가장 큰 image size로 transform을 적용합니다. Transform operation 중 ROI의 경우 input image에 따라 output size가 매번 바뀔 수 있기 때문에 해당 옵션이 추가되었습니다. Defaults to False.

Returns:

  • Dict ( Dict ) –

    transform이 적용된 데이터 Dict입니다.

Source code in SaigeToolkit/data/transform/transform.py
def __call__(self, data: Dict, warmup: bool = False) -> Dict:
    """data Dict에 transform을 적용합니다.

    Args:
        data (Dict): data Dictionary
        warmup (bool, optional): InferenceHandler warmup시에 사용하는 파라미터 입니다. True일 경우,
                                    현재 transform을 적용했을 때 나올 수 있는 가장 큰 image size로
                                    transform을 적용합니다.
                                 Transform operation 중 ROI의 경우 input image에 따라 output size가
                                    매번 바뀔 수 있기 때문에 해당 옵션이 추가되었습니다.
                                 Defaults to False.

    Returns:
        Dict: transform이 적용된 데이터 Dict입니다.
    """
    # transform_params 설정
    if "transform_params" not in data:
        data["transform_params"] = {
            "operation_stack": [
                self.Operation.ROI,
                self.Operation.InspectionSize,
                self.Operation.Resize,
            ],
            "operation_params": {},
        }

    operation_params: Dict = data["transform_params"]["operation_params"]

    # load PIL Image
    data = self.image_loader(**data)

    # 원본 이미지가 inspection_size를 넘지 않도록 resize 했을 때의 image scale 계산
    if self.inspection_size_resizer is not None:
        self.inspection_size_resizer.set_scale_from_data(**data)

    # ROI crop 적용
    if self.roi_handler is not None:
        data, roi_revert_params = self.roi_handler.apply_crop(
            return_revert_params=True, warmup=warmup, **data
        )
        if self.roi_mask_first:
            data = self.roi_handler.apply_mask(**data)

        if self.Operation.ROI in operation_params:
            raise KeyError
        operation_params[self.Operation.ROI] = roi_revert_params

    # inspection_size와 resize_factor를 하나로 묶어서 resize
    data, revert_param_list = self.stacked_resizer_handler(return_revert_params=True, **data)
    inspection_size_revert_params, resizer_revert_params = revert_param_list

    if inspection_size_revert_params is not None:
        if self.Operation.InspectionSize in operation_params:
            raise KeyError
        operation_params[self.Operation.InspectionSize] = inspection_size_revert_params

    if resizer_revert_params is not None:
        if self.Operation.Resize in operation_params:
            raise KeyError
        operation_params[self.Operation.Resize] = resizer_revert_params

    # # ROI blind mask 적용
    if self.roi_handler is not None and not self.roi_mask_first:
        data = self.roi_handler.apply_mask(**data)

    # data augmentation
    if self.augmentation is not None:
        data = self.augmentation(**data)

    return data

get_resize_scale classmethod

get_resize_scale(transform_params: Dict) -> List[float]

before_transform_image_size -> after_transform_input_size가 되기 위한 scale을 구합니다. before_transform_image_size * scale = after_transform_input_size

Parameters:

  • transform_params (Dict) –

    transform시에 저장해둔 parameter 입니다.

Returns:

  • List[float]

    List[float]: before_transform_image_size * scale = after_transform_input_size인 scale scale: [scale_width, scale_height]

Source code in SaigeToolkit/data/transform/transform.py
@classmethod
def get_resize_scale(cls, transform_params: Dict) -> List[float]:
    """before_transform_image_size -> after_transform_input_size가 되기 위한 scale을 구합니다.
    before_transform_image_size * scale = after_transform_input_size

    Args:
        transform_params (Dict): transform시에 저장해둔 parameter 입니다.

    Returns:
        List[float]: before_transform_image_size * scale = after_transform_input_size인 scale
                     scale: [scale_width, scale_height]
    """
    operation_params: Dict = transform_params["operation_params"]
    inspection_size_revert_params = operation_params.get(cls.Operation.InspectionSize, None)
    resizer_revert_params = operation_params.get(cls.Operation.Resize, None)

    if inspection_size_revert_params is None and resizer_revert_params is None:
        resize_scale = [1.0, 1.0]
    else:
        if inspection_size_revert_params is None:
            image_size_before_resize = resizer_revert_params["image_size_before_resize"]
            image_size_after_resize = resizer_revert_params["image_size_after_resize"]
        elif resizer_revert_params is None:
            image_size_before_resize = inspection_size_revert_params["image_size_before_resize"]
            image_size_after_resize = inspection_size_revert_params["image_size_after_resize"]
        else:
            image_size_before_resize = inspection_size_revert_params["image_size_before_resize"]
            image_size_after_resize = resizer_revert_params["image_size_after_resize"]

        resize_scale = (
            np.array(image_size_after_resize) / np.array(image_size_before_resize)
        ).tolist()

    return resize_scale

_get_next_revert_operation staticmethod

_get_next_revert_operation(transform_params: Dict) -> Optional[Operation]

다음으로 할 revert operation을 가져옵니다. operation_stack에서 operation이 제거되지는 않습니다.

Parameters:

  • transform_params (Dict) –

    transform시에 저장해둔 parameter 입니다.

Returns:

  • Optional[Operation]

    Optional[Operation]: 남아있는 revert operation이 있으면 operation을 없으면 None을 반환합니다.

Source code in SaigeToolkit/data/transform/transform.py
@staticmethod
def _get_next_revert_operation(transform_params: Dict) -> Optional[Operation]:
    """다음으로 할 revert operation을 가져옵니다. operation_stack에서 operation이 제거되지는 않습니다.

    Args:
        transform_params (Dict): transform시에 저장해둔 parameter 입니다.

    Returns:
        Optional[Operation]: 남아있는 revert operation이 있으면 operation을 없으면 None을 반환합니다.
    """
    operation_stack: List = transform_params["operation_stack"]
    next_operation = None
    if len(operation_stack) > 0:
        next_operation = operation_stack[-1]

    return next_operation

revert classmethod

revert(data: Dict, transform_params: Dict, operation: Optional[Operation] = None) -> Dict

summary

Parameters:

  • data (Dict) –

    revert operation을 적용할 data dictionary입니다. data는 다음과 같은 구조를 지닙니다. { "key1": { "data" (Union[np.ndarray, torch.Tensor, List[Dict]]): 실제 data입니다. "data_type" (str): 해당 data의 type 입니다. 현재 ["array", "objects"]를 지원합니다. }, "key2": { "data" (Union[np.ndarray, torch.Tensor, List[Dict]]): 실제 data입니다. "data_type" (str): 해당 data의 type 입니다. 현재 ["array", "objects"]를 지원합니다. }, ... }

  • transform_params (Dict) –

    transform시에 저장해둔 parameter 입니다.

  • operation (Optional[Operation], default: None ) –

    transform에서 revert가 가능한 operation 입니다. Enum class인 Transform.Operation에 있는 항목들을 지원합니다. operation이 None이 아닐 시, 해당 operation 까지 revert를 적용하고, None일 시, 그 다음 revert operation을 적용합니다. Defaults to None.

Raises:

  • RevertOperationNotFoundError

    args로 넣은 operation이 남은 revert operation 중에 없을 때 에러를 발생합니다.

Returns:

  • Dict ( Dict ) –

    revert operation이 적용된 data dictionary 입니다. 구조는 Args의 data와 같습니다.

Source code in SaigeToolkit/data/transform/transform.py
@classmethod
def revert(
    cls,
    data: Dict,
    transform_params: Dict,
    operation: Optional[Operation] = None,
) -> Dict:
    """_summary_

    Args:
        data (Dict): revert operation을 적용할 data dictionary입니다. data는 다음과 같은 구조를 지닙니다.
            {
                "key1": {
                    "data" (Union[np.ndarray, torch.Tensor, List[Dict]]): 실제 data입니다.
                    "data_type" (str): 해당 data의 type 입니다. 현재 ["array", "objects"]를 지원합니다.
                },
                "key2": {
                    "data" (Union[np.ndarray, torch.Tensor, List[Dict]]): 실제 data입니다.
                    "data_type" (str): 해당 data의 type 입니다. 현재 ["array", "objects"]를 지원합니다.
                },
                ...
            }
        transform_params (Dict): transform시에 저장해둔 parameter 입니다.
        operation (Optional[Operation], optional): transform에서 revert가 가능한 operation 입니다.
                                                    Enum class인 Transform.Operation에 있는 항목들을 지원합니다.
                                                    operation이 None이 아닐 시, 해당 operation 까지 revert를 적용하고,
                                                    None일 시, 그 다음 revert operation을 적용합니다.
                                                    Defaults to None.

    Raises:
        RevertOperationNotFoundError: args로 넣은 operation이 남은 revert operation 중에 없을 때 에러를 발생합니다.

    Returns:
        Dict: revert operation이 적용된 data dictionary 입니다. 구조는 Args의 data와 같습니다.
    """
    # operation이 None인 경우 다음 revert operation 하나를 진행
    if operation is None:
        data = cls._revert(data=data, transform_params=transform_params)
    # operation이 None이 아닌 경우
    else:
        # 해당 operation이 operation_stack에 있는지 확인
        operation_stack: List = transform_params["operation_stack"]
        if operation not in operation_stack:
            raise RevertOperationNotFoundError
        # 해당 operation까지 revert를 적용
        while cls._get_next_revert_operation(transform_params=transform_params) != operation:
            data = cls._revert(data=data, transform_params=transform_params)
        data = cls._revert(data=data, transform_params=transform_params)

    return data

_revert classmethod

_revert(data: Dict, transform_params: Dict) -> Dict
Source code in SaigeToolkit/data/transform/transform.py
@classmethod
def _revert(
    cls,
    data: Dict,
    transform_params: Dict,
) -> Dict:
    operation_stack: List = transform_params["operation_stack"]
    operation_params: Dict = transform_params["operation_params"]

    if cls._get_next_revert_operation(transform_params) is None:
        raise RevertOperationStackEmptyError

    next_revert_operation = operation_stack.pop()
    revert_params = operation_params.pop(next_revert_operation, None)

    next_revert_operation = {
        cls.Operation.ROI: cls._revert_roi,
        cls.Operation.Resize: cls._revert_resize,
        cls.Operation.InspectionSize: cls._revert_resize,
    }[next_revert_operation]

    result = {}
    for k, v in data.items():
        result[k] = {
            "data": next_revert_operation(revert_params=revert_params, **v),
            "data_type": v["data_type"],
        }

    return result

_revert_resize staticmethod

_revert_resize(data: Optional[Union[Tensor, ndarray, List[Dict]]], revert_params: Optional[Dict], data_type: str) -> Union[Tensor, ndarray, List[Dict]]
Source code in SaigeToolkit/data/transform/transform.py
@staticmethod
def _revert_resize(
    data: Optional[Union[torch.Tensor, np.ndarray, List[Dict]]],
    revert_params: Optional[Dict],
    data_type: str,
) -> Union[torch.Tensor, np.ndarray, List[Dict]]:
    if data is not None and revert_params is not None:
        image_size_before_resize = revert_params["image_size_before_resize"]
        image_size_after_resize = revert_params["image_size_after_resize"]

        if list(image_size_after_resize) != list(image_size_before_resize):
            if data_type == "array":
                data = resize_array(array=data, target_size=image_size_before_resize)
            elif data_type == "objects":
                resize_scale = (
                    np.array(image_size_before_resize) / np.array(image_size_after_resize)
                ).tolist()
                data = scale_segments_properties(segments_properties=data, scale=resize_scale)
            elif data_type == "polygons":
                data = resize_polygon(
                    polygons=data,
                    image_size=image_size_after_resize,
                    tw=image_size_before_resize[0],
                    th=image_size_before_resize[1],
                )
            else:
                raise NotImplementedError

    return data

_revert_roi staticmethod

_revert_roi(data: Optional[Union[Tensor, ndarray, List[Dict]]], revert_params: Optional[Dict], data_type: str) -> Union[Tensor, ndarray, List[Dict]]
Source code in SaigeToolkit/data/transform/transform.py
@staticmethod
def _revert_roi(
    data: Optional[Union[torch.Tensor, np.ndarray, List[Dict]]],
    revert_params: Optional[Dict],
    data_type: str,
) -> Union[torch.Tensor, np.ndarray, List[Dict]]:
    if data is not None and revert_params is not None:
        image_size_before_roi = revert_params["image_size_before_roi"]
        image_size_after_roi = revert_params["image_size_after_roi"]

        if list(image_size_before_roi) != list(image_size_after_roi):
            image_width, image_height = image_size_before_roi
            roi_left, roi_top, roi_right, roi_bottom = revert_params["roi_coordinates"]
            pad_left = roi_left
            pad_top = roi_top
            pad_right = image_width - roi_right
            pad_bottom = image_height - roi_bottom

            if data_type == "array":
                data = add_constant_margin_array(
                    array=data,
                    left=pad_left,
                    top=pad_top,
                    right=pad_right,
                    bottom=pad_bottom,
                    value=0,
                )
            elif data_type == "objects":
                data = translate_segments_properties(
                    segments_properties=data,
                    left=pad_left,
                    top=pad_top,
                )
            elif data_type == "polygons":
                data = translate_polygon(
                    polygons=data,
                    offset=(-pad_left, -pad_top),
                )
            else:
                raise NotImplementedError

    return data

is_oversized staticmethod

is_oversized(transform_params: Optional[Dict]) -> bool

InspectionSize 연산에서 resize 되었는지 여부를 판단

Source code in SaigeToolkit/data/transform/transform.py
@staticmethod
def is_oversized(transform_params: Optional[Dict]) -> bool:
    """InspectionSize 연산에서 resize 되었는지 여부를 판단"""
    if transform_params is None:
        return False

    inspection_size_params = get_tree_node_with_default(
        transform_params, ["operation_params", Transform.Operation.InspectionSize], None
    )
    if inspection_size_params is None:
        return False

    size1 = tuple(inspection_size_params["image_size_before_resize"])
    size2 = tuple(inspection_size_params["image_size_after_resize"])

    if size1 != size2:
        return True
    else:
        return False

DummyAttribute

ABCMeta

Bases: ABCMeta

"abstract_attribute" from:\ https://stackoverflow.com/questions/23831510/abstract-attribute-not-property/50381071#50381071

__call__

__call__(*args, **kwargs)
Source code in SaigeToolkit/data/dataset/base_dataset.py
def __call__(cls, *args, **kwargs):
    instance = NativeABCMeta.__call__(cls, *args, **kwargs)
    abstract_attributes = {
        name
        for name in dir(instance)
        if getattr(getattr(instance, name), "__is_abstract_attribute__", False)
    }
    if abstract_attributes:
        raise NotImplementedError(
            f"Can't instantiate abstract class {cls.__name__} with abstract attributes: {', '.join(abstract_attributes)}"
        )
    return instance

SaigeDataset

SaigeDataset(crop: Optional[dict] = None, transform: Optional[dict] = None, collate: Optional[Callable[[List[dict]], dict]] = None, device: device = torch.device('cpu'), **neglect: dict)

Bases: Dataset

Saige's basic dataset class.

Attributes:

  • crop_fn (Optional[Callable[[dict], List[dict]]) –

    function cropping image data into image patch data.

  • transform (Type[Transform]) –

    transform class for transforming to a single image data.

  • to_tensor (Callable[[Union[Image.Image, np.ndarray], torch.Tensor]) –

    data returning as Tensor type

  • n_patch (int) –

    number of patches when crop_fn is used.

  • collate_function (Callable[[List[dict]], dict]) –

    function list of data collating into one batch data

initializing Saige base dataset.

Parameters:

  • crop (Optional[dict], default: None ) –

    config for crop function. Defaults to None.

  • transform (Optional[dict], default: None ) –

    config for transforming to a single raw data

  • collate (Optional[Callable[[List[dict]], dict]], default: None ) –

    list of data collating into one batch data. if None, torch.utils basic collate function would be used. Defaults to None.

  • device (device, default: device('cpu') ) –

    gpu device

Source code in SaigeToolkit/data/dataset/base_dataset.py
def __init__(
    self,
    crop: Optional[dict] = None,
    transform: Optional[dict] = None,
    collate: Optional[Callable[[List[dict]], dict]] = None,
    device: torch.device = torch.device("cpu"),
    **neglect: dict,
) -> None:
    """initializing Saige base dataset.

    Args:
        crop (Optional[dict], optional):
            config for crop function. Defaults to None.
        transform (Optional[dict], optional):
            config for transforming to a single raw data
        collate (Optional[Callable[[List[dict]], dict]], optional):
            list of data collating into one batch data.
            if None, torch.utils basic collate function would be used. Defaults to None.
        device (torch.device, optional):
            gpu device
    """
    if neglect:
        logger.warning(f"Neglected arguments: {neglect}")

    # Config options
    self.crop_fn = get_crop_fn(**(crop or {}))
    self.has_crop_fn = crop is not None

    self.transform = Transform(**(transform or {}))

    self.device = device

    if collate is not None:
        assert collate in ["resize", "padding"]
        self.collate_function = {
            "resize": self.resize_collate,
            "padding": self.padding_collate,
        }[collate]
        logger.info(f'[{"DATA".center(9)}] [Base dataset collate] {collate}')

crop_fn instance-attribute

crop_fn = get_crop_fn(**crop or {})

has_crop_fn instance-attribute

has_crop_fn = crop is not None

transform instance-attribute

transform = Transform(**transform or {})

device instance-attribute

device = device

collate_function instance-attribute

collate_function = {'resize': resize_collate, 'padding': padding_collate}[collate]

files property writable

files

__len__

__len__()
Source code in SaigeToolkit/data/dataset/base_dataset.py
def __len__(self):
    return len(self.files)

data_on_memory

data_on_memory()

To store data in RAM memory (faster data loading), put all loaded data ( use self.load_raw_data() ) in list self.data_on_memory. Or define self.data_on_memory as empty list to load data from filesystem everytime.

Source code in SaigeToolkit/data/dataset/base_dataset.py
@abstract_attribute
def data_on_memory(self):
    """
    To store data in RAM memory (faster data loading),
    put all loaded data ( use self.load_raw_data() ) in list `self.data_on_memory`.
    Or define self.data_on_memory as empty list to load data from filesystem everytime.
    """
    pass

stack_data_on_memory

stack_data_on_memory() -> List[dict]

Stack all data on RAM memory for quick-loading purpose. output would be saved on class attribute.

Returns:

  • List[dict]

    List[dict]: Entire data list-dict.

Source code in SaigeToolkit/data/dataset/base_dataset.py
def stack_data_on_memory(self) -> List[dict]:
    """Stack all data on RAM memory for quick-loading purpose.
    output would be saved on class attribute.

    Returns:
        List[dict]: Entire data list-dict.
    """
    data_on_memory = []
    for idx in range(len(self)):
        data_on_memory.append(self.load_raw_data(idx))

    logger.info(f'[{"DATA".center(9)}] [DATA_ON_MEMORY] activated')

    return data_on_memory

load_raw_data

load_raw_data(index)
Source code in SaigeToolkit/data/dataset/base_dataset.py
def load_raw_data(self, index):
    # load image
    file = self.files[index]
    data = self.load_image(file)
    data.update(self.load_label(file))

    return data

load_image

load_image(file)
Source code in SaigeToolkit/data/dataset/base_dataset.py
def load_image(self, file):
    # open image
    if "image_path" in file:
        image = file["image_path"]
    elif "path" in file:
        image = file["path"]
    elif "Path" in file:
        image = file["Path"]
    else:
        raise NotImplementedError(f"no known image path item in {file.keys()}")

    data = self.transform.image_loader(image)

    return data

load_label abstractmethod

load_label(file)
Source code in SaigeToolkit/data/dataset/base_dataset.py
@abstractmethod
def load_label(self, file):
    pass

__getitem__

__getitem__(index: int) -> Union[dict, List[dict]]

dataset default getitem function. data is first loaded, then processed as following order: resize, augmentation, transform to torch.Tensor. data could be loaded from file_system (load_raw_data) or RAM memory (data_on_memory).

Parameters:

  • index (int) –

    data item index.

Returns:

  • Union[dict, List[dict]]

    Union[dict, List[dict]]: single data, or cropped data list when crop_fn exists.

Source code in SaigeToolkit/data/dataset/base_dataset.py
def __getitem__(self, index: int) -> Union[dict, List[dict]]:
    """dataset default __getitem__ function.
    data is first loaded, then processed as following order:
        resize, augmentation, transform to torch.Tensor.
    data could be loaded from file_system (load_raw_data) or RAM memory (data_on_memory).

    Args:
        index (int): data item index.

    Returns:
        Union[dict, List[dict]]:
            single data, or cropped data list when crop_fn exists.
    """

    # Load Images and Text or Image Labels
    if self.data_on_memory:
        data = self.data_on_memory[index]
    else:
        data = self.load_raw_data(index)

    # ROI
    if self.transform.roi_handler is not None:
        if self.has_crop_fn:
            data = self.transform.roi_handler(**data)
        else:
            data = self.transform.roi_handler.apply_crop(**data)

    assert "image" in data, "SaigeDataset currently only supports image dataset"

    if not self.has_crop_fn:
        data = self.process_data(data)

        return data

    else:
        l_data_raw = self.crop_fn(**data)

        batch = []
        for data_patch in l_data_raw:
            batch.append(self.process_data(data_patch))

        return batch

process_data

process_data(data: dict) -> dict

data processing after raw loading.

- resize: Resize Image and Label
- btw_resize_aug: Dummy function for user customization
- augmentation: Process augmentation defined in util/augmentation
- btw_aug_transform: Dummy function for user customization
- to_tensor: Transform data to torch tensor

Parameters:

  • data (dict) –

    raw data dict

Returns:

  • dict ( dict ) –

    processed data dict

Source code in SaigeToolkit/data/dataset/base_dataset.py
def process_data(self, data: dict) -> dict:
    """data processing after raw loading.

        - resize: Resize Image and Label
        - btw_resize_aug: Dummy function for user customization
        - augmentation: Process augmentation defined in util/augmentation
        - btw_aug_transform: Dummy function for user customization
        - to_tensor: Transform data to torch tensor

    Args:
        data (dict): raw data dict

    Returns:
        dict: processed data dict
    """
    if self.transform.base_resizer is not None:
        data = self.transform.base_resizer(**data)

    if self.transform.roi_handler is not None and not self.has_crop_fn:
        data = self.transform.roi_handler.apply_mask(**data)

    if self.transform.augmentation is not None:
        data = self.transform.augmentation(**data)

    data = self.to_tensor(**data)

    return data

to_tensor

to_tensor(**data: dict) -> dict

to_tensor items in data into torch.Tensor (if convertible)

Parameters:

  • data (dict, default: {} ) –

    raw data dict

Returns:

  • dict ( dict ) –

    tensorized data dict

Source code in SaigeToolkit/data/dataset/base_dataset.py
def to_tensor(self, **data: dict) -> dict:
    """to_tensor items in data into torch.Tensor (if convertible)

    Args:
        data (dict): raw data dict

    Returns:
        dict: tensorized data dict
    """

    def _to_tensor_from_numpy(image: np.ndarray):
        return torch.from_numpy(image).to(self.device).contiguous()

    def _to_tensor_from_pil_image(image: Image.Image):
        return _to_tensor_from_numpy(np.array(image))

    for k, v in data.items():
        if k == "org_image":
            continue

        if isinstance(v, Image.Image):
            data[k] = _to_tensor_from_pil_image(v)

        elif isinstance(v, np.ndarray):
            data[k] = _to_tensor_from_numpy(v)

        elif isinstance(v, int):
            data[k] = torch.tensor(v).to(self.device).contiguous()

        else:
            continue

        if k == "image":
            data[k] = data[k].permute((2, 0, 1)).div(255)
        else:
            data[k] = data[k].long()

    return data

resize_collate

resize_collate(batch: List[dict]) -> dict

Example collate function with resizing items.

Parameters:

  • batch (List[dict]) –

    list of data dicts

Returns:

  • dict ( dict ) –

    resized-and-collated data dict

Source code in SaigeToolkit/data/dataset/base_dataset.py
def resize_collate(self, batch: List[dict]) -> dict:
    """Example collate function with resizing items.

    Args:
        batch (List[dict]): list of data dicts

    Returns:
        dict: resized-and-collated data dict
    """

    img_size = (
        int(np.mean([data["image"].shape[-2] for data in batch])),
        int(np.mean([data["image"].shape[-1] for data in batch])),
    )

    # 이미 tensor 형태로 들어온 상태기 때문에 F.interpolate 함수 사용해보자
    data_out = {key: [] for key in batch[0].keys()}
    for data in batch:
        data_out["image"].append(F.interpolate(data["image"][None], (img_size[0], img_size[1])))

        for k, v in data.items():
            if k == "class":
                data_out[k].append(v.unsqueeze(0))
            elif k == "boxes":
                data_out[k].append(v)
            elif k == "mask":
                data_out[k].append(
                    F.interpolate(v[None, None].float(), (img_size[0], img_size[1]))
                    .long()
                    .squeeze(1)
                )

    for key, value in data_out.items():
        data_out[key] = torch.cat(value)

    return data_out

padding_collate

padding_collate(batch: List[dict]) -> dict

Example collate function with padding items.

Parameters:

  • batch (List[dict]) –

    list of data dicts

Returns:

  • dict ( dict ) –

    padded-and-collated data dict

Source code in SaigeToolkit/data/dataset/base_dataset.py
def padding_collate(self, batch: List[dict]) -> dict:
    """Example collate function with padding items.

    Args:
        batch (List[dict]): list of data dicts

    Returns:
        dict: padded-and-collated data dict
    """

    max_h = np.max([d["image"].shape[-2] for d in batch])
    max_w = np.max([d["image"].shape[-1] for d in batch])

    data_out = {key: [] for key in batch[0].keys()}
    for data in batch:
        data_out["image"].append(
            F.pad(
                data["image"][None],
                (0, max_w - data["image"].shape[-1], 0, max_h - data["image"].shape[-2]),
            )
        )

        for k, v in data.items():
            if k == "class":
                data_out[k].append(v.unsqueeze(0))
            elif k == "boxes":
                data_out[k].append(v)
            elif k == "mask":
                data_out[k].append(F.pad(v[None], (0, max_w - v.shape[-1], 0, max_h - v.shape[-2])))

    for key, value in data_out.items():
        data_out[key] = torch.cat(value)

    return data_out

calculate_patch_number

calculate_patch_number(files: Optional[List[dict]] = None) -> int

When crop_fn is activated, calculate number of text patches.

Parameters:

  • files (Optional[List[dict]], default: None ) –

    list of meta data dict. if None, calculate patch_number from self.files attribute. Defaults to None.

Returns:

  • int ( int ) –

    number of patches in meta data list files

Source code in SaigeToolkit/data/dataset/base_dataset.py
def calculate_patch_number(self, files: Optional[List[dict]] = None) -> int:
    """When crop_fn is activated, calculate number of text patches.

    Args:
        files (Optional[List[dict]], optional): list of meta data dict.
            if None, calculate patch_number from self.files attribute. Defaults to None.

    Returns:
        int: number of patches in meta data list `files`
    """
    if not self.has_crop_fn:
        return len(self)

    if files is None:
        files = self.files

    n_patch = 0
    for file in files:
        labels = self.load_label(file)
        if "polygons" in labels:
            n_patch += self.crop_fn.get_n_patch(labels["polygons"])
        elif "labels" in labels:
            n_patch += len(labels["labels"])
        elif "labels_count" in labels:
            n_patch += labels["labels_count"]
        else:
            n_patch += 1

    logger.info(f"total patch number in files: {n_patch}")

    return n_patch

get_crop_fn

get_crop_fn(_target_: Optional[str] = None, **cfg_crop: dict) -> Optional[BaseCropper]

getting crop function

Parameters:

  • cfg_crop (dict, default: {} ) –

    config dict for building cropper

Returns:

  • Optional[BaseCropper]

    Optional[BaseCropper]: saige cropper object. if cfg_crop is None, return None

Source code in SaigeToolkit/data/crop/builder.py
def get_crop_fn(_target_: Optional[str] = None, **cfg_crop: dict) -> Optional[BaseCropper]:
    """getting crop function

    Args:
        cfg_crop (dict): config dict for building cropper

    Returns:
        Optional[BaseCropper]: saige cropper object.
            if cfg_crop is None, return None
    """
    if _target_ is None:
        return None
    cropper = get_crop_class(_target_)
    logger.info(f"[{'CROPPER'.center(9)}] {_target_} [params] {cfg_crop}")
    return cropper(**cfg_crop)

abstract_attribute

abstract_attribute(obj=None)
Source code in SaigeToolkit/data/dataset/base_dataset.py
def abstract_attribute(obj=None):
    if obj is None:
        obj = DummyAttribute()
    obj.__is_abstract_attribute__ = True
    return obj