Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Docs] Update docstring of base_data_element #836

Merged
merged 5 commits into from
Dec 20, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
112 changes: 59 additions & 53 deletions mmengine/structures/base_data_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,27 @@ class BaseDataElement:
The attributes in ``BaseDataElement`` are divided into two parts,
the ``metainfo`` and the ``data`` respectively.

- ``metainfo``: Usually contains the
information about the image such as filename,
image_shape, pad_shape, etc. The attributes can be accessed or
modified by dict-like or object-like operations, such as
``.``(for data access and modification) , ``in``, ``del``,
``pop(str)``, ``get(str)``, ``metainfo_keys()``,
``metainfo_values()``, ``metainfo_items()``, ``set_metainfo()``(for
set or change key-value pairs in metainfo).

- ``data``: Annotations or model predictions are
stored. The attributes can be accessed or modified by
dict-like or object-like operations, such as
``.`` , ``in``, ``del``, ``pop(str)`` ``get(str)``, ``keys()``,
``values()``, ``items()``. Users can also apply tensor-like
methods to all obj:``torch.Tensor`` in the ``data_fileds``,
such as ``.cuda()``, ``.cpu()``, ``.numpy()``, , ``.to()``
``to_tensor()``, ``.detach()``.
- ``metainfo``: Usually contains the
information about the image such as filename,
image_shape, pad_shape, etc. The attributes can be accessed or
modified by dict-like or object-like operations, such as
``.`` (for data access and modification), ``in``, ``del``,
``pop(str)``, ``get(str)``, ``metainfo_keys()``,
``metainfo_values()``, ``metainfo_items()``, ``set_metainfo()`` (for
set or change key-value pairs in metainfo).

- ``data``: Annotations or model predictions are
stored. The attributes can be accessed or modified by
dict-like or object-like operations, such as
``.``, ``in``, ``del``, ``pop(str)``, ``get(str)``, ``keys()``,
``values()``, ``items()``. Users can also apply tensor-like
methods to all :obj:`torch.Tensor` in the ``data_fields``,
such as ``.cuda()``, ``.cpu()``, ``.numpy()``, ``.to()``,
``to_tensor()``, ``.detach()``.

Args:
metainfo (dict, optional): A dict contains the meta information
of single image. such as ``dict(img_shape=(512, 512, 3),
of single image, such as ``dict(img_shape=(512, 512, 3),
scale_factor=(1, 1, 1, 1))``. Defaults to None.
kwargs (dict, optional): A dict contains annotations of single image or
model predictions. Defaults to None.
Expand All @@ -82,46 +82,52 @@ class BaseDataElement:
... metainfo=dict(img_id=img_id, img_shape=img_shape),
... bboxes=bboxes, scores=scores)
>>> gt_instances = BaseDataElement(
... metainfo=dict(img_id=img_id,
... img_shape=(H, W)))
... metainfo=dict(img_id=img_id, img_shape=(640, 640)))

>>> # new
>>> gt_instances1 = gt_instance.new(
... metainfo=dict(img_id=1, img_shape=(640, 640)),
... bboxes=torch.rand((5, 4)),
... scores=torch.rand((5,)))
>>> gt_instances1 = gt_instances.new(
... metainfo=dict(img_id=1, img_shape=(640, 640)),
... bboxes=torch.rand((5, 4)),
... scores=torch.rand((5,)))
>>> gt_instances2 = gt_instances1.new()

