Repository: PaddlePaddle/PaddleSeg

Issue:
[Bug] 模型量化bug
使用paddleseg进行模型量化时，发现一个bug，代码链接：https://github.com/PaddlePaddle/PaddleSeg/blob/0a7f65405a2153162d46f4065566d5e6f082879b/slim/quant/qat_train.py#L190
，根据paddleslim（2.0.0）文档，量化模型是inplace的，没有返回值，quant_model = None，所以paddleseg量化时会报错“NoneType object has no attribution 'train'”。
paddleslim(2.0.0)文档：
https://paddleslim.readthedocs.io/zh_CN/develop/api_cn/dygraph/quanter/qat.html
paddleslim（2.0.0）源码：https://github.com/PaddlePaddle/PaddleSlim/blob/c2cbef1afaeca836c7551427ebd31c6889b56f8f/paddleslim/dygraph/quant/quanter.py#L217

修改：
```
quantizer.quantize(model) 
quant_model = model
```


env:
aistudio 至尊gpu版本

PaddleSeg version:  release/2.4
PaddlePaddle version: PaddlePaddle 2.2.2
Operation system: Linux




Discussion:

Resolving patch:
diff --git a/slim/quant/qat_export.py b/slim/quant/qat_export.py
--- a/slim/quant/qat_export.py
+++ b/slim/quant/qat_export.py
@@ -30,27 +30,25 @@
 
 from paddleslim import QAT
 
+
 def parse_args():
     parser = argparse.ArgumentParser(description='Model export.')
