Files

490 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 训练器(Solvers)
## 总览
Solver是对模型训练、验证和测试过程的一个流程定义。
在Solver中,会根据配置yaml文件的设置,对数据(data),模型(model),优化器(optimizer)和调度(scheduler)等需要的模块进行逐一初始化。
每一个具体的任务的自定义Solver都要继承自BaseSolver。
在某些特殊场景下,还需要初始化一些自定义的模块。例如,在训练过程中记录保存中间结果需要用到Hooks;在训练过程中验证需要定义Metrics等等。
<hr/>
## 基础用法
子Solver继承时的用法:
```python
from scepter.modules.solver.registry import SOLVERS
from scepter.modules.solver import BaseSolver
@SOLVERS.register_class()
class XxxSolver(BaseSolver):
def __init__(self, cfg, logger=None):
super().__init__(cfg, logger=logger)
```
实际启动Solver的使用方式见scepter.modules/task/cate_recognition中run_task.py和run_inference.py:
```python
solver = SOLVERS.build(cfg.SOLVER, logger=std_logger)
```
<hr/>
## **scepter.modules.solver.BaseSolver**
Solver的基类,是通过元类ABCMeta定义的抽象基类,支持注册操作。自定义的solver均应该是该类的子类,并且进行注册。
BaseSolver是一个具体实现Solver的案例,展示了使用pytorch_lightning和不使用时两种Solver的写法。
在实际使用中情况各异,因此Solver的使用也比较灵活,其中大部分的成员函数均可以按照需求在子类中,被复写或者新加好用的功能,甚至直接写新的函数代替。
<br>
### <font color="#0FB0E4">function **\_\_init\_\_**</font>
(cfg: *scepter.modules.utils.config.Config*, logger = None) -> None
初始化Solver类,从cfg中获取并定义一些必要的参数。
部分在__init__中初始化的参数,详情见代码:
**Configs**
- **FILE_SYSTEM** —— (cfg) 文件系统配置,默认None.
- **WORK_DIR** —— (str) 工作路径定义.
- **LOG_FILE** —— (str) Log文件的位置.
- **RESUME_FROM** —— (str) 恢复训练模型保存的中间结果.
- **MAX_EPOCHS** —— (int) 训练最大epochs数.
- **ACCU_STEP** —— (int) When use ddp, the grad accumulate steps for each process,默认1.
- **NUM_FOLDS** —— (int) Num folds for training,默认1.
- **EVAL_INTERVAL** —— (int) Eval the model interval,默认1.
- **EXTRA_KEYS** —— (List) The extra keys for metrics,默认[].
- **TRAIN_DATA** —— (cfg) 训练数据配置.
- **EVAL_DATA** —— (cfg) 验证数据配置.
- **TEST_DATA** —— (cfg) 测试数据配置.
- **TRAIN_HOOKS** —— (List) 训练HOOKS.
- **EVAL_HOOKS** —— (List) 验证HOOKS.
- **TEST_HOOKS** —— (List) 测试HOOKS.
- **MODEL** —— (cfg) 模型配置.
- **OPTIMIZER** —— (cfg) 优化器配置.
- **LR_SCHEDULER** —— (cfg) 学习率Scheduler配置.
- **METRICS** —— (List) Metrics.
**Parameters**
- **cfg** —— The Config used to build solver.
- **logger** —— Instantiated Logger to print or save log.
<br>
### <font color="#0FB0E4">function **set_up_pre**</font>
() -> None
配置环境、日志路径,调用construct_hook来初始化hook等等。
与pytorch_lightning二选一,在不使用pytorch_lightning(use_pl=Flase)时调用。需要在启动其他所有操作之前调用。
<br>
### <font color="#0FB0E4">function **set_up**</font>
() -> None
配置数据、模型、metrics、优化器及pytorch_lightning环境(如果使用的话)。
<br>
### <font color="#0FB0E4">function **construct_data**</font>
() -> None
实际数据的构建方法,默认会在self.set_up中被调用,包括TRAIN_DATA、EVAL_DATA、TEST_DATA。将实例化的结果写入self.datas中。
<br>
### <font color="#0FB0E4">function **construct_hook**</font>
() -> None
实际Hook的构建方法,默认会在self.set_up_pre中被调用,包括TRAIN_HOOKS、EVAL_HOOKS、TEST_HOOKS。将实例化的结果写入self.hooks_dict中。
<br>
### <font color="#0FB0E4">function **construct_model**</font>
() -> None
实际Hook的构建方法,默认会在self.set_up中被调用,将实例化的结果作为self.model。
<br>
### <font color="#0FB0E4">function **model_to_device**</font>
() -> None
实际Metrics的构建方法,默认会在self.set_up中被调用,将实例化的结果写入self.metrics。
<br>
### <font color="#0FB0E4">function **model_to_device**</font>
(tg_model_ins=None) -> None or MODELS
模型的配置方法,包括模型分片等分布式配置,默认会在self.set_up中被调用。
**Parameters**
- **tg_model_ins** —— 待配置的model,如果为None,默认使用self.model。
**Returns**
- **tg_model_ins** —— 配置好的model。如果tg_model_ins为None,则无返回值。
<br>
### <font color="#0FB0E4">function **init_opti**</font>
() -> None
优化器的配置方法,默认会在self.set_up中被调用。将实例化的optimizer和lr_scheduler分别作为self.optimizer和self.lr_scheduler。
<br>
### <font color="#0FB0E4">function **solve**</font>
(epoch = None, every_epoch = False) -> None
执行实际的训练、验证或者测试操作,执行self.solve_train、self.solve_eval、self.solve_test等。
并且在执行前后分别调用self.before_solve、self.after_solve来进行Hook的记录。
**Parameters**
- **epoch** —— 设定epoch数量。
- **every_epoch** —— 与self.solve_train、self.solve_eval、self.solve_test的实现方式及Data的配置有关,标记是否每个epoch都需要重新调用一遍。
以self.solve_train为例,如果实现方式是调用一次执行一个epoch,则every_epoch应为True;如果调用一次调用会执行到所有epoch都结束,则应为False。
<br>
### <font color="#0FB0E4">function **solve_train**</font>
() -> None
调用self.run_train,执行train。
并且在执行前后分别调用self.before_epoch、self.after_epoch来进行Hook的记录。
<br>
### <font color="#0FB0E4">function **solve_eval**</font>
() -> None
调用self.run_eval,执行eval。
并且在执行前后分别调用self.before_epoch、self.after_epoch来进行Hook的记录。
<br>
### <font color="#0FB0E4">function **solve_test**</font>
() -> None
调用self.run_test,执行test。
并且在执行前后分别调用self.before_epoch、self.after_epoch来进行Hook的记录。
<br>
### <font color="#0FB0E4">function **before_solve**</font>
() -> None
在实际执行run_xxx之前,进行Hook的记录。
<br>
### <font color="#0FB0E4">function **after_solve**</font>
() -> None
在执行run_xxx之后,再次进行Hook的记录。
<br>
### <font color="#0FB0E4">function **run_train**</font>
() -> None
循环调用self.run_step_train,执行一个epoch或者所有epoch的训练过程。
并且在循环开始及结束后分别调用self.before_all_iter、self.after_all_iter来进行Hook的记录。
并且在每次循环调用self.run_step_train前后,分别调用self.before_iter、self.after_iter来进行Hook的记录。
<br>
### <font color="#0FB0E4">function **run_eval**</font>
() -> None
循环调用self.run_step_eval,执行一个epoch或者所有epoch的验证过程。
并且在循环开始及结束后分别调用self.before_all_iter、self.after_all_iter来进行Hook的记录。
并且在每次循环调用self.run_step_eval前后,分别调用self.before_iter、self.after_iter来进行Hook的记录。
<br>
### <font color="#0FB0E4">function **run_test**</font>
() -> None
循环调用self.run_step_test,执行一个epoch或者所有epoch的验证过程。
并且在循环开始及结束后分别调用self.before_all_iter、self.after_all_iter来进行Hook的记录。
并且在每次循环调用self.run_step_test前后,分别调用self.before_iter、self.after_iter来进行Hook的记录。
<br>
### <font color="#0FB0E4">function **run_step_train**</font>
(batch_data, batch_idx = 0, step = None, rank = None) -> None
执行一个batch的模型推理。
<br>
### <font color="#0FB0E4">function **run_step_eval**</font>
(batch_data, batch_idx = 0, step = None, rank = None) -> None
执行一个batch的模型推理。
<br>
### <font color="#0FB0E4">function **run_step_test**</font>
(batch_data, batch_idx = 0, step = None, rank = None) -> None
执行一个batch的模型推理。
<br>
### <font color="#0FB0E4">function **register_flops**</font>
(Dict data, keys = []) -> None
使用fvcore进行flops计算,结果保存在self._model_flops中。
**Parameters**
- **data** —— 输入模型的data,格式为key-value结构,value为Tensor或者List,默认只取batch维度的第一个元素来保证batchsize=1。
- **keys** —— 指定使用keys中的元素所对应的value作为模型输入。如果keys为空,则去data中所有的value。
<br>
### <font color="#0FB0E4">function **before_epoch**</font>
() -> None
在每个epoch开始前执行。run_xxx前执行。
<br>
### <font color="#0FB0E4">function **before_all_iter**</font>
() -> None
在每个epoch开始前执行。循环调用run_step_xxx的循环前执行。
<br>
### <font color="#0FB0E4">function **before_iter**</font>
() -> None
在每个step开始前执行。run_step_xxx前执行。
<br>
### <font color="#0FB0E4">function **after_epoch**</font>
() -> None
在每个epoch开始后执行。run_xxx后执行。
<br>
### <font color="#0FB0E4">function **after_all_iter**</font>
() -> None
在每个epoch开始后执行。循环调用run_step_xxx的循环后执行。
<br>
### <font color="#0FB0E4">function **after_iter**</font>
() -> None
在每个step开始后执行。run_step_xxx后执行。
<br>
### <font color="#0FB0E4">function **collect_log_vars**</font>
() -> OrderedDict
获取需要在log中保存的变量。
**Returns**
- **ret** —— 返回需要的变量。
<br>
# Hooks
## 总览
在Solver执行过程中,需要打印日志、记录Tensorboard、梯度计算和更新、保存中间模型参数、保存测试结果等,这些都需要Hook去执行。
<hr/>
## 基础用法
新建Hook的方法:
```python
from scepter.modules.solver.hooks.hook import Hook
from scepter.modules.solver.hooks.registry import HOOKS
@HOOKS.register_class()
class XxxHook(Hook):
def __init__(self, cfg, logger=None):
super(XxxHook, self).__init__(cfg, logger=logger)
```
<hr/>
## **scepter.modules.solvers.hooks.Hook**
定义了一个标准的Hook类的基类,定义了详细的成员函数列表。继承自该类的子类均需要在这些成员函数中挑选部分进行实现。
成员函数包括:
### <font color="#0FB0E4">function **__init__**</font>
(cfg: *scepter.modules.utils.config.Config*, logger = None) -> None
初始化logger。
### <font color="#0FB0E4">function **before_solve**</font>
(solver) -> None
开始solve之前执行。
### <font color="#0FB0E4">function **after_solve**</font>
(solver) -> None
结束solve之后执行。
### <font color="#0FB0E4">function **before_epoch**</font>
(solver) -> None
每个epoch之前执行。
### <font color="#0FB0E4">function **after_epoch**</font>
(solver) -> None
每个epoch之后执行。
### <font color="#0FB0E4">function **before_all_iter**</font>
(solver) -> None
迭代开始之前执行。
### <font color="#0FB0E4">function **after_all_iter**</font>
(solver) -> None
迭代结束之后执行。
### <font color="#0FB0E4">function **before_iter**</font>
(solver) -> None
每个step之前执行。
### <font color="#0FB0E4">function **after_iter**</font>
(solver) -> None
每个step之后执行。
## **scepter.modules.solver.hooks.CheckpointHook**
在solve开始之前,加载checkpoint。加载模型的路径来自Solver的RESUME_FROM参数。依赖于Solver中实现的load_checkpoint成员函数。
每个epoch结束之后,保存checkpoint。
**Configs**
- **PRIORITY** —— (int)默认为_DEFAULT_CHECKPOINT_PRIORITY=300
- **INTERVAL** —— (int)保存checkpoint的epoch间隔,默认为1
- **SAVE_NAME_PREFIX** —— (str)保存checkpoint的前缀名,默认为'ldm_step'
- **SAVE_LAST** —— (bool)是否保存最后iter的checkpoint,默认为False,作用于after_iter中。
- **SAVE_BEST** —— (bool)是否保存最好的checkpoint,默认为True,作用于after_epoch中。需要同时设置SAVE_BEST_BY,否则退回默认False。
- **SAVE_BEST_BY** —— (str)判断最好的指标,默认越大越好
## **scepter.modules.solver.hooks.BackwardHook**
在每步迭代之后执行的内容。包括loss的反传,optimizer的步数配置等等。
**Configs**
- **PRIORITY** —— (int)_DEFAULT_BACKWARD_PRIORITY=0
- **GRADIENT_CLIP** —— (int)torch.nn.utils.clip_grad_norm_中max_norm参数,默认为-1。小于等于0时不生效。
- **ACCUMULATE_STEP** —— (int)用于设置梯度累计的步数
- **EMPTY_CACHE_STEP** —— (int)torch.cuda.empty_cache每多少步清除一下memory,默认为-1。小于等于0时不生效。
-
## **scepter.modules.solver.hooks.LogHook**
日志Hook。
**Configs**
- **PRIORITY** —— (int)__DEFAULT_LOG_PRIORITY=100
- **SHOW_GPU_MEM** —— (bool)判断是否打印内存使用情况
- **LOG_INTERVAL** —— (int)打印log的步数间隔,默认为10。小于等于0时不生效。
## **scepter.modules.solver.hooks.TensorboardLogHook**
Tensorboard日志Hook。
**Configs**
- **PRIORITY** —— (int)__DEFAULT_LOG_PRIORITY=100
- **LOG_DIR** —— (str)存储Tensorboard log的路径。
- **LOG_INTERVAL** —— (int)打印log的步数间隔,默认为1000。
## **scepter.modules.solver.hooks.LrHook**
学习率变化Hook。
**Configs**
- **PRIORITY** —— (int)_DEFAULT_LR_PRIORITY=200
- **WARMUP_FUNC** —— (str)warmup的方式:仅支持"linear",默认为"linear"。
- **WARMUP_EPOCHS** —— (int)warmup epoch数,默认为1。
- **WARMUP_START_LR** —— (float)warmup初始学习率,默认为0.0001。
- **SET_BY_EPOCH** —— (bool)是否每个epoch设置一次学习率,默认为True。False则每个step设置一次。
## **scepter.modules.solver.hooks.DistSamplerHook**
每个epoch开始之前,采样一个epoch的数据。
**Configs**
- **PRIORITY** —— (int)__DEFAULT_SAMPLER_PRIORITY=400
## **scepter.modules.solver.hooks.ProbeDataHook**
用于打印probe存储的train/eval中间(可视化)结果。
**Configs**
- **PRIORITY** —— (int)_DEFAULT_LR_PRIORITY=200
- **PROB_INTERVAL** —— (int)打印probe的步数间隔,默认为1000。
## **scepter.modules.solver.hooks.SafetensorsHook**
用于存储.safetensors格式的模型文件。
**Configs**
- **PRIORITY** —— (int)_DEFAULT_LR_PRIORITY=200
- **INTERVAL** —— (int)存储的步数间隔,默认为1000。
- **SAVE_NAME_PREFIX** —— (str)保存文件的前缀名。