>>> # add and process property
>>> gt_instances = BaseDataElement()
>>> gt_instances.set_metainfo(dict(img_id=9, img_shape=(100, 100))
>>> gt_instances.set_metainfo(dict(img_id=9, img_shape=(100, 100)))
>>> assert 'img_shape' in gt_instances.metainfo_keys()
>>> assert 'img_shape' in gt_instances
>>> assert 'img_shape' not in gt_instances.keys()
>>> assert 'img_shape' in gt_instances.all_keys()
>>> print(gt_instances.img_shape)
(100, 100)
>>> gt_instances.scores = torch.rand((5,))
>>> assert 'scores' in gt_instances.keys()
>>> assert 'scores' in gt_instances
>>> assert 'scores' in gt_instances.all_keys()
>>> assert 'scores' not in gt_instances.metainfo_keys()
>>> print(gt_instances.scores)
tensor([0.5230, 0.7885, 0.2426, 0.3911, 0.4876])
>>> gt_instances.bboxes = torch.rand((5, 4))
>>> assert 'bboxes' in gt_instances.keys()
>>> assert 'bboxes' in gt_instances
>>> assert 'bboxes' in gt_instances.all_keys()
>>> assert 'bboxes' not in gt_instances.metainfo_keys()
>>> print(gt_instances.bboxes)
tensor([[0.0900, 0.0424, 0.1755, 0.4469],
[0.8648, 0.0592, 0.3484, 0.0913],
[0.5808, 0.1909, 0.6165, 0.7088],
[0.5490, 0.4209, 0.9416, 0.2374],
[0.3652, 0.1218, 0.8805, 0.7523]])

>>> # delete and change property
>>> gt_instances = BaseDataElement(
... metainfo=dict(img_id=0, img_shape=(640, 640)),
... bboxes=torch.rand((6, 4)), scores=torch.rand((6,)))
>>> gt_instances.img_shape = (1280, 1280)
... metainfo=dict(img_id=0, img_shape=(640, 640)),
... bboxes=torch.rand((6, 4)), scores=torch.rand((6,)))
>>> gt_instances.set_metainfo(dict(img_shape=(1280, 1280)))
>>> gt_instances.img_shape # (1280, 1280)
>>> gt_instances.bboxes = gt_instances.bboxes * 2
>>> gt_instances.get('img_shape', None) # (640, 640)
>>> gt_instances.get('bboxes', None) # 6x4 tensor
>>> gt_instances.get('img_shape', None) # (1280, 1280)
>>> gt_instances.get('bboxes', None) # 6x4 tensor
>>> del gt_instances.img_shape
>>> del gt_instances.bboxes
>>> assert 'img_shape' not in gt_instances
Expand All @@ -131,19 +137,19 @@ class BaseDataElement:

>>> # Tensor-like
>>> cuda_instances = gt_instances.cuda()
>>> cuda_instances = gt_instancess.to('cuda:0')
>>> cuda_instances = gt_instances.to('cuda:0')
>>> cpu_instances = cuda_instances.cpu()
>>> cpu_instances = cuda_instances.to('cpu')
>>> fp16_instances = cuda_instances.to(
... device=None, dtype=torch.float16, non_blocking=False, copy=False,
... memory_format=torch.preserve_format)
... device=None, dtype=torch.float16, non_blocking=False,
... copy=False, memory_format=torch.preserve_format)
>>> cpu_instances = cuda_instances.detach()
>>> np_instances = cpu_instances.numpy()