-    parser.add_argument(
-        "--config",
-        dest="cfg",
-        help="The config file.",
-        default=None,
-        type=str,
-        required=True)
-    parser.add_argument(
-        '--save_dir',
-        dest='save_dir',
-        help='The directory for saving the exported model',
-        type=str,
-        default='./output')
-    parser.add_argument(
-        '--model_path',
-        dest='model_path',
-        help='The path of model for export',
-        type=str,
-        default=None)
+    parser.add_argument("--config",
+                        dest="cfg",
+                        help="The config file.",
+                        default=None,
+                        type=str,
+                        required=True)
+    parser.add_argument('--save_dir',
+                        dest='save_dir',
+                        help='The directory for saving the exported model',
+                        type=str,
+                        default='./output')
+    parser.add_argument('--model_path',
+                        dest='model_path',
+                        help='The path of model for export',
+                        type=str,
+                        default=None)
     parser.add_argument(
         '--without_argmax',
         dest='without_argmax',
@@ -72,15 +70,15 @@ def main(args):
 
     skip_quant(net)
     quantizer = QAT(config=quant_config)
-    quant_net = quantizer.quantize(net)
+    quantizer.quantize(net)
     logger.info('Quantize the model successfully')
 
     if args.model_path:
-        utils.load_entire_model(quant_net, args.model_path)
+        utils.load_entire_model(net, args.model_path)
         logger.info('Loaded trained params of model successfully')
 
     if not args.without_argmax or args.with_softmax:
-        new_net = SavedSegmentationNet(quant_net, args.without_argmax,
+        new_net = SavedSegmentationNet(net, args.without_argmax,
                                        args.with_softmax)
     else:
         new_net = net
diff --git a/slim/quant/qat_train.py b/slim/quant/qat_train.py
--- a/slim/quant/qat_train.py
+++ b/slim/quant/qat_train.py
@@ -37,85 +37,77 @@
 
 def parse_args():
     parser = argparse.ArgumentParser(description='Model training')
-    parser.add_argument(
-        "--config", dest="cfg", help="The config file.", default=None, type=str)
-    parser.add_argument(
-        '--iters',
-        dest='iters',
-        help='iters for training',
-        type=int,
-        default=None)
-    parser.add_argument(
-        '--batch_size',
-        dest='batch_size',
-        help='Mini batch size of one gpu or cpu',
-        type=int,
-        default=None)
-    parser.add_argument(
-        '--learning_rate',
-        dest='learning_rate',
-        help='Learning rate',
-        type=float,
-        default=None)
+    parser.add_argument("--config",
+                        dest="cfg",
+                        help="The config file.",
+                        default=None,
+                        type=str)
+    parser.add_argument('--iters',
+                        dest='iters',
+                        help='iters for training',
+                        type=int,
+                        default=None)
+    parser.add_argument('--batch_size',
+                        dest='batch_size',
+                        help='Mini batch size of one gpu or cpu',
+                        type=int,
+                        default=None)
+    parser.add_argument('--learning_rate',
+                        dest='learning_rate',
+                        help='Learning rate',
+                        type=float,
+                        default=None)
     parser.add_argument(
         '--save_interval',
         dest='save_interval',
         help='How many iters to save a model snapshot once during training.',
         type=int,
         default=1000)
-    parser.add_argument(
-        '--resume_model',
-        dest='resume_model',
-        help='The path of resume model',
-        type=str,
-        default=None)
-    parser.add_argument(
-        '--save_dir',
-        dest='save_dir',
-        help='The directory for saving the model snapshot',
-        type=str,
-        default='./output')
-    parser.add_argument(
-        '--keep_checkpoint_max',
-        dest='keep_checkpoint_max',
-        help='Maximum number of checkpoints to save',
-        type=int,
-        default=5)
-    parser.add_argument(
-        '--num_workers',
-        dest='num_workers',
-        help='Num workers for data loader',
-        type=int,
-        default=0)
-    parser.add_argument(
-        '--do_eval',
-        dest='do_eval',
-        help='Eval while training',
-        action='store_true')
-    parser.add_argument(
-        '--log_iters',
-        dest='log_iters',
-        help='Display logging information at every log_iters',
-        default=10,
-        type=int)
+    parser.add_argument('--resume_model',
+                        dest='resume_model',
+                        help='The path of resume model',
+                        type=str,
+                        default=None)
+    parser.add_argument('--save_dir',
+                        dest='save_dir',
+                        help='The directory for saving the model snapshot',
+                        type=str,
+                        default='./output')
+    parser.add_argument('--keep_checkpoint_max',
+                        dest='keep_checkpoint_max',
+                        help='Maximum number of checkpoints to save',
+                        type=int,
+                        default=5)
+    parser.add_argument('--num_workers',
+                        dest='num_workers',
+                        help='Num workers for data loader',
+                        type=int,
+                        default=0)
+    parser.add_argument('--do_eval',
+                        dest='do_eval',
+                        help='Eval while training',
+                        action='store_true')
+    parser.add_argument('--log_iters',
+                        dest='log_iters',
+                        help='Display logging information at every log_iters',
+                        default=10,
+                        type=int)
     parser.add_argument(
         '--use_vdl',
         dest='use_vdl',
         help='Whether to record the data to VisualDL during training',
         action='store_true')
-    parser.add_argument(
-        '--seed',
-        dest='seed',
-        help='Set the random seed during training.',
-        default=None,
-        type=int)
-
-    parser.add_argument(
-        '--model_path',
-        dest='model_path',
-        help='The path of pretrained model',
-        type=str,
-        default=None)
+    parser.add_argument('--seed',
+                        dest='seed',
+                        help='Set the random seed during training.',
+                        default=None,
+                        type=int)
+
+    parser.add_argument('--model_path',
+                        dest='model_path',
+                        help='The path of pretrained model',
+                        type=str,
+                        default=None)
 
     return parser.parse_args()
 
@@ -156,11 +148,10 @@ def main(args):
     if not args.cfg:
         raise RuntimeError('No configuration file specified.')
 
-    cfg = Config(
-        args.cfg,
-        learning_rate=args.learning_rate,
-        iters=args.iters,
-        batch_size=args.batch_size)
+    cfg = Config(args.cfg,
+                 learning_rate=args.learning_rate,
+                 iters=args.iters,
+                 batch_size=args.batch_size)
 
     train_dataset = cfg.train_dataset
     if train_dataset is None:
@@ -187,24 +178,23 @@ def main(args):
 
     skip_quant(model)
     quantizer = QAT(config=quant_config)
-    quant_model = quantizer.quantize(model)
+    quantizer.quantize(model)
     logger.info('Quantize the model successfully')
 
-    train(
-        quant_model,
-        train_dataset,
-        val_dataset=val_dataset,
-        optimizer=cfg.optimizer,
-        save_dir=args.save_dir,
-        iters=cfg.iters,
-        batch_size=cfg.batch_size,
-        resume_model=None,
-        save_interval=args.save_interval,
-        log_iters=args.log_iters,
-        num_workers=args.num_workers,
-        use_vdl=args.use_vdl,
-        losses=losses,
-        keep_checkpoint_max=args.keep_checkpoint_max)
+    train(model,
+          train_dataset,
+          val_dataset=val_dataset,
+          optimizer=cfg.optimizer,
+          save_dir=args.save_dir,
+          iters=cfg.iters,
+          batch_size=cfg.batch_size,
+          resume_model=None,
+          save_interval=args.save_interval,
+          log_iters=args.log_iters,
+          num_workers=args.num_workers,
+          use_vdl=args.use_vdl,
+          losses=losses,
+          keep_checkpoint_max=args.keep_checkpoint_max)
 
 
 if __name__ == '__main__':
diff --git a/slim/quant/qat_val.py b/slim/quant/qat_val.py
--- a/slim/quant/qat_val.py
+++ b/slim/quant/qat_val.py
@@ -55,20 +55,21 @@ def parse_args():
     parser = argparse.ArgumentParser(description='Model evaluation')
 
     # params of evaluate
-    parser.add_argument(
-        "--config", dest="cfg", help="The config file.", default=None, type=str)
-    parser.add_argument(
-        '--model_path',
-        dest='model_path',
-        help='The path of model for evaluation',
-        type=str,
-        default=None)
-    parser.add_argument(
-        '--num_workers',
-        dest='num_workers',
-        help='Num workers for data loader',
-        type=int,
-        default=0)
+    parser.add_argument("--config",
+                        dest="cfg",
+                        help="The config file.",
+                        default=None,
+                        type=str)
+    parser.add_argument('--model_path',
+                        dest='model_path',
+                        help='The path of model for evaluation',
+                        type=str,
+                        default=None)
+    parser.add_argument('--num_workers',
+                        dest='num_workers',
+                        help='Num workers for data loader',
+                        type=int,
+                        default=0)
 
     # augment for evaluation
     parser.add_argument(
@@ -76,30 +77,26 @@ def parse_args():
         dest='aug_eval',
         help='Whether to use mulit-scales and flip augment for evaluation',
         action='store_true')
-    parser.add_argument(
-        '--scales',
-        dest='scales',
-        nargs='+',
-        help='Scales for augment',
-        type=float,
-        default=1.0)
-    parser.add_argument(
-        '--flip_horizontal',
-        dest='flip_horizontal',
-        help='Whether to use flip horizontally augment',
-        action='store_true')
-    parser.add_argument(
-        '--flip_vertical',
-        dest='flip_vertical',
-        help='Whether to use flip vertically augment',
-        action='store_true')
+    parser.add_argument('--scales',
+                        dest='scales',
+                        nargs='+',
+                        help='Scales for augment',
+                        type=float,
+                        default=1.0)
+    parser.add_argument('--flip_horizontal',
+                        dest='flip_horizontal',
+                        help='Whether to use flip horizontally augment',
+                        action='store_true')
+    parser.add_argument('--flip_vertical',
+                        dest='flip_vertical',
+                        help='Whether to use flip vertically augment',
+                        action='store_true')
 
     # sliding window evaluation
-    parser.add_argument(
-        '--is_slide',
-        dest='is_slide',
-        help='Whether to evaluate by sliding window',
-        action='store_true')
+    parser.add_argument('--is_slide',
+                        dest='is_slide',
+                        help='Whether to evaluate by sliding window',
+                        action='store_true')
     parser.add_argument(
         '--crop_size',
         dest='crop_size',
@@ -167,18 +164,17 @@ def main(args):
 
     skip_quant(model)
     quantizer = QAT(config=quant_config)
-    quant_model = quantizer.quantize(model)
+    quantizer.quantize(model)
     logger.info('Quantize the model successfully')
 
     if args.model_path:
-        utils.load_entire_model(quant_model, args.model_path)
+        utils.load_entire_model(model, args.model_path)
         logger.info('Loaded trained params of model successfully')
 
     test_config = get_test_config(cfg, args)
     config_check(cfg, val_dataset=val_dataset)
 
-    evaluate(
-        quant_model, val_dataset, num_workers=args.num_workers, **test_config)
+    evaluate(model, val_dataset, num_workers=args.num_workers, **test_config)
 
 
 if __name__ == '__main__':


Test patch: