|
|
|
from typing import Optional, Sequence |
|
|
|
from mmengine.hooks import Hook |
|
from mmengine.runner import Runner |
|
|
|
from mmdet.registry import HOOKS |
|
from mmdet.structures import DetDataSample |
|
|
|
|
|
@HOOKS.register_module() |
|
class MemoryProfilerHook(Hook): |
|
"""Memory profiler hook recording memory information including virtual |
|
memory, swap memory, and the memory of the current process. |
|
|
|
Args: |
|
interval (int): Checking interval (every k iterations). |
|
Default: 50. |
|
""" |
|
|
|
def __init__(self, interval: int = 50) -> None: |
|
try: |
|
from psutil import swap_memory, virtual_memory |
|
self._swap_memory = swap_memory |
|
self._virtual_memory = virtual_memory |
|
except ImportError: |
|
raise ImportError('psutil is not installed, please install it by: ' |
|
'pip install psutil') |
|
|
|
try: |
|
from memory_profiler import memory_usage |
|
self._memory_usage = memory_usage |
|
except ImportError: |
|
raise ImportError( |
|
'memory_profiler is not installed, please install it by: ' |
|
'pip install memory_profiler') |
|
|
|
self.interval = interval |
|
|
|
def _record_memory_information(self, runner: Runner) -> None: |
|
"""Regularly record memory information. |
|
|
|
Args: |
|
runner (:obj:`Runner`): The runner of the training or evaluation |
|
process. |
|
""" |
|
|
|
virtual_memory = self._virtual_memory() |
|
swap_memory = self._swap_memory() |
|
|
|
process_memory = self._memory_usage()[0] |
|
factor = 1024 * 1024 |
|
runner.logger.info( |
|
'Memory information ' |
|
'available_memory: ' |
|
f'{round(virtual_memory.available / factor)} MB, ' |
|
'used_memory: ' |
|
f'{round(virtual_memory.used / factor)} MB, ' |
|
f'memory_utilization: {virtual_memory.percent} %, ' |
|
'available_swap_memory: ' |
|
f'{round((swap_memory.total - swap_memory.used) / factor)}' |
|
' MB, ' |
|
f'used_swap_memory: {round(swap_memory.used / factor)} MB, ' |
|
f'swap_memory_utilization: {swap_memory.percent} %, ' |
|
'current_process_memory: ' |
|
f'{round(process_memory)} MB') |
|
|
|
def after_train_iter(self, |
|
runner: Runner, |
|
batch_idx: int, |
|
data_batch: Optional[dict] = None, |
|
outputs: Optional[dict] = None) -> None: |
|
"""Regularly record memory information. |
|
|
|
Args: |
|
runner (:obj:`Runner`): The runner of the training process. |
|
batch_idx (int): The index of the current batch in the train loop. |
|
data_batch (dict, optional): Data from dataloader. |
|
Defaults to None. |
|
outputs (dict, optional): Outputs from model. Defaults to None. |
|
""" |
|
if self.every_n_inner_iters(batch_idx, self.interval): |
|
self._record_memory_information(runner) |
|
|
|
def after_val_iter( |
|
self, |
|
runner: Runner, |
|
batch_idx: int, |
|
data_batch: Optional[dict] = None, |
|
outputs: Optional[Sequence[DetDataSample]] = None) -> None: |
|
"""Regularly record memory information. |
|
|
|
Args: |
|
runner (:obj:`Runner`): The runner of the validation process. |
|
batch_idx (int): The index of the current batch in the val loop. |
|
data_batch (dict, optional): Data from dataloader. |
|
Defaults to None. |
|
outputs (Sequence[:obj:`DetDataSample`], optional): |
|
Outputs from model. Defaults to None. |
|
""" |
|
if self.every_n_inner_iters(batch_idx, self.interval): |
|
self._record_memory_information(runner) |
|
|
|
def after_test_iter( |
|
self, |
|
runner: Runner, |
|
batch_idx: int, |
|
data_batch: Optional[dict] = None, |
|
outputs: Optional[Sequence[DetDataSample]] = None) -> None: |
|
"""Regularly record memory information. |
|
|
|
Args: |
|
runner (:obj:`Runner`): The runner of the testing process. |
|
batch_idx (int): The index of the current batch in the test loop. |
|
data_batch (dict, optional): Data from dataloader. |
|
Defaults to None. |
|
outputs (Sequence[:obj:`DetDataSample`], optional): |
|
Outputs from model. Defaults to None. |
|
""" |
|
if self.every_n_inner_iters(batch_idx, self.interval): |
|
self._record_memory_information(runner) |
|
|