|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- # Tutorial 5: Customize Runtime Settings
-
- ## Customize optimization settings
-
- ### Customize optimizer supported by Pytorch
-
- We already support to use all the optimizers implemented by PyTorch, and the only modification is to change the `optimizer` field of config files.
- For example, if you want to use `ADAM` (note that the performance could drop a lot), the modification could be as the following.
-
- ```python
- optimizer = dict(type='Adam', lr=0.0003, weight_decay=0.0001)
- ```
-
- To modify the learning rate of the model, the users only need to modify the `lr` in the config of optimizer. The users can directly set arguments following the [API doc](https://pytorch.org/docs/stable/optim.html?highlight=optim#module-torch.optim) of PyTorch.
-
- ### Customize self-implemented optimizer
-
- #### 1. Define a new optimizer
-
- A customized optimizer could be defined as following.
-
- Assume you want to add a optimizer named `MyOptimizer`, which has arguments `a`, `b`, and `c`.
- You need to create a new directory named `mmdet/core/optimizer`.
- And then implement the new optimizer in a file, e.g., in `mmdet/core/optimizer/my_optimizer.py`:
-
- ```python
- from .registry import OPTIMIZERS
- from torch.optim import Optimizer
-
-
- @OPTIMIZERS.register_module()
- class MyOptimizer(Optimizer):
-
- def __init__(self, a, b, c)
-
- ```
-
- #### 2. Add the optimizer to registry
-
- To find the above module defined above, this module should be imported into the main namespace at first. There are two options to achieve it.
-
- - Modify `mmdet/core/optimizer/__init__.py` to import it.
-
- The newly defined module should be imported in `mmdet/core/optimizer/__init__.py` so that the registry will
- find the new module and add it:
-
- ```python
- from .my_optimizer import MyOptimizer
- ```
-
- - Use `custom_imports` in the config to manually import it
-
- ```python
- custom_imports = dict(imports=['mmdet.core.optimizer.my_optimizer'], allow_failed_imports=False)
- ```
-
- The module `mmdet.core.optimizer.my_optimizer` will be imported at the beginning of the program and the class `MyOptimizer` is then automatically registered.
- Note that only the package containing the class `MyOptimizer` should be imported.
- `mmdet.core.optimizer.my_optimizer.MyOptimizer` **cannot** be imported directly.
-
- Actually users can use a totally different file directory structure using this importing method, as long as the module root can be located in `PYTHONPATH`.
-
- #### 3. Specify the optimizer in the config file
-
- Then you can use `MyOptimizer` in `optimizer` field of config files.
- In the configs, the optimizers are defined by the field `optimizer` like the following:
-
- ```python
- optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
- ```
-
- To use your own optimizer, the field can be changed to
-
- ```python
- optimizer = dict(type='MyOptimizer', a=a_value, b=b_value, c=c_value)
- ```
-
- ### Customize optimizer constructor
-
- Some models may have some parameter-specific settings for optimization, e.g. weight decay for BatchNorm layers.
- The users can do those fine-grained parameter tuning through customizing optimizer constructor.
-
- ```python
- from mmcv.utils import build_from_cfg
-
- from mmcv.runner.optimizer import OPTIMIZER_BUILDERS, OPTIMIZERS
- from mmdet.utils import get_root_logger
- from .my_optimizer import MyOptimizer
-
-
- @OPTIMIZER_BUILDERS.register_module()
- class MyOptimizerConstructor(object):
-
- def __init__(self, optimizer_cfg, paramwise_cfg=None):
-
- def __call__(self, model):
-
- return my_optimizer
-
- ```
-
- The default optimizer constructor is implemented [here](https://github.com/open-mmlab/mmcv/blob/9ecd6b0d5ff9d2172c49a182eaa669e9f27bb8e7/mmcv/runner/optimizer/default_constructor.py#L11), which could also serve as a template for new optimizer constructor.
-
- ### Additional settings
-
- Tricks not implemented by the optimizer should be implemented through optimizer constructor (e.g., set parameter-wise learning rates) or hooks. We list some common settings that could stabilize the training or accelerate the training. Feel free to create PR, issue for more settings.
-
- - __Use gradient clip to stabilize training__:
- Some models need gradient clip to clip the gradients to stabilize the training process. An example is as below:
-
- ```python
- optimizer_config = dict(
- _delete_=True, grad_clip=dict(max_norm=35, norm_type=2))
- ```
-
- If your config inherits the base config which already sets the `optimizer_config`, you might need `_delete_=True` to override the unnecessary settings. See the [config documentation](https://mmdetection.readthedocs.io/en/latest/tutorials/config.html) for more details.
-
- - __Use momentum schedule to accelerate model convergence__:
- We support momentum scheduler to modify model's momentum according to learning rate, which could make the model converge in a faster way.
- Momentum scheduler is usually used with LR scheduler, for example, the following config is used in 3D detection to accelerate convergence.
- For more details, please refer to the implementation of [CyclicLrUpdater](https://github.com/open-mmlab/mmcv/blob/f48241a65aebfe07db122e9db320c31b685dc674/mmcv/runner/hooks/lr_updater.py#L327) and [CyclicMomentumUpdater](https://github.com/open-mmlab/mmcv/blob/f48241a65aebfe07db122e9db320c31b685dc674/mmcv/runner/hooks/momentum_updater.py#L130).
-
- ```python
- lr_config = dict(
- policy='cyclic',
- target_ratio=(10, 1e-4),
- cyclic_times=1,
- step_ratio_up=0.4,
- )
- momentum_config = dict(
- policy='cyclic',
- target_ratio=(0.85 / 0.95, 1),
- cyclic_times=1,
- step_ratio_up=0.4,
- )
- ```
-
- ## Customize training schedules
-
- By default we use step learning rate with 1x schedule, this calls [`StepLRHook`](https://github.com/open-mmlab/mmcv/blob/f48241a65aebfe07db122e9db320c31b685dc674/mmcv/runner/hooks/lr_updater.py#L153) in MMCV.
- We support many other learning rate schedule [here](https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py), such as `CosineAnnealing` and `Poly` schedule. Here are some examples
-
- - Poly schedule:
-
- ```python
- lr_config = dict(policy='poly', power=0.9, min_lr=1e-4, by_epoch=False)
- ```
-
- - ConsineAnnealing schedule:
-
- ```python
- lr_config = dict(
- policy='CosineAnnealing',
- warmup='linear',
- warmup_iters=1000,
- warmup_ratio=1.0 / 10,
- min_lr_ratio=1e-5)
- ```
-
- ## Customize workflow
-
- Workflow is a list of (phase, epochs) to specify the running order and epochs.
- By default it is set to be
-
- ```python
- workflow = [('train', 1)]
- ```
-
- which means running 1 epoch for training.
- Sometimes user may want to check some metrics (e.g. loss, accuracy) about the model on the validate set.
- In such case, we can set the workflow as
-
- ```python
- [('train', 1), ('val', 1)]
- ```
-
- so that 1 epoch for training and 1 epoch for validation will be run iteratively.
-
- **Note**:
-
- 1. The parameters of model will not be updated during val epoch.
- 2. Keyword `total_epochs` in the config only controls the number of training epochs and will not affect the validation workflow.
- 3. Workflows `[('train', 1), ('val', 1)]` and `[('train', 1)]` will not change the behavior of `EvalHook` because `EvalHook` is called by `after_train_epoch` and validation workflow only affect hooks that are called through `after_val_epoch`. Therefore, the only difference between `[('train', 1), ('val', 1)]` and `[('train', 1)]` is that the runner will calculate losses on validation set after each training epoch.
-
- ## Customize hooks
-
- ### Customize self-implemented hooks
-
- #### 1. Implement a new hook
-
- There are some occasions when the users might need to implement a new hook. MMDetection supports customized hooks in training (#3395) since v2.3.0. Thus the users could implement a hook directly in mmdet or their mmdet-based codebases and use the hook by only modifying the config in training.
- Before v2.3.0, the users need to modify the code to get the hook registered before training starts.
- Here we give an example of creating a new hook in mmdet and using it in training.
-
- ```python
- from mmcv.runner import HOOKS, Hook
-
-
- @HOOKS.register_module()
- class MyHook(Hook):
-
- def __init__(self, a, b):
- pass
-
- def before_run(self, runner):
- pass
-
- def after_run(self, runner):
- pass
-
- def before_epoch(self, runner):
- pass
-
- def after_epoch(self, runner):
- pass
-
- def before_iter(self, runner):
- pass
-
- def after_iter(self, runner):
- pass
- ```
-
- Depending on the functionality of the hook, the users need to specify what the hook will do at each stage of the training in `before_run`, `after_run`, `before_epoch`, `after_epoch`, `before_iter`, and `after_iter`.
-
- #### 2. Register the new hook
-
- Then we need to make `MyHook` imported. Assuming the file is in `mmdet/core/utils/my_hook.py` there are two ways to do that:
-
- - Modify `mmdet/core/utils/__init__.py` to import it.
-
- The newly defined module should be imported in `mmdet/core/utils/__init__.py` so that the registry will
- find the new module and add it:
-
- ```python
- from .my_hook import MyHook
- ```
-
- - Use `custom_imports` in the config to manually import it
-
- ```python
- custom_imports = dict(imports=['mmdet.core.utils.my_hook'], allow_failed_imports=False)
- ```
-
- #### 3. Modify the config
-
- ```python
- custom_hooks = [
- dict(type='MyHook', a=a_value, b=b_value)
- ]
- ```
-
- You can also set the priority of the hook by adding key `priority` to `'NORMAL'` or `'HIGHEST'` as below
-
- ```python
- custom_hooks = [
- dict(type='MyHook', a=a_value, b=b_value, priority='NORMAL')
- ]
- ```
-
- By default the hook's priority is set as `NORMAL` during registration.
-
- ### Use hooks implemented in MMCV
-
- If the hook is already implemented in MMCV, you can directly modify the config to use the hook as below
-
- #### 4. Example: `NumClassCheckHook`
-
- We implement a customized hook named [NumClassCheckHook](https://github.com/open-mmlab/mmdetection/blob/master/mmdet/datasets/utils.py) to check whether the `num_classes` in head matches the length of `CLASSSES` in `dataset`.
-
- We set it in [default_runtime.py](https://github.com/open-mmlab/mmdetection/blob/master/configs/_base_/default_runtime.py).
-
- ```python
- custom_hooks = [dict(type='NumClassCheckHook')]
- ```
-
- ### Modify default runtime hooks
-
- There are some common hooks that are not registered through `custom_hooks`, they are
-
- - log_config
- - checkpoint_config
- - evaluation
- - lr_config
- - optimizer_config
- - momentum_config
-
- In those hooks, only the logger hook has the `VERY_LOW` priority, others' priority are `NORMAL`.
- The above-mentioned tutorials already covers how to modify `optimizer_config`, `momentum_config`, and `lr_config`.
- Here we reveals how what we can do with `log_config`, `checkpoint_config`, and `evaluation`.
-
- #### Checkpoint config
-
- The MMCV runner will use `checkpoint_config` to initialize [`CheckpointHook`](https://github.com/open-mmlab/mmcv/blob/9ecd6b0d5ff9d2172c49a182eaa669e9f27bb8e7/mmcv/runner/hooks/checkpoint.py#L9).
-
- ```python
- checkpoint_config = dict(interval=1)
- ```
-
- The users could set `max_keep_ckpts` to only save only small number of checkpoints or decide whether to store state dict of optimizer by `save_optimizer`. More details of the arguments are [here](https://mmcv.readthedocs.io/en/latest/api.html#mmcv.runner.CheckpointHook)
-
- #### Log config
-
- The `log_config` wraps multiple logger hooks and enables to set intervals. Now MMCV supports `WandbLoggerHook`, `MlflowLoggerHook`, and `TensorboardLoggerHook`.
- The detail usages can be found in the [doc](https://mmcv.readthedocs.io/en/latest/api.html#mmcv.runner.LoggerHook).
-
- ```python
- log_config = dict(
- interval=50,
- hooks=[
- dict(type='TextLoggerHook'),
- dict(type='TensorboardLoggerHook')
- ])
- ```
-
- #### Evaluation config
-
- The config of `evaluation` will be used to initialize the [`EvalHook`](https://github.com/open-mmlab/mmdetection/blob/7a404a2c000620d52156774a5025070d9e00d918/mmdet/core/evaluation/eval_hooks.py#L8).
- Except the key `interval`, other arguments such as `metric` will be passed to the `dataset.evaluate()`
-
- ```python
- evaluation = dict(interval=1, metric='bbox')
- ```
|