>>> # print
>>> metainfo = dict(img_shape=(800, 1196, 3))
>>> gt_instances = BaseDataElement(
>>> metainfo=metainfo, det_labels=torch.LongTensor([0, 1, 2, 3]))
... metainfo=metainfo, det_labels=torch.LongTensor([0, 1, 2, 3]))
>>> sample = BaseDataElement(metainfo=metainfo,
... gt_instances=gt_instances)
>>> print(sample)
Expand Down Expand Up @@ -185,7 +191,7 @@ class BaseDataElement:
... return self._pred_instances
... @pred_instances.setter
... def pred_instances(self, value):
... self.set_field(value,'_pred_instances',
... self.set_field(value, '_pred_instances',
... dtype=BaseDataElement)
... @pred_instances.deleter
... def pred_instances(self):
Expand Down Expand Up @@ -235,7 +241,7 @@ def set_data(self, data: dict) -> None:
model predictions.
"""
assert isinstance(data,
dict), f'meta should be a `dict` but got {data}'
dict), f'data should be a `dict` but got {data}'
for k, v in data.items():
# Use `setattr()` rather than `self.set_field` to allow `set_data`
# to set property method.
Expand All @@ -247,7 +253,7 @@ def update(self, instance: 'BaseDataElement') -> None:

Args:
instance (BaseDataElement): Another BaseDataElement object for
update the current object.
update the current object.
"""
assert isinstance(
instance, BaseDataElement
Expand All @@ -272,7 +278,7 @@ def new(self,
model predictions.

Returns:
BaseDataElement: a new data element with same type.
BaseDataElement: A new data element with same type.
"""
new_data = self.__class__()

Expand All @@ -290,7 +296,7 @@ def clone(self):
"""Deep copy the current data element.

Returns:
BaseDataElement: the copy of current data element.
BaseDataElement: The copy of current data element.
"""
clone_data = self.__class__()
clone_data.set_metainfo(dict(self.metainfo_items()))
Expand Down Expand Up @@ -342,7 +348,7 @@ def all_values(self) -> list:
def all_items(self) -> Iterator[Tuple[str, Any]]:
"""
Returns:
iterator: an iterator object whose element is (key, value) tuple
iterator: An iterator object whose element is (key, value) tuple
pairs for ``metainfo`` and ``data``.
"""
for k in self.all_keys():
Expand All @@ -351,7 +357,7 @@ def all_items(self) -> Iterator[Tuple[str, Any]]:
def items(self) -> Iterator[Tuple[str, Any]]:
"""
Returns:
iterator: an iterator object whose element is (key, value) tuple
iterator: An iterator object whose element is (key, value) tuple
pairs for ``data``.
"""
for k in self.keys():
Expand All @@ -360,7 +366,7 @@ def items(self) -> Iterator[Tuple[str, Any]]:
def metainfo_items(self) -> Iterator[Tuple[str, Any]]:
"""
Returns:
iterator: an iterator object whose element is (key, value) tuple
iterator: An iterator object whose element is (key, value) tuple
pairs for ``metainfo``.
"""
for k in self.metainfo_keys():
Expand All @@ -378,20 +384,20 @@ def __setattr__(self, name: str, value: Any):
super().__setattr__(name, value)
else:
raise AttributeError(f'{name} has been used as a '
'private attribute, which is immutable. ')
'private attribute, which is immutable.')
else:
self.set_field(
name=name, value=value, field_type='data', dtype=None)

def __delattr__(self, item: str):
"""delete the item in dataelement.
"""Delete the item in dataelement.

Args:
item (str): The key to delete.
"""
if item in ('_metainfo_fields', '_data_fields'):
raise AttributeError(f'{item} has been used as a '
'private attribute, which is immutable. ')
'private attribute, which is immutable.')
super().__delattr__(item)
if item in self._metainfo_fields:
self._metainfo_fields.remove(item)
Expand All @@ -402,13 +408,13 @@ def __delattr__(self, item: str):
__delitem__ = __delattr__

def get(self, key, default=None) -> Any:
"""get property in data and metainfo as the same as python."""
"""Get property in data and metainfo as the same as python."""
# Use `getattr()` rather than `self.__dict__.get()` to allow getting
# properties.
return getattr(self, key, default)

def pop(self, *args) -> Any:
"""pop property in data and metainfo as the same as python."""
"""Pop property in data and metainfo as the same as python."""
assert len(args) < 3, '``pop`` get more than 2 arguments'
name = args[0]
if name in self._metainfo_fields:
Expand Down Expand Up @@ -459,7 +465,7 @@ def set_field(self,
raise AttributeError(
f'Cannot set {name} to be a field of data '
f'because {name} is already a metainfo field')
# The name only added to `data_fields`` when it is not the
# The name only added to `data_fields` when it is not the
# attribute related to property(methods decorated by @property).
if not isinstance(
getattr(type(self),
Expand Down Expand Up @@ -513,7 +519,7 @@ def detach(self) -> 'BaseDataElement':

# Tensor-like methods
def numpy(self) -> 'BaseDataElement':
"""Convert all tensor to np.narray in data."""
"""Convert all tensors to np.ndarray in data."""
new_data = self.new()
for k, v in self.items():
if isinstance(v, (torch.Tensor, BaseDataElement)):
Expand All @@ -523,7 +529,7 @@ def numpy(self) -> 'BaseDataElement':
return new_data

def to_tensor(self) -> 'BaseDataElement':
"""Convert all np.narray to tensor in data."""
"""Convert all np.ndarray to tensor in data."""
new_data = self.new()
for k, v in self.items():
data = {}
Expand All @@ -544,7 +550,7 @@ def to_dict(self) -> dict:
}

def __repr__(self) -> str:
"""represent the object."""
"""Represent the object."""

def _addindent(s_: str, num_spaces: int) -> str:
"""This func is modified from `pytorch` https://github.com/pytorch/
Expand All @@ -569,13 +575,13 @@ def _addindent(s_: str, num_spaces: int) -> str:
return s # type: ignore

def dump(obj: Any) -> str:
"""represent the object.
"""Represent the object.

Args:
obj (Any): The obj to represent.

Returns:
str: The represented str .
str: The represented str.
"""
_repr = ''
if isinstance(obj, dict):
Expand Down