# 训练配置参数

本工具模型训练基于[YOLOX](https://github.com//Megvii-BaseDetection/YOLOX.git)，模型量化基于[MQbench](https://github.com/ModelTC/MQBench.git), 因此训练参数分为两部分

## 模型训练

### 训练配置

```python
    # --------------  training config --------------------- #
    # epoch number used for warmup
    self.warmup_epochs = 5
    # max training epoch
    self.max_epoch = 300
    # minimum learning rate during warmup
    self.warmup_lr = 0
    self.min_lr_ratio = 0.05
    # learning rate for one image. During training, lr will multiply batchsize.
    self.basic_lr_per_img = 0.01 / 64.0
    # name of LRScheduler
    self.scheduler = "yoloxwarmcos"
    # last #epoch to close augmention like mosaic
    self.no_aug_epochs = 15
    # apply EMA during training
    # !!! 注意： QAT训练暂不支持ema
    self.ema = True

    # weight decay of optimizer
    self.weight_decay = 5e-4
    # momentum of optimizer
    self.momentum = 0.9
    # log period in iter, for example,
    # if set to 1, user could see log every iteration.
    self.print_interval = 10
    # eval period in epoch, for example,
    # if set to 1, model will be evaluate after every epoch.
    self.eval_interval = 10
    # save history checkpoint or not.
    # If set to False, yolox will only save latest and best ckpt.
    self.save_history_ckpt = True
    # name of experiment
    self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0]
```

### 数据处理与增强

```python
    # ---------------- dataloader config ---------------- #
    # set worker to 4 for shorter dataloader init time
    # If your training process cost many memory, reduce this value.
    self.data_num_workers = 4
    self.input_size = (640, 640)  # (height, width)
    # Actual multiscale ranges: [640 - 5 * 32, 640 + 5 * 32].
    # To disable multiscale training, set the value to 0.
    self.multiscale_range = 5
    # You can uncomment this line to specify a multiscale range
    # self.random_size = (14, 26)


    # --------------- transform config ----------------- #
    # prob of applying mosaic aug
    self.mosaic_prob = 1.0
    # prob of applying mixup aug
    self.mixup_prob = 1.0
    # prob of applying hsv aug
    self.hsv_prob = 1.0
    # prob of applying flip aug
    self.flip_prob = 0.5
    # rotation angle range, for example, if set to 2, the true range is (-2, 2)
    self.degrees = 10.0
    # translate range, for example, if set to 0.1, the true range is (-0.1, 0.1)
    self.translate = 0.1
    self.mosaic_scale = (0.1, 2)
    # apply mixup aug or not
    self.enable_mixup = True
    self.mixup_scale = (0.5, 1.5)
    # shear angle range, for example, if set to 2, the true range is (-2, 2)
    self.shear = 2.0
```

## 模型量化

建议优先使用预置量化设置进行训练, 默认配置已包含如下设置
```python
    # defined in configs/sa6921_vnne_3classes_voc_quant_a8w4_300e_trainset.py
    # 基础量化配置， 权重 4bit perchannel 对称量化， 激活值 8bit pertensor 非对称量化
    "quant_config": {
        "deploy_backend": BackendType.AOFullA8W4,
    },
    # 优化配置
    # input层：对于输入uint8数据，预处理为(x - 0) / 255, 使用固定量化器不对输入做量化， 固定scale为1/255
    x_quantizer = FixedFakeQuantize.with_args(observer=PseudoObserver, 
                                            **QuantizeScheme(
                                                symmetry=True, 
                                                per_channel=False, 
                                                pot_scale=False, 
                                                half_range=True,
                                                bit=8).to_observer_params())
    # obj、cls等输出层：由于sigmoid映射x~[-8, 8]时， y~[0.0003, 0.9997], 因此采用固定量化值域范围的量化方式
    PseudoObserver_params = QuantizeScheme(symmetry=True, 
                                            per_channel=False,  
                                            pot_scale=False, 
                                            half_range=False,
                                            bit=8).to_observer_params()
    PseudoObserver_params.update(
        {
            'limit_max': 8,
            'limit_min':-8,
        }
    )
    fixed_quantizer = PseudoFakeQuantize.with_args(observer=PseudoObserver, 
                                                **PseudoObserver_params)
    "custom_quant_config": {
        "x_post_act_fake_quantizer": x_quantizer,
        "head0_layer_8_obj_conv0_conv0_post_act_fake_quantizer": fixed_quantizer,
        "head0_layer_8_cls_conv0_conv0_post_act_fake_quantizer": fixed_quantizer,
        "head0_layer_16_obj_conv0_conv0_post_act_fake_quantizer": fixed_quantizer,
        "head0_layer_16_cls_conv0_conv0_post_act_fake_quantizer": fixed_quantizer,
        "head0_layer_32_obj_conv0_conv0_post_act_fake_quantizer": fixed_quantizer,
        "head0_layer_32_cls_conv0_conv0_post_act_fake_quantizer": fixed_quantizer,
        },
```


### 量化配置支持如下参数调整

```python
# defined in mediatools/prepare_by_platform.py

    ParamsTable = {
        BackendType.AOFullA8W4: dict(qtype='affine',  
                                    # weight 量化配置：
                                    # symmetry: 是否对称量化
                                    # perchannel: 是否perchannel量化
                                    # pot_scale： indecate wheather scale is power of two.
                                    # bit: 量化位宽
                                    w_qscheme=QuantizeScheme(symmetry=True, per_channel=True, pot_scale=False, bit=4),
                                    # activation 量化配置：
                                    # symmetry: 是否对称量化
                                    # perchannel: 是否perchannel量化
                                    # pot_scale： indecate wheather scale is power of two.
                                    # bit: 量化位宽
                                    # half_range: 特殊设置，针对输入层Uint8数据类型开启
                                    a_qscheme=QuantizeScheme(symmetry=False, per_channel=False, pot_scale=False, bit=8,
                                                            half_range=False),
                                    # 权重量化器： 推荐默认LearnableFakeQuantize（LSQ）
                                    default_weight_quantize=LearnableFakeQuantize,
                                    # 激活值量化器： 推荐默认LearnableFakeQuantize（LSQ）
                                    default_act_quantize=LearnableFakeQuantize,
                                    # observer： 用于统计数值范围
                                    # MinMaxObserver: 最大最小统计
                                    # EMAMinMaxObserver： EMA平滑的最大最小统计
                                    # PseudoObserver：不统计实际范围，根据预设值输出统计值
                                    default_weight_observer=MinMaxObserver,
                                    default_act_observer=EMAMinMaxObserver),
    }

```

### 量化训练参数

```python
    # defined in configs/sa6921_vnne_3classes_voc_quant_a8w4_300e_trainset.py
    # --------------- QAT config ----------------- #
    # QAT warmup epoch, keep float training epoch
    self.qat_warmup_epoch = 0
    # number of epochs for calibration model, after qat_warmup and qat_calib, QAT starts
    self.qat_clib_epoch = 2
```