From 765f15bc60cc293ced58270455bbe34d3d52dbef Mon Sep 17 00:00:00 2001 From: lilithzhou <80816848+lilith-zy@users.noreply.github.com> Date: Wed, 18 Aug 2021 17:54:37 +0800 Subject: [PATCH 01/35] Update WeChat QR Code (#1154) * Update wx_group.png * Update wx_group.png --- docs/images/wx_group.png | Bin 68003 -> 204411 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/wx_group.png b/docs/images/wx_group.png index d73a7e9254f3bedfba5c6274028cf0e848f94c9c..60259dd4e0a11035b02266b3f67b35748518c5c0 100644 GIT binary patch literal 204411 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�~N-&&3yX7tuD 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 V!{dAb;QtvO=L^EmKf~j+{tE~bBF+E+ literal 68003 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 P{)v%5w1bxa{PBMP{#akc From fb4166419ae48e942be2b43bb042579a444de299 Mon Sep 17 00:00:00 2001 From: lyuwenyu Date: Thu, 19 Aug 2021 11:02:30 +0800 Subject: [PATCH 02/35] using ppcls pretrained --- hubconf.py | 151 +++++++++++++++++------------------------------------ 1 file changed, 47 insertions(+), 104 deletions(-) diff --git a/hubconf.py b/hubconf.py index eb114bc20..d615a905d 100644 --- a/hubconf.py +++ b/hubconf.py @@ -63,9 +63,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `AlexNet` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.AlexNet(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'AlexNet') return model @@ -80,9 +79,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `VGG11` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.VGG11(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'VGG11') return model @@ -97,9 +95,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `VGG13` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.VGG13(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'VGG13') return model @@ -114,9 +111,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `VGG16` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.VGG16(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'VGG16') return model @@ -131,9 +127,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `VGG19` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.VGG19(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'VGG19') return model @@ -149,9 +144,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNet18` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNet18(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNet18') return model @@ -167,9 +161,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNet34` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNet34(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNet34') return model @@ -185,9 +178,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNet50` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNet50(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNet50') return model @@ -203,9 +195,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNet101` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNet101(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNet101') return model @@ -221,9 +212,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNet152` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNet152(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNet152') return model @@ -237,9 +227,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `SqueezeNet1_0` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.SqueezeNet1_0(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'SqueezeNet1_0') return model @@ -253,9 +242,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `SqueezeNet1_1` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.SqueezeNet1_1(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'SqueezeNet1_1') return model @@ -271,9 +259,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `DenseNet121` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.DenseNet121(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'DenseNet121') return model @@ -289,9 +276,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `DenseNet161` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.DenseNet161(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'DenseNet161') return model @@ -307,9 +293,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `DenseNet169` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.DenseNet169(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'DenseNet169') return model @@ -325,9 +310,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `DenseNet201` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.DenseNet201(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'DenseNet201') return model @@ -343,9 +327,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `DenseNet264` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.DenseNet264(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'DenseNet264') return model @@ -359,9 +342,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `InceptionV3` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.InceptionV3(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'InceptionV3') return model @@ -375,9 +357,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `InceptionV4` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.InceptionV4(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'InceptionV4') return model @@ -391,9 +372,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `GoogLeNet` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.GoogLeNet(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'GoogLeNet') return model @@ -407,9 +387,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ShuffleNetV2_x0_25` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ShuffleNetV2_x0_25(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ShuffleNetV2_x0_25') return model @@ -423,9 +402,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV1` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV1(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV1') return model @@ -439,9 +417,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV1_x0_25` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV1_x0_25(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV1_x0_25') return model @@ -455,9 +432,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV1_x0_5` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV1_x0_5(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV1_x0_5') return model @@ -471,9 +447,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV1_x0_75` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV1_x0_75(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV1_x0_75') return model @@ -487,9 +462,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV2_x0_25` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV2_x0_25(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV2_x0_25') return model @@ -503,9 +477,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV2_x0_5` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV2_x0_5(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV2_x0_5') return model @@ -519,9 +492,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV2_x0_75` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV2_x0_75(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV2_x0_75') return model @@ -535,9 +507,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV2_x1_5` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV2_x1_5(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV2_x1_5') return model @@ -551,9 +522,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV2_x2_0` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV2_x2_0(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'MobileNetV2_x2_0') return model @@ -567,10 +537,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_large_x0_35` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_large_x0_35(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_large_x0_35') return model @@ -584,10 +552,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_large_x0_5` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_large_x0_5(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_large_x0_5') return model @@ -601,10 +567,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_large_x0_75` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_large_x0_75(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_large_x0_75') return model @@ -618,10 +582,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_large_x1_0` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_large_x1_0(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_large_x1_0') return model @@ -635,10 +597,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_large_x1_25` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_large_x1_25(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_large_x1_25') return model @@ -652,10 +612,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_small_x0_35` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_small_x0_35(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_small_x0_35') return model @@ -669,10 +627,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_small_x0_5` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_small_x0_5(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_small_x0_5') return model @@ -686,10 +642,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_small_x0_75` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_small_x0_75(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_small_x0_75') return model @@ -703,10 +657,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_small_x1_0` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_small_x1_0(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_small_x1_0') return model @@ -720,10 +672,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `MobileNetV3_small_x1_25` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.MobileNetV3_small_x1_25(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, - 'MobileNetV3_small_x1_25') return model @@ -737,9 +687,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNeXt101_32x4d` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNeXt101_32x4d(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNeXt101_32x4d') return model @@ -753,9 +702,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNeXt101_64x4d` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNeXt101_64x4d(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNeXt101_64x4d') return model @@ -769,9 +717,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNeXt152_32x4d` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNeXt152_32x4d(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNeXt152_32x4d') return model @@ -785,9 +732,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNeXt152_64x4d` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNeXt152_64x4d(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNeXt152_64x4d') return model @@ -801,9 +747,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNeXt50_32x4d` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNeXt50_32x4d(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNeXt50_32x4d') return model @@ -817,9 +762,8 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNeXt50_64x4d` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.ResNeXt50_64x4d(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'ResNeXt50_64x4d') return model @@ -833,8 +777,7 @@ with _SysPathG( Returns: model: nn.Layer. Specific `ResNeXt50_64x4d` model depends on args. """ + kwargs.update({'pretrained': pretrained}) model = backbone.DarkNet53(**kwargs) - if pretrained: - model = _load_pretrained_parameters(model, 'DarkNet53') return model From d21ebb85d01032ece7ec7d89de04a170a14ab0a8 Mon Sep 17 00:00:00 2001 From: cuicheng01 Date: Fri, 20 Aug 2021 09:53:18 +0000 Subject: [PATCH 03/35] fix random_erasing bug --- ppcls/data/preprocess/ops/random_erasing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ppcls/data/preprocess/ops/random_erasing.py b/ppcls/data/preprocess/ops/random_erasing.py index d96ceda6e..b395d5205 100644 --- a/ppcls/data/preprocess/ops/random_erasing.py +++ b/ppcls/data/preprocess/ops/random_erasing.py @@ -42,9 +42,9 @@ class RandomErasing(object): h = int(round(math.sqrt(target_area * aspect_ratio))) w = int(round(math.sqrt(target_area / aspect_ratio))) - if w < img.shape[2] and h < img.shape[1]: - x1 = random.randint(0, img.shape[1] - h) - y1 = random.randint(0, img.shape[2] - w) + if w < img.shape[1] and h < img.shape[0]: + x1 = random.randint(0, img.shape[0] - h) + y1 = random.randint(0, img.shape[1] - w) if img.shape[0] == 3: img[x1:x1 + h, y1:y1 + w, 0] = self.mean[0] img[x1:x1 + h, y1:y1 + w, 1] = self.mean[1] From fdff2de329373d91ab86cb0a6073d4c69a27c90e Mon Sep 17 00:00:00 2001 From: cuicheng01 <45199522+cuicheng01@users.noreply.github.com> Date: Sat, 21 Aug 2021 17:49:49 +0800 Subject: [PATCH 04/35] fix random_erasing bug (#1160) --- ppcls/data/preprocess/ops/random_erasing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ppcls/data/preprocess/ops/random_erasing.py b/ppcls/data/preprocess/ops/random_erasing.py index d96ceda6e..b395d5205 100644 --- a/ppcls/data/preprocess/ops/random_erasing.py +++ b/ppcls/data/preprocess/ops/random_erasing.py @@ -42,9 +42,9 @@ class RandomErasing(object): h = int(round(math.sqrt(target_area * aspect_ratio))) w = int(round(math.sqrt(target_area / aspect_ratio))) - if w < img.shape[2] and h < img.shape[1]: - x1 = random.randint(0, img.shape[1] - h) - y1 = random.randint(0, img.shape[2] - w) + if w < img.shape[1] and h < img.shape[0]: + x1 = random.randint(0, img.shape[0] - h) + y1 = random.randint(0, img.shape[1] - w) if img.shape[0] == 3: img[x1:x1 + h, y1:y1 + w, 0] = self.mean[0] img[x1:x1 + h, y1:y1 + w, 1] = self.mean[1] From 800487e416c201a0f5f07f435d0e417b17af57e9 Mon Sep 17 00:00:00 2001 From: Tingquan Gao Date: Sat, 21 Aug 2021 17:50:09 +0800 Subject: [PATCH 05/35] fix: fix the VDL doc, test=document_fix (#1159) --- docs/en/extension/VisualDL_en.md | 17 +++++++++-------- docs/zh_CN/extension/VisualDL.md | 14 ++++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/en/extension/VisualDL_en.md b/docs/en/extension/VisualDL_en.md index cdd99581a..9ffd03e92 100644 --- a/docs/en/extension/VisualDL_en.md +++ b/docs/en/extension/VisualDL_en.md @@ -7,29 +7,30 @@ VisualDL, a visualization analysis tool of PaddlePaddle, provides a variety of c Now PaddleClas support use VisualDL to visualize the changes of learning rate, loss, accuracy in training. ### Set config and start training -You only need to set the `vdl_dir` field in train config: +You only need to set the field `Global.use_visualdl` to `True` in train config: ```yaml # config.yaml -vdl_dir: "./vdl.log" +Global: +... + use_visualdl: True +... ``` -`vdl_dir`: Specify the directory where VisualDL stores logs. - -Then normal start training: +PaddleClas will save the VisualDL logs to subdirectory `vdl/` under the output directory specified by `Global.output_dir`. And then you just need to start training normally: ```shell python3 tools/train.py -c config.yaml ``` ### Start VisualDL -After starting the training program, you can start the VisualDL service in the new terminal session: +After starting the training program, you can start the VisualDL service in a new terminal session: ```shell - visualdl --logdir ./vdl.log + visualdl --logdir ./output/vdl/ ``` -In the above command, `--logdir` specify the logs directory. VisualDL will traverse and iterate to find the subdirectories of the specified directory to visualize all the experimental results. You can also use the following parameters to set the IP and port number of the VisualDL service: +In the above command, `--logdir` specify the directory of the VisualDL logs produced in training. VisualDL will traverse and iterate to find the subdirectories of the specified directory to visualize all the experimental results. You can also use the following parameters to set the IP and port number of the VisualDL service: * `--host`:ip, default is 127.0.0.1 * `--port`:port, default is 8040 diff --git a/docs/zh_CN/extension/VisualDL.md b/docs/zh_CN/extension/VisualDL.md index d360c5b15..3c0020063 100644 --- a/docs/zh_CN/extension/VisualDL.md +++ b/docs/zh_CN/extension/VisualDL.md @@ -7,15 +7,17 @@ VisualDL是飞桨可视化分析工具,以丰富的图表呈现训练参数变 现在PaddleClas支持在训练阶段使用VisualDL查看训练过程中学习率(learning rate)、损失值(loss)以及准确率(accuracy)的变化情况。 ### 设置config文件并启动训练 -在PaddleClas中使用VisualDL,只需在训练配置文件(config文件)添加如下字段: +在PaddleClas中使用VisualDL,只需在训练配置文件(config文件)中设置字段 `Global.use_visualdl` 为 `True`: ```yaml # config.yaml -vdl_dir: "./vdl.log" +Global: +... + use_visualdl: True +... ``` -`vdl_dir` 用于指定VisualDL用于保存log信息的目录。 -然后正常启动训练即可: +PaddleClas 会将 VisualDL 的日志保存在 `Global.output_dir` 字段指定目录下的 `vdl/` 子目录下,然后正常启动训练即可: ```shell python3 tools/train.py -c config.yaml @@ -25,10 +27,10 @@ python3 tools/train.py -c config.yaml 在启动训练程序后,可以在新的终端session中启动VisualDL服务: ```shell - visualdl --logdir ./vdl.log + visualdl --logdir ./output/vdl/ ``` -上述命令中,参数`--logdir`用于指定日志目录,VisualDL将遍历并且迭代寻找指定目录的子目录,将所有实验结果进行可视化。也同样可以使用下述参数设定VisualDL服务的ip及端口号: +上述命令中,参数`--logdir`用于指定保存 VisualDL 日志的目录,VisualDL将遍历并且迭代寻找指定目录的子目录,将所有实验结果进行可视化。也同样可以使用下述参数设定VisualDL服务的ip及端口号: * `--host`:设定IP,默认为127.0.0.1 * `--port`:设定端口,默认为8040 From ebde0e13cbf0d027c485b8cc2946087d29218453 Mon Sep 17 00:00:00 2001 From: dongshuilong Date: Sun, 22 Aug 2021 15:10:23 +0000 Subject: [PATCH 06/35] refactor trainer --- ppcls/engine/core.py | 403 ++++++++++++++++ ppcls/engine/eval/__init__.py | 16 + ppcls/engine/eval/classification.py | 118 +++++ ppcls/engine/eval/retrieval.py | 160 +++++++ ppcls/engine/slim/__init__.py | 0 ppcls/engine/train/__init__.py | 15 + ppcls/engine/train/classification.py | 89 ++++ ppcls/engine/train/retrieval.py | 90 ++++ ppcls/engine/train/utils.py | 82 ++++ ppcls/engine/trainer.py | 662 --------------------------- tools/eval.py | 6 +- tools/export_model.py | 77 +--- tools/infer.py | 7 +- tools/train.py | 4 +- 14 files changed, 984 insertions(+), 745 deletions(-) create mode 100644 ppcls/engine/core.py create mode 100644 ppcls/engine/eval/__init__.py create mode 100644 ppcls/engine/eval/classification.py create mode 100644 ppcls/engine/eval/retrieval.py create mode 100644 ppcls/engine/slim/__init__.py create mode 100644 ppcls/engine/train/__init__.py create mode 100644 ppcls/engine/train/classification.py create mode 100644 ppcls/engine/train/retrieval.py create mode 100644 ppcls/engine/train/utils.py delete mode 100644 ppcls/engine/trainer.py diff --git a/ppcls/engine/core.py b/ppcls/engine/core.py new file mode 100644 index 000000000..d0e448d71 --- /dev/null +++ b/ppcls/engine/core.py @@ -0,0 +1,403 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import os +import sys +import numpy as np + +__dir__ = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.abspath(os.path.join(__dir__, '../../'))) + +import time +import platform +import datetime +import argparse +import paddle +import paddle.nn as nn +import paddle.distributed as dist +from visualdl import LogWriter + +from ppcls.utils.check import check_gpu +from ppcls.utils.misc import AverageMeter +from ppcls.utils import logger +from ppcls.utils.logger import init_logger +from ppcls.utils.config import print_config +from ppcls.data import build_dataloader +from ppcls.arch import build_model, RecModel, DistillationModel +from ppcls.arch import apply_to_static +from ppcls.loss import build_loss +from ppcls.metric import build_metrics +from ppcls.optimizer import build_optimizer +from ppcls.utils.save_load import load_dygraph_pretrain, load_dygraph_pretrain_from_url +from ppcls.utils.save_load import init_model +from ppcls.utils import save_load + +from ppcls.data.utils.get_image_list import get_image_list +from ppcls.data.postprocess import build_postprocess +from ppcls.data import create_operators +from ppcls.engine.train import classification_train, retrieval_train +from ppcls.engine.eval import classification_eval, retrieval_eval +from ppcls.arch.gears.identity_head import IdentityHead + + +class Core(object): + def __init__(self, config, mode="train"): + assert mode in ['train', 'eval', 'infer', 'export'] + self.mode = mode + self.config = config + self.eval_mode = self.config["Global"].get("eval_mode", + "classification") + + # init logger + self.output_dir = self.config['Global']['output_dir'] + log_file = os.path.join(self.output_dir, self.config["Arch"]["name"], + f"{mode}.log") + init_logger(name='root', log_file=log_file) + print_config(config) + + # init train_func and eval_func + if self.eval_mode == "classification": + self.evaler = classification_eval + self.trainer = classification_train + elif self.eval_mode == "retrieval": + self.trainer = retrieval_train + self.evaler = retrieval_eval + else: + logger.warning("Invalid eval mode: {}".format(self.eval_mode)) + self.use_dali = self.config['Global'].get("use_dali", False) + + # for visualdl + self.vdl_writer = None + if self.config['Global']['use_visualdl'] and mode == "train": + vdl_writer_path = os.path.join(self.output_dir, "vdl") + if not os.path.exists(vdl_writer_path): + os.makedirs(vdl_writer_path) + self.vdl_writer = LogWriter(logdir=vdl_writer_path) + + # set device + assert self.config["Global"]["device"] in ["cpu", "gpu", "xpu"] + self.device = paddle.set_device(self.config["Global"]["device"]) + logger.info('train with paddle {} and device {}'.format( + paddle.__version__, self.device)) + + # AMP training + self.amp = True if "AMP" in self.config else False + if self.amp and self.config["AMP"] is not None: + self.scale_loss = self.config["AMP"].get("scale_loss", 1.0) + self.use_dynamic_loss_scaling = self.config["AMP"].get( + "use_dynamic_loss_scaling", False) + else: + self.scale_loss = 1.0 + self.use_dynamic_loss_scaling = False + if self.amp: + AMP_RELATED_FLAGS_SETTING = { + 'FLAGS_cudnn_batchnorm_spatial_persistent': 1, + 'FLAGS_max_inplace_grad_add': 8, + } + paddle.fluid.set_flags(AMP_RELATED_FLAGS_SETTING) + + # build dataloader + if self.mode == 'train': + self.train_dataloader = build_dataloader( + self.config["DataLoader"], "Train", self.device, self.use_dali) + if self.mode in ["train", "eval"]: + if self.eval_mode == "classification": + self.eval_dataloader = build_dataloader( + self.config["DataLoader"], "Eval", self.device, + self.use_dali) + elif self.eval_mode == "retrieval": + self.gallery_dataloader = build_dataloader( + self.config["DataLoader"]["Eval"], "Gallery", self.device, + self.use_dali) + self.query_dataloader = build_dataloader( + self.config["DataLoader"]["Eval"], "Query", self.device, + self.use_dali) + + # build loss + if self.mode == "train": + loss_info = self.config["Loss"]["Train"] + self.train_loss_func = build_loss(loss_info) + if self.mode in ["train", "eval"]: + loss_config = self.config.get("Loss", None) + if loss_config is not None: + loss_config = loss_config.get("Eval") + if loss_config is not None: + self.eval_loss_func = build_loss(loss_config) + else: + self.eval_loss_func = None + else: + self.eval_loss_func = None + + # build metric + if self.mode == 'train': + metric_config = self.config.get("Metric") + if metric_config is not None: + metric_config = metric_config.get("Train") + if metric_config is not None: + self.train_metric_func = build_metrics(metric_config) + else: + self.train_metric_func = None + else: + self.train_metric_func = None + + if self.mode in ["train", "eval"]: + metric_config = self.config.get("Metric") + if self.eval_mode == "classification": + if metric_config is not None: + metric_config = metric_config.get("Eval") + if metric_config is not None: + self.eval_metric_func = build_metrics(metric_config) + elif self.eval_mode == "retrieval": + if metric_config is None: + metric_config = [{"name": "Recallk", "topk": (1, 5)}] + else: + metric_config = metric_config["Eval"] + self.eval_metric_func = build_metrics(metric_config) + else: + self.eval_metric_func = None + + # build model + self.model = build_model(self.config["Arch"]) + # set @to_static for benchmark, skip this by default. + apply_to_static(self.config, self.model) + # load_pretrain + if self.config["Global"]["pretrained_model"] is not None: + if self.config["Global"]["pretrained_model"].startswith("http"): + load_dygraph_pretrain_from_url( + self.model, self.config["Global"]["pretrained_model"]) + else: + load_dygraph_pretrain( + self.model, self.config["Global"]["pretrained_model"]) + + # for slim + + # build optimizer + if self.mode == 'train': + self.optimizer, self.lr_sch = build_optimizer( + self.config["Optimizer"], self.config["Global"]["epochs"], + len(self.train_dataloader), self.model.parameters()) + + # for distributed + self.config["Global"][ + "distributed"] = paddle.distributed.get_world_size() != 1 + if self.config["Global"]["distributed"]: + dist.init_parallel_env() + if self.config["Global"]["distributed"]: + self.model = paddle.DataParallel(self.model) + + # build postprocess for infer + if self.mode == 'infer': + self.preprocess_func = create_operators(self.config["Infer"][ + "transforms"]) + self.postprocess_func = build_postprocess(self.config["Infer"][ + "PostProcess"]) + + def train(self): + assert self.mode == "train" + print_batch_step = self.config['Global']['print_batch_step'] + save_interval = self.config["Global"]["save_interval"] + best_metric = { + "metric": 0.0, + "epoch": 0, + } + # key: + # val: metrics list word + self.output_info = dict() + self.time_info = { + "batch_cost": AverageMeter( + "batch_cost", '.5f', postfix=" s,"), + "reader_cost": AverageMeter( + "reader_cost", ".5f", postfix=" s,"), + } + # global iter counter + self.global_step = 0 + + if self.config["Global"]["checkpoints"] is not None: + metric_info = init_model(self.config["Global"], self.model, + self.optimizer) + if metric_info is not None: + best_metric.update(metric_info) + + # for amp training + if self.amp: + self.scaler = paddle.amp.GradScaler( + init_loss_scaling=self.scale_loss, + use_dynamic_loss_scaling=self.use_dynamic_loss_scaling) + + self.max_iter = len(self.train_dataloader) - 1 if platform.system( + ) == "Windows" else len(self.train_dataloader) + for epoch_id in range(best_metric["epoch"] + 1, + self.config["Global"]["epochs"] + 1): + acc = 0.0 + # for one epoch train + self.trainer(self, epoch_id, print_batch_step) + + if self.use_dali: + self.train_dataloader.reset() + metric_msg = ", ".join([ + "{}: {:.5f}".format(key, self.output_info[key].avg) + for key in self.output_info + ]) + logger.info("[Train][Epoch {}/{}][Avg]{}".format( + epoch_id, self.config["Global"]["epochs"], metric_msg)) + self.output_info.clear() + + # eval model and save model if possible + if self.config["Global"][ + "eval_during_train"] and epoch_id % self.config["Global"][ + "eval_interval"] == 0: + acc = self.eval(epoch_id) + if acc > best_metric["metric"]: + best_metric["metric"] = acc + best_metric["epoch"] = epoch_id + save_load.save_model( + self.model, + self.optimizer, + best_metric, + self.output_dir, + model_name=self.config["Arch"]["name"], + prefix="best_model") + logger.info("[Eval][Epoch {}][best metric: {}]".format( + epoch_id, best_metric["metric"])) + logger.scaler( + name="eval_acc", + value=acc, + step=epoch_id, + writer=self.vdl_writer) + + self.model.train() + + # save model + if epoch_id % save_interval == 0: + save_load.save_model( + self.model, + self.optimizer, {"metric": acc, + "epoch": epoch_id}, + self.output_dir, + model_name=self.config["Arch"]["name"], + prefix="epoch_{}".format(epoch_id)) + # save the latest model + save_load.save_model( + self.model, + self.optimizer, {"metric": acc, + "epoch": epoch_id}, + self.output_dir, + model_name=self.config["Arch"]["name"], + prefix="latest") + + if self.vdl_writer is not None: + self.vdl_writer.close() + + @paddle.no_grad() + def eval(self, epoch_id=0): + assert self.mode in ["train", "eval"] + self.model.eval() + eval_result = self.evaler(self, epoch_id) + self.model.train() + return eval_result + + @paddle.no_grad() + def infer(self): + assert self.mode == "infer" and self.eval_mode == "classification" + total_trainer = paddle.distributed.get_world_size() + local_rank = paddle.distributed.get_rank() + image_list = get_image_list(self.config["Infer"]["infer_imgs"]) + # data split + image_list = image_list[local_rank::total_trainer] + + batch_size = self.config["Infer"]["batch_size"] + self.model.eval() + batch_data = [] + image_file_list = [] + for idx, image_file in enumerate(image_list): + with open(image_file, 'rb') as f: + x = f.read() + for process in self.preprocess_func: + x = process(x) + batch_data.append(x) + image_file_list.append(image_file) + if len(batch_data) >= batch_size or idx == len(image_list) - 1: + batch_tensor = paddle.to_tensor(batch_data) + out = self.model(batch_tensor) + if isinstance(out, list): + out = out[0] + result = self.postprocess_func(out, image_file_list) + print(result) + batch_data.clear() + image_file_list.clear() + + def export(self): + assert self.mode == "export" + model = ExportModel(self.config["Arch"], self.model) + if self.config["Global"]["pretrained_model"] is not None: + load_dygraph_pretrain(model.base_model, + self.config["Global"]["pretrained_model"]) + + model.eval() + + model = paddle.jit.to_static( + model, + input_spec=[ + paddle.static.InputSpec( + shape=[None] + self.config["Global"]["image_shape"], + dtype='float32') + ]) + paddle.jit.save( + model, + os.path.join(self.config["Global"]["save_inference_dir"], + "inference")) + + +class ExportModel(nn.Layer): + """ + ExportModel: add softmax onto the model + """ + + def __init__(self, config, model): + super().__init__() + self.base_model = model + + # we should choose a final model to export + if isinstance(self.base_model, DistillationModel): + self.infer_model_name = config["infer_model_name"] + else: + self.infer_model_name = None + + self.infer_output_key = config.get("infer_output_key", None) + if self.infer_output_key == "features" and isinstance(self.base_model, + RecModel): + self.base_model.head = IdentityHead() + if config.get("infer_add_softmax", True): + self.softmax = nn.Softmax(axis=-1) + else: + self.softmax = None + + def eval(self): + self.training = False + for layer in self.sublayers(): + layer.training = False + layer.eval() + + def forward(self, x): + x = self.base_model(x) + if isinstance(x, list): + x = x[0] + if self.infer_model_name is not None: + x = x[self.infer_model_name] + if self.infer_output_key is not None: + x = x[self.infer_output_key] + if self.softmax is not None: + x = self.softmax(x) + return x diff --git a/ppcls/engine/eval/__init__.py b/ppcls/engine/eval/__init__.py new file mode 100644 index 000000000..0cc0dc983 --- /dev/null +++ b/ppcls/engine/eval/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ppcls.engine.eval.classification import classification_eval +from ppcls.engine.eval.retrieval import retrieval_eval diff --git a/ppcls/engine/eval/classification.py b/ppcls/engine/eval/classification.py new file mode 100644 index 000000000..38be7cd3f --- /dev/null +++ b/ppcls/engine/eval/classification.py @@ -0,0 +1,118 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import os +import sys +import time +import platform +import paddle + +__dir__ = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) +from ppcls.utils.misc import AverageMeter +from ppcls.utils import logger + + +def classification_eval(evaler, epoch_id=0): + output_info = dict() + time_info = { + "batch_cost": AverageMeter( + "batch_cost", '.5f', postfix=" s,"), + "reader_cost": AverageMeter( + "reader_cost", ".5f", postfix=" s,"), + } + print_batch_step = evaler.config["Global"]["print_batch_step"] + + metric_key = None + tic = time.time() + eval_dataloader = evaler.eval_dataloader if evaler.use_dali else evaler.eval_dataloader( + ) + max_iter = len(evaler.eval_dataloader) - 1 if platform.system( + ) == "Windows" else len(evaler.eval_dataloader) + for iter_id, batch in enumerate(eval_dataloader): + if iter_id >= max_iter: + break + if iter_id == 5: + for key in time_info: + time_info[key].reset() + if evaler.use_dali: + batch = [ + paddle.to_tensor(batch[0]['data']), + paddle.to_tensor(batch[0]['label']) + ] + time_info["reader_cost"].update(time.time() - tic) + batch_size = batch[0].shape[0] + batch[0] = paddle.to_tensor(batch[0]).astype("float32") + batch[1] = batch[1].reshape([-1, 1]).astype("int64") + # image input + out = evaler.model(batch[0]) + # calc loss + if evaler.eval_loss_func is not None: + loss_dict = evaler.eval_loss_func(out, batch[-1]) + for key in loss_dict: + if key not in output_info: + output_info[key] = AverageMeter(key, '7.5f') + output_info[key].update(loss_dict[key].numpy()[0], batch_size) + # calc metric + if evaler.eval_metric_func is not None: + metric_dict = evaler.eval_metric_func(out, batch[-1]) + if paddle.distributed.get_world_size() > 1: + for key in metric_dict: + paddle.distributed.all_reduce( + metric_dict[key], op=paddle.distributed.ReduceOp.SUM) + metric_dict[key] = metric_dict[ + key] / paddle.distributed.get_world_size() + for key in metric_dict: + if metric_key is None: + metric_key = key + if key not in output_info: + output_info[key] = AverageMeter(key, '7.5f') + + output_info[key].update(metric_dict[key].numpy()[0], + batch_size) + + time_info["batch_cost"].update(time.time() - tic) + + if iter_id % print_batch_step == 0: + time_msg = "s, ".join([ + "{}: {:.5f}".format(key, time_info[key].avg) + for key in time_info + ]) + + ips_msg = "ips: {:.5f} images/sec".format( + batch_size / time_info["batch_cost"].avg) + + metric_msg = ", ".join([ + "{}: {:.5f}".format(key, output_info[key].val) + for key in output_info + ]) + logger.info("[Eval][Epoch {}][Iter: {}/{}]{}, {}, {}".format( + epoch_id, iter_id, + len(evaler.eval_dataloader), metric_msg, time_msg, ips_msg)) + + tic = time.time() + if evaler.use_dali: + evaler.eval_dataloader.reset() + metric_msg = ", ".join([ + "{}: {:.5f}".format(key, output_info[key].avg) for key in output_info + ]) + logger.info("[Eval][Epoch {}][Avg]{}".format(epoch_id, metric_msg)) + + # do not try to save best eval.model + if evaler.eval_metric_func is None: + return -1 + # return 1st metric in the dict + return output_info[metric_key].avg diff --git a/ppcls/engine/eval/retrieval.py b/ppcls/engine/eval/retrieval.py new file mode 100644 index 000000000..ccba31754 --- /dev/null +++ b/ppcls/engine/eval/retrieval.py @@ -0,0 +1,160 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import os +import sys +import time +import platform +import paddle + +__dir__ = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) +from ppcls.utils.misc import AverageMeter +from ppcls.utils import logger + + +def retrieval_eval(evaler, epoch_id=0): + evaler.model.eval() + # step1. build gallery + gallery_feas, gallery_img_id, gallery_unique_id = cal_feature( + evaler, name='gallery') + query_feas, query_img_id, query_query_id = cal_feature( + evaler, name='query') + + # step2. do evaluation + sim_block_size = evaler.config["Global"].get("sim_block_size", 64) + sections = [sim_block_size] * (len(query_feas) // sim_block_size) + if len(query_feas) % sim_block_size: + sections.append(len(query_feas) % sim_block_size) + fea_blocks = paddle.split(query_feas, num_or_sections=sections) + if query_query_id is not None: + query_id_blocks = paddle.split( + query_query_id, num_or_sections=sections) + image_id_blocks = paddle.split(query_img_id, num_or_sections=sections) + metric_key = None + + if evaler.eval_loss_func is None: + metric_dict = {metric_key: 0.} + else: + metric_dict = dict() + for block_idx, block_fea in enumerate(fea_blocks): + similarity_matrix = paddle.matmul( + block_fea, gallery_feas, transpose_y=True) + if query_query_id is not None: + query_id_block = query_id_blocks[block_idx] + query_id_mask = (query_id_block != gallery_unique_id.t()) + + image_id_block = image_id_blocks[block_idx] + image_id_mask = (image_id_block != gallery_img_id.t()) + + keep_mask = paddle.logical_or(query_id_mask, image_id_mask) + similarity_matrix = similarity_matrix * keep_mask.astype( + "float32") + else: + keep_mask = None + + metric_tmp = evaler.eval_metric_func(similarity_matrix, + image_id_blocks[block_idx], + gallery_img_id, keep_mask) + + for key in metric_tmp: + if key not in metric_dict: + metric_dict[key] = metric_tmp[key] * block_fea.shape[ + 0] / len(query_feas) + else: + metric_dict[key] += metric_tmp[key] * block_fea.shape[ + 0] / len(query_feas) + + metric_info_list = [] + for key in metric_dict: + if metric_key is None: + metric_key = key + metric_info_list.append("{}: {:.5f}".format(key, metric_dict[key])) + metric_msg = ", ".join(metric_info_list) + logger.info("[Eval][Epoch {}][Avg]{}".format(epoch_id, metric_msg)) + + return metric_dict[metric_key] + + +def cal_feature(evaler, name='gallery'): + all_feas = None + all_image_id = None + all_unique_id = None + has_unique_id = False + + if name == 'gallery': + dataloader = evaler.gallery_dataloader + elif name == 'query': + dataloader = evaler.query_dataloader + else: + raise RuntimeError("Only support gallery or query dataset") + + max_iter = len(dataloader) - 1 if platform.system() == "Windows" else len( + dataloader) + dataloader_tmp = dataloader if evaler.use_dali else dataloader() + for idx, batch in enumerate(dataloader_tmp): # load is very time-consuming + if idx >= max_iter: + break + if idx % evaler.config["Global"]["print_batch_step"] == 0: + logger.info( + f"{name} feature calculation process: [{idx}/{len(dataloader)}]" + ) + if evaler.use_dali: + batch = [ + paddle.to_tensor(batch[0]['data']), + paddle.to_tensor(batch[0]['label']) + ] + batch = [paddle.to_tensor(x) for x in batch] + batch[1] = batch[1].reshape([-1, 1]).astype("int64") + if len(batch) == 3: + has_unique_id = True + batch[2] = batch[2].reshape([-1, 1]).astype("int64") + out = evaler.model(batch[0], batch[1]) + batch_feas = out["features"] + + # do norm + if evaler.config["Global"].get("feature_normalize", True): + feas_norm = paddle.sqrt( + paddle.sum(paddle.square(batch_feas), axis=1, keepdim=True)) + batch_feas = paddle.divide(batch_feas, feas_norm) + + if all_feas is None: + all_feas = batch_feas + if has_unique_id: + all_unique_id = batch[2] + all_image_id = batch[1] + else: + all_feas = paddle.concat([all_feas, batch_feas]) + all_image_id = paddle.concat([all_image_id, batch[1]]) + if has_unique_id: + all_unique_id = paddle.concat([all_unique_id, batch[2]]) + if evaler.use_dali: + dataloader_tmp.reset() + if paddle.distributed.get_world_size() > 1: + feat_list = [] + img_id_list = [] + unique_id_list = [] + paddle.distributed.all_gather(feat_list, all_feas) + paddle.distributed.all_gather(img_id_list, all_image_id) + all_feas = paddle.concat(feat_list, axis=0) + all_image_id = paddle.concat(img_id_list, axis=0) + if has_unique_id: + paddle.distributed.all_gather(unique_id_list, all_unique_id) + all_unique_id = paddle.concat(unique_id_list, axis=0) + + logger.info("Build {} done, all feat shape: {}, begin to eval..".format( + name, all_feas.shape)) + return all_feas, all_image_id, all_unique_id diff --git a/ppcls/engine/slim/__init__.py b/ppcls/engine/slim/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ppcls/engine/train/__init__.py b/ppcls/engine/train/__init__.py new file mode 100644 index 000000000..897c5846d --- /dev/null +++ b/ppcls/engine/train/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from ppcls.engine.train.classification import classification_train +from ppcls.engine.train.retrieval import retrieval_train diff --git a/ppcls/engine/train/classification.py b/ppcls/engine/train/classification.py new file mode 100644 index 000000000..c3d74f962 --- /dev/null +++ b/ppcls/engine/train/classification.py @@ -0,0 +1,89 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +import datetime +import os +import platform +import sys +import time + +import numpy as np +import paddle + +__dir__ = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) +from ppcls.utils import logger +from ppcls.utils.misc import AverageMeter +from ppcls.engine.train.utils import update_loss, update_metric, log_info + + +def classification_train(trainer, epoch_id, print_batch_step): + tic = time.time() + + train_dataloader = trainer.train_dataloader if trainer.use_dali else trainer.train_dataloader( + ) + for iter_id, batch in enumerate(train_dataloader): + if iter_id >= trainer.max_iter: + break + if iter_id == 5: + for key in trainer.time_info: + trainer.time_info[key].reset() + trainer.time_info["reader_cost"].update(time.time() - tic) + if trainer.use_dali: + batch = [ + paddle.to_tensor(batch[0]['data']), + paddle.to_tensor(batch[0]['label']) + ] + batch_size = batch[0].shape[0] + batch[1] = batch[1].reshape([-1, 1]).astype("int64") + + trainer.global_step += 1 + # image input + if trainer.amp: + with paddle.amp.auto_cast(custom_black_list={ + "flatten_contiguous_range", "greater_than" + }): + out = trainer.model(batch[0]) + loss_dict = trainer.train_loss_func(out, batch[1]) + else: + out = trainer.model(batch[0]) + + # calc loss + if trainer.config["DataLoader"]["Train"]["dataset"].get( + "batch_transform_ops", None): + loss_dict = trainer.train_loss_func(out, batch[1:]) + else: + loss_dict = trainer.train_loss_func(out, batch[1]) + + # step opt and lr + if trainer.amp: + scaled = trainer.scaler.scale(loss_dict["loss"]) + scaled.backward() + trainer.scaler.minimize(trainer.optimizer, scaled) + else: + loss_dict["loss"].backward() + trainer.optimizer.step() + trainer.optimizer.clear_grad() + trainer.lr_sch.step() + + # below code just for logging + # update metric_for_logger + update_metric(trainer, out, batch, batch_size) + # update_loss_for_logger + update_loss(trainer, loss_dict, batch_size) + trainer.time_info["batch_cost"].update(time.time() - tic) + if iter_id % print_batch_step == 0: + log_info(trainer, batch_size, epoch_id, iter_id) + tic = time.time() diff --git a/ppcls/engine/train/retrieval.py b/ppcls/engine/train/retrieval.py new file mode 100644 index 000000000..d4a994597 --- /dev/null +++ b/ppcls/engine/train/retrieval.py @@ -0,0 +1,90 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +import datetime +import os +import platform +import sys +import time + +import numpy as np +import paddle + +__dir__ = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) +from ppcls.utils import logger +from ppcls.utils.misc import AverageMeter +from ppcls.engine.train.utils import update_loss, update_metric, log_info + + +def retrieval_train(trainer, epoch_id, print_batch_step): + tic = time.time() + + train_dataloader = trainer.train_dataloader if trainer.use_dali else trainer.train_dataloader( + ) + for iter_id, batch in enumerate(train_dataloader): + if iter_id >= trainer.max_iter: + break + if iter_id == 5: + for key in trainer.time_info: + trainer.time_info[key].reset() + trainer.time_info["reader_cost"].update(time.time() - tic) + if trainer.use_dali: + batch = [ + paddle.to_tensor(batch[0]['data']), + paddle.to_tensor(batch[0]['label']) + ] + batch_size = batch[0].shape[0] + batch[1] = batch[1].reshape([-1, 1]).astype("int64") + + trainer.global_step += 1 + # image input + if trainer.amp: + with paddle.amp.auto_cast(custom_black_list={ + "flatten_contiguous_range", "greater_than" + }): + out = trainer.model(batch[0], batch[1]) + loss_dict = trainer.train_loss_func(out, batch[1]) + else: + out = trainer.model(batch[0], batch[1]) + + # calc loss + if trainer.config["DataLoader"]["Train"]["dataset"].get( + "batch_transform_ops", None): + loss_dict = trainer.train_loss_func(out, batch[1:]) + else: + loss_dict = trainer.train_loss_func(out, batch[1]) + + # step opt and lr + if trainer.amp: + scaled = trainer.scaler.scale(loss_dict["loss"]) + scaled.backward() + trainer.scaler.minimize(trainer.optimizer, scaled) + else: + loss_dict["loss"].backward() + trainer.optimizer.step() + trainer.optimizer.clear_grad() + trainer.lr_sch.step() + + # below code just for logging + # update metric_for_logger + update_metric(trainer, out, batch, batch_size) + + # update_loss_for_logger + update_loss(trainer, loss_dict, batch_size) + trainer.time_info["batch_cost"].update(time.time() - tic) + if iter_id % print_batch_step == 0: + log_info(trainer, batch_size, epoch_id, iter_id) + tic = time.time() diff --git a/ppcls/engine/train/utils.py b/ppcls/engine/train/utils.py new file mode 100644 index 000000000..f4cbce97e --- /dev/null +++ b/ppcls/engine/train/utils.py @@ -0,0 +1,82 @@ +# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import absolute_import, division, print_function + +import datetime +import os +import platform +import sys +import time + +import numpy as np +import paddle + +__dir__ = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) +from ppcls.utils import logger +from ppcls.utils.misc import AverageMeter + + +def update_metric(trainer, out, batch, batch_size): + # calc metric + if trainer.train_metric_func is not None: + metric_dict = trainer.train_metric_func(out, batch[-1]) + for key in metric_dict: + if key not in trainer.output_info: + trainer.output_info[key] = AverageMeter(key, '7.5f') + trainer.output_info[key].update(metric_dict[key].numpy()[0], + batch_size) + + +def update_loss(trainer, loss_dict, batch_size): + # update_output_info + for key in loss_dict: + if key not in trainer.output_info: + trainer.output_info[key] = AverageMeter(key, '7.5f') + trainer.output_info[key].update(loss_dict[key].numpy()[0], batch_size) + + +def log_info(trainer, batch_size, epoch_id, iter_id): + lr_msg = "lr: {:.5f}".format(trainer.lr_sch.get_lr()) + metric_msg = ", ".join([ + "{}: {:.5f}".format(key, trainer.output_info[key].avg) + for key in trainer.output_info + ]) + time_msg = "s, ".join([ + "{}: {:.5f}".format(key, trainer.time_info[key].avg) + for key in trainer.time_info + ]) + + ips_msg = "ips: {:.5f} images/sec".format( + batch_size / trainer.time_info["batch_cost"].avg) + eta_sec = ((trainer.config["Global"]["epochs"] - epoch_id + 1 + ) * len(trainer.train_dataloader) - iter_id + ) * trainer.time_info["batch_cost"].avg + eta_msg = "eta: {:s}".format(str(datetime.timedelta(seconds=int(eta_sec)))) + logger.info("[Train][Epoch {}/{}][Iter: {}/{}]{}, {}, {}, {}, {}".format( + epoch_id, trainer.config["Global"]["epochs"], iter_id, + len(trainer.train_dataloader), lr_msg, metric_msg, time_msg, ips_msg, + eta_msg)) + + logger.scaler( + name="lr", + value=trainer.lr_sch.get_lr(), + step=trainer.global_step, + writer=trainer.vdl_writer) + for key in trainer.output_info: + logger.scaler( + name="train_{}".format(key), + value=trainer.output_info[key].avg, + step=trainer.global_step, + writer=trainer.vdl_writer) diff --git a/ppcls/engine/trainer.py b/ppcls/engine/trainer.py deleted file mode 100644 index 14b7547dd..000000000 --- a/ppcls/engine/trainer.py +++ /dev/null @@ -1,662 +0,0 @@ -# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -import os -import sys -import numpy as np - -__dir__ = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(__dir__, '../../'))) - -import time -import platform -import datetime -import argparse -import paddle -import paddle.nn as nn -import paddle.distributed as dist -from visualdl import LogWriter - -from ppcls.utils.check import check_gpu -from ppcls.utils.misc import AverageMeter -from ppcls.utils import logger -from ppcls.utils.logger import init_logger -from ppcls.utils.config import print_config -from ppcls.data import build_dataloader -from ppcls.arch import build_model -from ppcls.arch import apply_to_static -from ppcls.loss import build_loss -from ppcls.metric import build_metrics -from ppcls.optimizer import build_optimizer -from ppcls.utils.save_load import load_dygraph_pretrain, load_dygraph_pretrain_from_url -from ppcls.utils.save_load import init_model -from ppcls.utils import save_load - -from ppcls.data.utils.get_image_list import get_image_list -from ppcls.data.postprocess import build_postprocess -from ppcls.data import create_operators - - -class Trainer(object): - def __init__(self, config, mode="train"): - self.mode = mode - self.config = config - self.output_dir = self.config['Global']['output_dir'] - - log_file = os.path.join(self.output_dir, self.config["Arch"]["name"], - f"{mode}.log") - init_logger(name='root', log_file=log_file) - print_config(config) - # set device - assert self.config["Global"]["device"] in ["cpu", "gpu", "xpu"] - self.device = paddle.set_device(self.config["Global"]["device"]) - # set dist - self.config["Global"][ - "distributed"] = paddle.distributed.get_world_size() != 1 - if self.config["Global"]["distributed"]: - dist.init_parallel_env() - - if "Head" in self.config["Arch"]: - self.is_rec = True - else: - self.is_rec = False - - self.model = build_model(self.config["Arch"]) - # set @to_static for benchmark, skip this by default. - apply_to_static(self.config, self.model) - - if self.config["Global"]["pretrained_model"] is not None: - if self.config["Global"]["pretrained_model"].startswith("http"): - load_dygraph_pretrain_from_url( - self.model, self.config["Global"]["pretrained_model"]) - else: - load_dygraph_pretrain( - self.model, self.config["Global"]["pretrained_model"]) - - if self.config["Global"]["distributed"]: - self.model = paddle.DataParallel(self.model) - - self.vdl_writer = None - if self.config['Global']['use_visualdl'] and mode == "train": - vdl_writer_path = os.path.join(self.output_dir, "vdl") - if not os.path.exists(vdl_writer_path): - os.makedirs(vdl_writer_path) - self.vdl_writer = LogWriter(logdir=vdl_writer_path) - logger.info('train with paddle {} and device {}'.format( - paddle.__version__, self.device)) - # init members - self.train_dataloader = None - self.eval_dataloader = None - self.gallery_dataloader = None - self.query_dataloader = None - self.eval_mode = self.config["Global"].get("eval_mode", - "classification") - self.amp = True if "AMP" in self.config else False - if self.amp and self.config["AMP"] is not None: - self.scale_loss = self.config["AMP"].get("scale_loss", 1.0) - self.use_dynamic_loss_scaling = self.config["AMP"].get( - "use_dynamic_loss_scaling", False) - else: - self.scale_loss = 1.0 - self.use_dynamic_loss_scaling = False - if self.amp: - AMP_RELATED_FLAGS_SETTING = { - 'FLAGS_cudnn_batchnorm_spatial_persistent': 1, - 'FLAGS_max_inplace_grad_add': 8, - } - paddle.fluid.set_flags(AMP_RELATED_FLAGS_SETTING) - self.train_loss_func = None - self.eval_loss_func = None - self.train_metric_func = None - self.eval_metric_func = None - self.use_dali = self.config['Global'].get("use_dali", False) - - def train(self): - # build train loss and metric info - if self.train_loss_func is None: - loss_info = self.config["Loss"]["Train"] - self.train_loss_func = build_loss(loss_info) - if self.train_metric_func is None: - metric_config = self.config.get("Metric") - if metric_config is not None: - metric_config = metric_config.get("Train") - if metric_config is not None: - self.train_metric_func = build_metrics(metric_config) - - if self.train_dataloader is None: - self.train_dataloader = build_dataloader( - self.config["DataLoader"], "Train", self.device, self.use_dali) - - step_each_epoch = len(self.train_dataloader) - - optimizer, lr_sch = build_optimizer(self.config["Optimizer"], - self.config["Global"]["epochs"], - step_each_epoch, - self.model.parameters()) - - print_batch_step = self.config['Global']['print_batch_step'] - save_interval = self.config["Global"]["save_interval"] - - best_metric = { - "metric": 0.0, - "epoch": 0, - } - # key: - # val: metrics list word - output_info = dict() - time_info = { - "batch_cost": AverageMeter( - "batch_cost", '.5f', postfix=" s,"), - "reader_cost": AverageMeter( - "reader_cost", ".5f", postfix=" s,"), - } - # global iter counter - global_step = 0 - - if self.config["Global"]["checkpoints"] is not None: - metric_info = init_model(self.config["Global"], self.model, - optimizer) - if metric_info is not None: - best_metric.update(metric_info) - - # for amp training - if self.amp: - scaler = paddle.amp.GradScaler( - init_loss_scaling=self.scale_loss, - use_dynamic_loss_scaling=self.use_dynamic_loss_scaling) - - tic = time.time() - max_iter = len(self.train_dataloader) - 1 if platform.system( - ) == "Windows" else len(self.train_dataloader) - for epoch_id in range(best_metric["epoch"] + 1, - self.config["Global"]["epochs"] + 1): - acc = 0.0 - train_dataloader = self.train_dataloader if self.use_dali else self.train_dataloader( - ) - for iter_id, batch in enumerate(train_dataloader): - if iter_id >= max_iter: - break - if iter_id == 5: - for key in time_info: - time_info[key].reset() - time_info["reader_cost"].update(time.time() - tic) - if self.use_dali: - batch = [ - paddle.to_tensor(batch[0]['data']), - paddle.to_tensor(batch[0]['label']) - ] - batch_size = batch[0].shape[0] - batch[1] = batch[1].reshape([-1, 1]).astype("int64") - - global_step += 1 - # image input - if self.amp: - with paddle.amp.auto_cast(custom_black_list={ - "flatten_contiguous_range", "greater_than" - }): - out = self.forward(batch) - loss_dict = self.train_loss_func(out, batch[1]) - else: - out = self.forward(batch) - - # calc loss - if self.config["DataLoader"]["Train"]["dataset"].get( - "batch_transform_ops", None): - loss_dict = self.train_loss_func(out, batch[1:]) - else: - loss_dict = self.train_loss_func(out, batch[1]) - - for key in loss_dict: - if not key in output_info: - output_info[key] = AverageMeter(key, '7.5f') - output_info[key].update(loss_dict[key].numpy()[0], - batch_size) - # calc metric - if self.train_metric_func is not None: - metric_dict = self.train_metric_func(out, batch[-1]) - for key in metric_dict: - if not key in output_info: - output_info[key] = AverageMeter(key, '7.5f') - output_info[key].update(metric_dict[key].numpy()[0], - batch_size) - - # step opt and lr - if self.amp: - scaled = scaler.scale(loss_dict["loss"]) - scaled.backward() - scaler.minimize(optimizer, scaled) - else: - loss_dict["loss"].backward() - optimizer.step() - optimizer.clear_grad() - lr_sch.step() - - time_info["batch_cost"].update(time.time() - tic) - - if iter_id % print_batch_step == 0: - lr_msg = "lr: {:.5f}".format(lr_sch.get_lr()) - metric_msg = ", ".join([ - "{}: {:.5f}".format(key, output_info[key].avg) - for key in output_info - ]) - time_msg = "s, ".join([ - "{}: {:.5f}".format(key, time_info[key].avg) - for key in time_info - ]) - - ips_msg = "ips: {:.5f} images/sec".format( - batch_size / time_info["batch_cost"].avg) - eta_sec = ((self.config["Global"]["epochs"] - epoch_id + 1 - ) * len(self.train_dataloader) - iter_id - ) * time_info["batch_cost"].avg - eta_msg = "eta: {:s}".format( - str(datetime.timedelta(seconds=int(eta_sec)))) - logger.info( - "[Train][Epoch {}/{}][Iter: {}/{}]{}, {}, {}, {}, {}". - format(epoch_id, self.config["Global"][ - "epochs"], iter_id, - len(self.train_dataloader), lr_msg, metric_msg, - time_msg, ips_msg, eta_msg)) - - logger.scaler( - name="lr", - value=lr_sch.get_lr(), - step=global_step, - writer=self.vdl_writer) - for key in output_info: - logger.scaler( - name="train_{}".format(key), - value=output_info[key].avg, - step=global_step, - writer=self.vdl_writer) - tic = time.time() - if self.use_dali: - self.train_dataloader.reset() - metric_msg = ", ".join([ - "{}: {:.5f}".format(key, output_info[key].avg) - for key in output_info - ]) - logger.info("[Train][Epoch {}/{}][Avg]{}".format( - epoch_id, self.config["Global"]["epochs"], metric_msg)) - output_info.clear() - - # eval model and save model if possible - if self.config["Global"][ - "eval_during_train"] and epoch_id % self.config["Global"][ - "eval_interval"] == 0: - acc = self.eval(epoch_id) - if acc > best_metric["metric"]: - best_metric["metric"] = acc - best_metric["epoch"] = epoch_id - save_load.save_model( - self.model, - optimizer, - best_metric, - self.output_dir, - model_name=self.config["Arch"]["name"], - prefix="best_model") - logger.info("[Eval][Epoch {}][best metric: {}]".format( - epoch_id, best_metric["metric"])) - logger.scaler( - name="eval_acc", - value=acc, - step=epoch_id, - writer=self.vdl_writer) - - self.model.train() - - # save model - if epoch_id % save_interval == 0: - save_load.save_model( - self.model, - optimizer, {"metric": acc, - "epoch": epoch_id}, - self.output_dir, - model_name=self.config["Arch"]["name"], - prefix="epoch_{}".format(epoch_id)) - # save the latest model - save_load.save_model( - self.model, - optimizer, {"metric": acc, - "epoch": epoch_id}, - self.output_dir, - model_name=self.config["Arch"]["name"], - prefix="latest") - - if self.vdl_writer is not None: - self.vdl_writer.close() - - def build_avg_metrics(self, info_dict): - return {key: AverageMeter(key, '7.5f') for key in info_dict} - - @paddle.no_grad() - def eval(self, epoch_id=0): - self.model.eval() - if self.eval_loss_func is None: - loss_config = self.config.get("Loss", None) - if loss_config is not None: - loss_config = loss_config.get("Eval") - if loss_config is not None: - self.eval_loss_func = build_loss(loss_config) - if self.eval_mode == "classification": - if self.eval_dataloader is None: - self.eval_dataloader = build_dataloader( - self.config["DataLoader"], "Eval", self.device, - self.use_dali) - - if self.eval_metric_func is None: - metric_config = self.config.get("Metric") - if metric_config is not None: - metric_config = metric_config.get("Eval") - if metric_config is not None: - self.eval_metric_func = build_metrics(metric_config) - - eval_result = self.eval_cls(epoch_id) - - elif self.eval_mode == "retrieval": - if self.gallery_dataloader is None: - self.gallery_dataloader = build_dataloader( - self.config["DataLoader"]["Eval"], "Gallery", self.device, - self.use_dali) - - if self.query_dataloader is None: - self.query_dataloader = build_dataloader( - self.config["DataLoader"]["Eval"], "Query", self.device, - self.use_dali) - # build metric info - if self.eval_metric_func is None: - metric_config = self.config.get("Metric", None) - if metric_config is None: - metric_config = [{"name": "Recallk", "topk": (1, 5)}] - else: - metric_config = metric_config["Eval"] - self.eval_metric_func = build_metrics(metric_config) - eval_result = self.eval_retrieval(epoch_id) - else: - logger.warning("Invalid eval mode: {}".format(self.eval_mode)) - eval_result = None - self.model.train() - return eval_result - - def forward(self, batch): - if not self.is_rec: - out = self.model(batch[0]) - else: - out = self.model(batch[0], batch[1]) - return out - - @paddle.no_grad() - def eval_cls(self, epoch_id=0): - output_info = dict() - time_info = { - "batch_cost": AverageMeter( - "batch_cost", '.5f', postfix=" s,"), - "reader_cost": AverageMeter( - "reader_cost", ".5f", postfix=" s,"), - } - print_batch_step = self.config["Global"]["print_batch_step"] - - metric_key = None - tic = time.time() - eval_dataloader = self.eval_dataloader if self.use_dali else self.eval_dataloader( - ) - max_iter = len(self.eval_dataloader) - 1 if platform.system( - ) == "Windows" else len(self.eval_dataloader) - for iter_id, batch in enumerate(eval_dataloader): - if iter_id >= max_iter: - break - if iter_id == 5: - for key in time_info: - time_info[key].reset() - if self.use_dali: - batch = [ - paddle.to_tensor(batch[0]['data']), - paddle.to_tensor(batch[0]['label']) - ] - time_info["reader_cost"].update(time.time() - tic) - batch_size = batch[0].shape[0] - batch[0] = paddle.to_tensor(batch[0]).astype("float32") - batch[1] = batch[1].reshape([-1, 1]).astype("int64") - # image input - out = self.forward(batch) - # calc loss - if self.eval_loss_func is not None: - loss_dict = self.eval_loss_func(out, batch[-1]) - for key in loss_dict: - if not key in output_info: - output_info[key] = AverageMeter(key, '7.5f') - output_info[key].update(loss_dict[key].numpy()[0], - batch_size) - # calc metric - if self.eval_metric_func is not None: - metric_dict = self.eval_metric_func(out, batch[-1]) - if paddle.distributed.get_world_size() > 1: - for key in metric_dict: - paddle.distributed.all_reduce( - metric_dict[key], - op=paddle.distributed.ReduceOp.SUM) - metric_dict[key] = metric_dict[ - key] / paddle.distributed.get_world_size() - for key in metric_dict: - if metric_key is None: - metric_key = key - if not key in output_info: - output_info[key] = AverageMeter(key, '7.5f') - - output_info[key].update(metric_dict[key].numpy()[0], - batch_size) - - time_info["batch_cost"].update(time.time() - tic) - - if iter_id % print_batch_step == 0: - time_msg = "s, ".join([ - "{}: {:.5f}".format(key, time_info[key].avg) - for key in time_info - ]) - - ips_msg = "ips: {:.5f} images/sec".format( - batch_size / time_info["batch_cost"].avg) - - metric_msg = ", ".join([ - "{}: {:.5f}".format(key, output_info[key].val) - for key in output_info - ]) - logger.info("[Eval][Epoch {}][Iter: {}/{}]{}, {}, {}".format( - epoch_id, iter_id, - len(self.eval_dataloader), metric_msg, time_msg, ips_msg)) - - tic = time.time() - if self.use_dali: - self.eval_dataloader.reset() - metric_msg = ", ".join([ - "{}: {:.5f}".format(key, output_info[key].avg) - for key in output_info - ]) - logger.info("[Eval][Epoch {}][Avg]{}".format(epoch_id, metric_msg)) - - # do not try to save best model - if self.eval_metric_func is None: - return -1 - # return 1st metric in the dict - return output_info[metric_key].avg - - def eval_retrieval(self, epoch_id=0): - self.model.eval() - # step1. build gallery - gallery_feas, gallery_img_id, gallery_unique_id = self._cal_feature( - name='gallery') - query_feas, query_img_id, query_query_id = self._cal_feature( - name='query') - - # step2. do evaluation - sim_block_size = self.config["Global"].get("sim_block_size", 64) - sections = [sim_block_size] * (len(query_feas) // sim_block_size) - if len(query_feas) % sim_block_size: - sections.append(len(query_feas) % sim_block_size) - fea_blocks = paddle.split(query_feas, num_or_sections=sections) - if query_query_id is not None: - query_id_blocks = paddle.split( - query_query_id, num_or_sections=sections) - image_id_blocks = paddle.split(query_img_id, num_or_sections=sections) - metric_key = None - - if self.eval_metric_func is None: - metric_dict = {metric_key: 0.} - else: - metric_dict = dict() - for block_idx, block_fea in enumerate(fea_blocks): - similarity_matrix = paddle.matmul( - block_fea, gallery_feas, transpose_y=True) - if query_query_id is not None: - query_id_block = query_id_blocks[block_idx] - query_id_mask = (query_id_block != gallery_unique_id.t()) - - image_id_block = image_id_blocks[block_idx] - image_id_mask = (image_id_block != gallery_img_id.t()) - - keep_mask = paddle.logical_or(query_id_mask, image_id_mask) - similarity_matrix = similarity_matrix * keep_mask.astype( - "float32") - else: - keep_mask = None - - metric_tmp = self.eval_metric_func(similarity_matrix, - image_id_blocks[block_idx], - gallery_img_id, keep_mask) - - for key in metric_tmp: - if key not in metric_dict: - metric_dict[key] = metric_tmp[key] * block_fea.shape[ - 0] / len(query_feas) - else: - metric_dict[key] += metric_tmp[key] * block_fea.shape[ - 0] / len(query_feas) - - metric_info_list = [] - for key in metric_dict: - if metric_key is None: - metric_key = key - metric_info_list.append("{}: {:.5f}".format(key, metric_dict[key])) - metric_msg = ", ".join(metric_info_list) - logger.info("[Eval][Epoch {}][Avg]{}".format(epoch_id, metric_msg)) - - return metric_dict[metric_key] - - def _cal_feature(self, name='gallery'): - all_feas = None - all_image_id = None - all_unique_id = None - if name == 'gallery': - dataloader = self.gallery_dataloader - elif name == 'query': - dataloader = self.query_dataloader - else: - raise RuntimeError("Only support gallery or query dataset") - - has_unique_id = False - max_iter = len(dataloader) - 1 if platform.system( - ) == "Windows" else len(dataloader) - dataloader_tmp = dataloader if self.use_dali else dataloader() - for idx, batch in enumerate( - dataloader_tmp): # load is very time-consuming - if idx >= max_iter: - break - if idx % self.config["Global"]["print_batch_step"] == 0: - logger.info( - f"{name} feature calculation process: [{idx}/{len(dataloader)}]" - ) - if self.use_dali: - batch = [ - paddle.to_tensor(batch[0]['data']), - paddle.to_tensor(batch[0]['label']) - ] - batch = [paddle.to_tensor(x) for x in batch] - batch[1] = batch[1].reshape([-1, 1]).astype("int64") - if len(batch) == 3: - has_unique_id = True - batch[2] = batch[2].reshape([-1, 1]).astype("int64") - out = self.forward(batch) - batch_feas = out["features"] - - # do norm - if self.config["Global"].get("feature_normalize", True): - feas_norm = paddle.sqrt( - paddle.sum(paddle.square(batch_feas), axis=1, - keepdim=True)) - batch_feas = paddle.divide(batch_feas, feas_norm) - - if all_feas is None: - all_feas = batch_feas - if has_unique_id: - all_unique_id = batch[2] - all_image_id = batch[1] - else: - all_feas = paddle.concat([all_feas, batch_feas]) - all_image_id = paddle.concat([all_image_id, batch[1]]) - if has_unique_id: - all_unique_id = paddle.concat([all_unique_id, batch[2]]) - if self.use_dali: - dataloader_tmp.reset() - if paddle.distributed.get_world_size() > 1: - feat_list = [] - img_id_list = [] - unique_id_list = [] - paddle.distributed.all_gather(feat_list, all_feas) - paddle.distributed.all_gather(img_id_list, all_image_id) - all_feas = paddle.concat(feat_list, axis=0) - all_image_id = paddle.concat(img_id_list, axis=0) - if has_unique_id: - paddle.distributed.all_gather(unique_id_list, all_unique_id) - all_unique_id = paddle.concat(unique_id_list, axis=0) - - logger.info("Build {} done, all feat shape: {}, begin to eval..". - format(name, all_feas.shape)) - return all_feas, all_image_id, all_unique_id - - @paddle.no_grad() - def infer(self, ): - total_trainer = paddle.distributed.get_world_size() - local_rank = paddle.distributed.get_rank() - image_list = get_image_list(self.config["Infer"]["infer_imgs"]) - # data split - image_list = image_list[local_rank::total_trainer] - - preprocess_func = create_operators(self.config["Infer"]["transforms"]) - postprocess_func = build_postprocess(self.config["Infer"][ - "PostProcess"]) - - batch_size = self.config["Infer"]["batch_size"] - - self.model.eval() - - batch_data = [] - image_file_list = [] - for idx, image_file in enumerate(image_list): - with open(image_file, 'rb') as f: - x = f.read() - for process in preprocess_func: - x = process(x) - batch_data.append(x) - image_file_list.append(image_file) - if len(batch_data) >= batch_size or idx == len(image_list) - 1: - batch_tensor = paddle.to_tensor(batch_data) - out = self.forward([batch_tensor]) - if isinstance(out, list): - out = out[0] - result = postprocess_func(out, image_file_list) - print(result) - batch_data.clear() - image_file_list.clear() diff --git a/tools/eval.py b/tools/eval.py index b03030c5a..367f5f8b4 100644 --- a/tools/eval.py +++ b/tools/eval.py @@ -21,11 +21,11 @@ __dir__ = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.abspath(os.path.join(__dir__, '../'))) from ppcls.utils import config -from ppcls.engine.trainer import Trainer +from ppcls.engine.core import Core if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - trainer = Trainer(config, mode="eval") - trainer.eval() + evaler = Core(config, mode="eval") + evaler.eval() diff --git a/tools/export_model.py b/tools/export_model.py index e019e2574..7d324a613 100644 --- a/tools/export_model.py +++ b/tools/export_model.py @@ -24,82 +24,11 @@ import paddle import paddle.nn as nn from ppcls.utils import config -from ppcls.utils.logger import init_logger -from ppcls.utils.config import print_config -from ppcls.arch import build_model, RecModel, DistillationModel -from ppcls.utils.save_load import load_dygraph_pretrain -from ppcls.arch.gears.identity_head import IdentityHead - - -class ExportModel(nn.Layer): - """ - ExportModel: add softmax onto the model - """ - - def __init__(self, config): - super().__init__() - self.base_model = build_model(config) - - # we should choose a final model to export - if isinstance(self.base_model, DistillationModel): - self.infer_model_name = config["infer_model_name"] - else: - self.infer_model_name = None - - self.infer_output_key = config.get("infer_output_key", None) - if self.infer_output_key == "features" and isinstance(self.base_model, - RecModel): - self.base_model.head = IdentityHead() - if config.get("infer_add_softmax", True): - self.softmax = nn.Softmax(axis=-1) - else: - self.softmax = None - - def eval(self): - self.training = False - for layer in self.sublayers(): - layer.training = False - layer.eval() - - def forward(self, x): - x = self.base_model(x) - if isinstance(x, list): - x = x[0] - if self.infer_model_name is not None: - x = x[self.infer_model_name] - if self.infer_output_key is not None: - x = x[self.infer_output_key] - if self.softmax is not None: - x = self.softmax(x) - return x - +from ppcls.engine.core import Core if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - log_file = os.path.join(config['Global']['output_dir'], - config["Arch"]["name"], "export.log") - init_logger(name='root', log_file=log_file) - print_config(config) - - # set device - assert config["Global"]["device"] in ["cpu", "gpu", "xpu"] - device = paddle.set_device(config["Global"]["device"]) - model = ExportModel(config["Arch"]) - if config["Global"]["pretrained_model"] is not None: - load_dygraph_pretrain(model.base_model, - config["Global"]["pretrained_model"]) - - model.eval() - - model = paddle.jit.to_static( - model, - input_spec=[ - paddle.static.InputSpec( - shape=[None] + config["Global"]["image_shape"], - dtype='float32') - ]) - paddle.jit.save(model, - os.path.join(config["Global"]["save_inference_dir"], - "inference")) + exporter = Core(config, mode="export") + exporter.export() diff --git a/tools/infer.py b/tools/infer.py index da23a3d88..9c00542c1 100644 --- a/tools/infer.py +++ b/tools/infer.py @@ -21,12 +21,11 @@ __dir__ = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.abspath(os.path.join(__dir__, '../'))) from ppcls.utils import config -from ppcls.engine.trainer import Trainer +from ppcls.engine.core import Core if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - trainer = Trainer(config, mode="infer") - - trainer.infer() + inferer = Core(config, mode="infer") + inferer.infer() diff --git a/tools/train.py b/tools/train.py index 169678c5a..23a064e7b 100644 --- a/tools/train.py +++ b/tools/train.py @@ -21,11 +21,11 @@ __dir__ = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.abspath(os.path.join(__dir__, '../'))) from ppcls.utils import config -from ppcls.engine.trainer import Trainer +from ppcls.engine.core import Core if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - trainer = Trainer(config, mode="train") + trainer = Core(config, mode="train") trainer.train() From 23b2332e1f40ebdfb39b0643ac89bd09b484a094 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 18:47:03 +0800 Subject: [PATCH 07/35] Create VGG16_CIFAR10_DeepHash.yaml --- .../professional/VGG16_CIFAR10_DeepHash.yaml | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml diff --git a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml new file mode 100644 index 000000000..01edcdd27 --- /dev/null +++ b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml @@ -0,0 +1,147 @@ +# global configs +Global: + checkpoints: null + pretrained_model: null + output_dir: ./output + device: gpu + save_interval: 1 + eval_during_train: True + eval_interval: 1 + eval_mode: "retrieval" + epochs: 128 + print_batch_step: 10 + use_visualdl: False + + # used for static mode and model export + image_shape: [3, 227, 227] + save_inference_dir: ./inference + + #feature postprocess + feature_normalize: False + feature_binarize: "round" + +# model architecture +Arch: + name: "RecModel" + Backbone: + name: "VGG16" + pretrained: True + class_num: 48 + Head: + name: "FC" + class_num: 10 + embedding_size: 48 + + infer_output_key: "features" + infer_add_softmax: "false" + +# loss function config for train/eval process +Loss: + Train: + - CELoss: + weight: 1.0 + epsilon: 0.1 + Eval: + - CELoss: + weight: 1.0 + +Optimizer: + name: Momentum + momentum: 0.9 + lr: + name: Piecewise + learning_rate: 0.01 + decay_epochs: [200] + values: [0.01, 0.001] + +# data loader for train and eval +DataLoader: + Train: + dataset: + name: ImageNetDataset + image_root: ./dataset/cifar10/ + cls_label_path: ./dataset/cifar10/cifar10-2/train.txt + transform_ops: + - DecodeImage: + to_rgb: True + channel_first: False + - ResizeImage: + size: 256 + - RandCropImage: + size: 227 + - RandFlipImage: + flip_code: 1 + - NormalizeImage: + scale: 1.0/255.0 + mean: [0.4914, 0.4822, 0.4465] + std: [0.2023, 0.1994, 0.2010] + order: '' + sampler: + name: DistributedBatchSampler + batch_size: 128 + drop_last: False + shuffle: True + loader: + num_workers: 4 + use_shared_memory: True + + Eval: + Query: + dataset: + name: ImageNetDataset + image_root: ./dataset/cifar10/ + cls_label_path: ./dataset/cifar10/cifar10-2/test.txt + transform_ops: + - DecodeImage: + to_rgb: True + channel_first: False + - ResizeImage: + size: 227 + - NormalizeImage: + scale: 1.0/255.0 + mean: [0.4914, 0.4822, 0.4465] + std: [0.2023, 0.1994, 0.2010] + order: '' + sampler: + name: DistributedBatchSampler + batch_size: 512 + drop_last: False + shuffle: False + loader: + num_workers: 4 + use_shared_memory: True + + Gallery: + dataset: + name: ImageNetDataset + image_root: ./dataset/cifar10/ + cls_label_path: ./dataset/cifar10/cifar10-2/database.txt + transform_ops: + - DecodeImage: + to_rgb: True + channel_first: False + - ResizeImage: + size: 227 + - NormalizeImage: + scale: 1.0/255.0 + mean: [0.4914, 0.4822, 0.4465] + std: [0.2023, 0.1994, 0.2010] + order: '' + sampler: + name: DistributedBatchSampler + batch_size: 512 + drop_last: False + shuffle: False + loader: + num_workers: 4 + use_shared_memory: True + +Metric: + Train: + - TopkAcc: + topk: [1, 5] + Eval: + - mAP: + - Precisionk: + topk: [1, 5] + From 865870f5f9fa6b3f71975a297149c576f3d47681 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 18:53:50 +0800 Subject: [PATCH 08/35] Update VGG16_CIFAR10_DeepHash.yaml --- .../quick_start/professional/VGG16_CIFAR10_DeepHash.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml index 01edcdd27..dd27df808 100644 --- a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml +++ b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml @@ -13,7 +13,7 @@ Global: use_visualdl: False # used for static mode and model export - image_shape: [3, 227, 227] + image_shape: [3, 224, 224] save_inference_dir: ./inference #feature postprocess @@ -68,7 +68,7 @@ DataLoader: - ResizeImage: size: 256 - RandCropImage: - size: 227 + size: 224 - RandFlipImage: flip_code: 1 - NormalizeImage: @@ -96,7 +96,7 @@ DataLoader: to_rgb: True channel_first: False - ResizeImage: - size: 227 + size: 224 - NormalizeImage: scale: 1.0/255.0 mean: [0.4914, 0.4822, 0.4465] From d963dc17daedc3da9e0bfaae17d5f96461b211d3 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:06:49 +0800 Subject: [PATCH 09/35] Update VGG16_CIFAR10_DeepHash.yaml --- .../quick_start/professional/VGG16_CIFAR10_DeepHash.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml index dd27df808..6ab045f4f 100644 --- a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml +++ b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml @@ -24,7 +24,7 @@ Global: Arch: name: "RecModel" Backbone: - name: "VGG16" + name: "VGG19" pretrained: True class_num: 48 Head: From 0b9f0ad0014f7912c21f291a07c7d9e0b5ade01c Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:07:35 +0800 Subject: [PATCH 10/35] Create vgg_variant.py --- .../backbone/variant_models/vgg_variant.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 ppcls/arch/backbone/variant_models/vgg_variant.py diff --git a/ppcls/arch/backbone/variant_models/vgg_variant.py b/ppcls/arch/backbone/variant_models/vgg_variant.py new file mode 100644 index 000000000..ac6c0138e --- /dev/null +++ b/ppcls/arch/backbone/variant_models/vgg_variant.py @@ -0,0 +1,28 @@ +import paddle +from paddle.nn import Sigmoid +from ppcls.arch.backbone.legendary_models.vgg import VGG19 + +__all__ = ["VGG19Sigmoid"] + + +class SigmoidSuffix(paddle.nn.Layer): + def __init__(self, origin_layer): + super(SigmoidSuffix, self).__init__() + self.origin_layer = origin_layer + self.sigmoid = Sigmoid() + + def forward(self, *input, res_dict=None, **kwargs): + x = self.origin_layer(input) + x = self.sigmoid(x) + return x + + +def VGG19Sigmoid(pretrained=False, use_ssld=False, **kwargs): + def replace_function(origin_layer): + new_layer = SigmoidSuffix(origin_layer) + return new_layer + + match_re = "linear_2" + model = VGG19(pretrained=pretrained, use_ssld=use_ssld, **kwargs) + model.replace_sub(match_re, replace_function, True) + return model From 26eda0efef2a7db993d7abcd7b2a96ed328dff08 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:08:06 +0800 Subject: [PATCH 11/35] Update __init__.py --- ppcls/arch/backbone/variant_models/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ppcls/arch/backbone/variant_models/__init__.py b/ppcls/arch/backbone/variant_models/__init__.py index e87a0e098..34fcdeb2c 100644 --- a/ppcls/arch/backbone/variant_models/__init__.py +++ b/ppcls/arch/backbone/variant_models/__init__.py @@ -1 +1,2 @@ from .resnet_variant import ResNet50_last_stage_stride1 +from .vgg_variant import VGG19Sigmoid From 581af23ac6a5000e1080c6387c2def96424df837 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:08:53 +0800 Subject: [PATCH 12/35] Update VGG16_CIFAR10_DeepHash.yaml --- .../quick_start/professional/VGG16_CIFAR10_DeepHash.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml index 6ab045f4f..d6722d5df 100644 --- a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml +++ b/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml @@ -24,7 +24,7 @@ Global: Arch: name: "RecModel" Backbone: - name: "VGG19" + name: "VGG19Sigmoid" pretrained: True class_num: 48 Head: From f878fb27e5a1a3f312bf7820dfa783e7f384128e Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:19:19 +0800 Subject: [PATCH 13/35] Update __init__.py --- ppcls/arch/backbone/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ppcls/arch/backbone/__init__.py b/ppcls/arch/backbone/__init__.py index 1923b0993..a1727613a 100644 --- a/ppcls/arch/backbone/__init__.py +++ b/ppcls/arch/backbone/__init__.py @@ -58,6 +58,7 @@ from ppcls.arch.backbone.model_zoo.rednet import RedNet26, RedNet38, RedNet50, R from ppcls.arch.backbone.model_zoo.tnt import TNT_small from ppcls.arch.backbone.model_zoo.hardnet import HarDNet68, HarDNet85, HarDNet39_ds, HarDNet68_ds from ppcls.arch.backbone.variant_models.resnet_variant import ResNet50_last_stage_stride1 +from ppcls.arch.backbone.variant_models.vgg_variant import VGG19Sigmoid def get_apis(): From 2f85378bb61c30ceef8595f66e8380cf4659db8a Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:23:47 +0800 Subject: [PATCH 14/35] Rename VGG16_CIFAR10_DeepHash.yaml to VGG19_CIFAR10_DeepHash.yaml --- .../{VGG16_CIFAR10_DeepHash.yaml => VGG19_CIFAR10_DeepHash.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ppcls/configs/quick_start/professional/{VGG16_CIFAR10_DeepHash.yaml => VGG19_CIFAR10_DeepHash.yaml} (100%) diff --git a/ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml b/ppcls/configs/quick_start/professional/VGG19_CIFAR10_DeepHash.yaml similarity index 100% rename from ppcls/configs/quick_start/professional/VGG16_CIFAR10_DeepHash.yaml rename to ppcls/configs/quick_start/professional/VGG19_CIFAR10_DeepHash.yaml From 0354f4457412db633138773dea82acc6df5c072b Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:29:39 +0800 Subject: [PATCH 15/35] Update metrics.py --- ppcls/metric/metrics.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/ppcls/metric/metrics.py b/ppcls/metric/metrics.py index 9908b3541..204d2af09 100644 --- a/ppcls/metric/metrics.py +++ b/ppcls/metric/metrics.py @@ -168,6 +168,47 @@ class Recallk(nn.Layer): return metric_dict +class Precisionk(nn.Layer): + def __init__(self, topk=(1, 5)): + super().__init__() + assert isinstance(topk, (int, list, tuple)) + if isinstance(topk, int): + topk = [topk] + self.topk = topk + + def forward(self, similarities_matrix, query_img_id, gallery_img_id, + keep_mask): + metric_dict = dict() + + #get cmc + choosen_indices = paddle.argsort( + similarities_matrix, axis=1, descending=True) + gallery_labels_transpose = paddle.transpose(gallery_img_id, [1, 0]) + gallery_labels_transpose = paddle.broadcast_to( + gallery_labels_transpose, + shape=[ + choosen_indices.shape[0], gallery_labels_transpose.shape[1] + ]) + choosen_label = paddle.index_sample(gallery_labels_transpose, + choosen_indices) + equal_flag = paddle.equal(choosen_label, query_img_id) + if keep_mask is not None: + keep_mask = paddle.index_sample( + keep_mask.astype('float32'), choosen_indices) + equal_flag = paddle.logical_and(equal_flag, + keep_mask.astype('bool')) + equal_flag = paddle.cast(equal_flag, 'float32') + + Ns = paddle.arange(gallery_img_id.shape[0]) + 1 + equal_flag_cumsum = paddle.cumsum(equal_flag, axis=1) + Precision_at_k = (paddle.mean(equal_flag_cumsum, axis=0) / Ns).numpy() + + for k in self.topk: + metric_dict["precision@{}".format(k)] = Precision_at_k[k - 1] + + return metric_dict + + class DistillationTopkAcc(TopkAcc): def __init__(self, model_key, feature_key=None, topk=(1, 5)): super().__init__(topk=topk) From a804bb02bd6d55b14be05c65c33843e2bded82b2 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:32:35 +0800 Subject: [PATCH 16/35] Update VGG19_CIFAR10_DeepHash.yaml --- .../quick_start/professional/VGG19_CIFAR10_DeepHash.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppcls/configs/quick_start/professional/VGG19_CIFAR10_DeepHash.yaml b/ppcls/configs/quick_start/professional/VGG19_CIFAR10_DeepHash.yaml index d6722d5df..97228828a 100644 --- a/ppcls/configs/quick_start/professional/VGG19_CIFAR10_DeepHash.yaml +++ b/ppcls/configs/quick_start/professional/VGG19_CIFAR10_DeepHash.yaml @@ -121,7 +121,7 @@ DataLoader: to_rgb: True channel_first: False - ResizeImage: - size: 227 + size: 224 - NormalizeImage: scale: 1.0/255.0 mean: [0.4914, 0.4822, 0.4465] From 34d9c8593e9865d530955ca46a568419a6c52045 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Mon, 23 Aug 2021 19:45:44 +0800 Subject: [PATCH 17/35] Update __init__.py --- ppcls/metric/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppcls/metric/__init__.py b/ppcls/metric/__init__.py index db80bab61..4c817a115 100644 --- a/ppcls/metric/__init__.py +++ b/ppcls/metric/__init__.py @@ -16,7 +16,7 @@ from paddle import nn import copy from collections import OrderedDict -from .metrics import TopkAcc, mAP, mINP, Recallk +from .metrics import TopkAcc, mAP, mINP, Recallk, Precisionk from .metrics import DistillationTopkAcc from .metrics import GoogLeNetTopkAcc From c9912f0a04e7706fcdacfdef43ee83454b58f1f7 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Tue, 24 Aug 2021 10:53:13 +0800 Subject: [PATCH 18/35] Update vgg_variant.py --- ppcls/arch/backbone/variant_models/vgg_variant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppcls/arch/backbone/variant_models/vgg_variant.py b/ppcls/arch/backbone/variant_models/vgg_variant.py index ac6c0138e..b73ad3592 100644 --- a/ppcls/arch/backbone/variant_models/vgg_variant.py +++ b/ppcls/arch/backbone/variant_models/vgg_variant.py @@ -11,7 +11,7 @@ class SigmoidSuffix(paddle.nn.Layer): self.origin_layer = origin_layer self.sigmoid = Sigmoid() - def forward(self, *input, res_dict=None, **kwargs): + def forward(self, input, res_dict=None, **kwargs): x = self.origin_layer(input) x = self.sigmoid(x) return x From 15f6f5813914b02644aab39f791dd9cc1940994c Mon Sep 17 00:00:00 2001 From: dongshuilong Date: Tue, 24 Aug 2021 03:02:55 +0000 Subject: [PATCH 19/35] refactor trainer v2 --- ppcls/engine/{core.py => engine.py} | 25 +++--- ppcls/engine/{eval => evaluation}/__init__.py | 4 +- .../{eval => evaluation}/classification.py | 0 .../engine/{eval => evaluation}/retrieval.py | 0 ppcls/engine/train/__init__.py | 3 +- ppcls/engine/train/classification.py | 89 ------------------- ppcls/engine/train/{retrieval.py => train.py} | 13 ++- tools/eval.py | 6 +- tools/export_model.py | 6 +- tools/infer.py | 6 +- tools/train.py | 6 +- 11 files changed, 34 insertions(+), 124 deletions(-) rename ppcls/engine/{core.py => engine.py} (95%) rename ppcls/engine/{eval => evaluation}/__init__.py (82%) rename ppcls/engine/{eval => evaluation}/classification.py (100%) rename ppcls/engine/{eval => evaluation}/retrieval.py (100%) delete mode 100644 ppcls/engine/train/classification.py rename ppcls/engine/train/{retrieval.py => train.py} (90%) diff --git a/ppcls/engine/core.py b/ppcls/engine/engine.py similarity index 95% rename from ppcls/engine/core.py rename to ppcls/engine/engine.py index d0e448d71..711ec3b70 100644 --- a/ppcls/engine/core.py +++ b/ppcls/engine/engine.py @@ -47,19 +47,18 @@ from ppcls.utils import save_load from ppcls.data.utils.get_image_list import get_image_list from ppcls.data.postprocess import build_postprocess from ppcls.data import create_operators -from ppcls.engine.train import classification_train, retrieval_train -from ppcls.engine.eval import classification_eval, retrieval_eval +from ppcls.engine.train import train_epoch +from ppcls.engine import evaluation from ppcls.arch.gears.identity_head import IdentityHead -class Core(object): +class Engine(object): def __init__(self, config, mode="train"): - assert mode in ['train', 'eval', 'infer', 'export'] + assert mode in ["train", "eval", "infer", "export"] self.mode = mode self.config = config self.eval_mode = self.config["Global"].get("eval_mode", "classification") - # init logger self.output_dir = self.config['Global']['output_dir'] log_file = os.path.join(self.output_dir, self.config["Arch"]["name"], @@ -68,14 +67,10 @@ class Core(object): print_config(config) # init train_func and eval_func - if self.eval_mode == "classification": - self.evaler = classification_eval - self.trainer = classification_train - elif self.eval_mode == "retrieval": - self.trainer = retrieval_train - self.evaler = retrieval_eval - else: - logger.warning("Invalid eval mode: {}".format(self.eval_mode)) + assert self.eval_mode in ["classification", "retrieval"], logger.error("Invalid eval mode: {}".format(self.eval_mode)) + self.train_epoch_func = train_epoch + self.eval_func = getattr(evaluation, self.eval_mode + "_eval") + self.use_dali = self.config['Global'].get("use_dali", False) # for visualdl @@ -242,7 +237,7 @@ class Core(object): self.config["Global"]["epochs"] + 1): acc = 0.0 # for one epoch train - self.trainer(self, epoch_id, print_batch_step) + self.train_epoch_func(self, epoch_id, print_batch_step) if self.use_dali: self.train_dataloader.reset() @@ -304,7 +299,7 @@ class Core(object): def eval(self, epoch_id=0): assert self.mode in ["train", "eval"] self.model.eval() - eval_result = self.evaler(self, epoch_id) + eval_result = self.eval_func(self, epoch_id) self.model.train() return eval_result diff --git a/ppcls/engine/eval/__init__.py b/ppcls/engine/evaluation/__init__.py similarity index 82% rename from ppcls/engine/eval/__init__.py rename to ppcls/engine/evaluation/__init__.py index 0cc0dc983..e0cd77888 100644 --- a/ppcls/engine/eval/__init__.py +++ b/ppcls/engine/evaluation/__init__.py @@ -12,5 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ppcls.engine.eval.classification import classification_eval -from ppcls.engine.eval.retrieval import retrieval_eval +from ppcls.engine.evaluation.classification import classification_eval +from ppcls.engine.evaluation.retrieval import retrieval_eval diff --git a/ppcls/engine/eval/classification.py b/ppcls/engine/evaluation/classification.py similarity index 100% rename from ppcls/engine/eval/classification.py rename to ppcls/engine/evaluation/classification.py diff --git a/ppcls/engine/eval/retrieval.py b/ppcls/engine/evaluation/retrieval.py similarity index 100% rename from ppcls/engine/eval/retrieval.py rename to ppcls/engine/evaluation/retrieval.py diff --git a/ppcls/engine/train/__init__.py b/ppcls/engine/train/__init__.py index 897c5846d..800d3a41e 100644 --- a/ppcls/engine/train/__init__.py +++ b/ppcls/engine/train/__init__.py @@ -11,5 +11,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from ppcls.engine.train.classification import classification_train -from ppcls.engine.train.retrieval import retrieval_train +from ppcls.engine.train.train import train_epoch diff --git a/ppcls/engine/train/classification.py b/ppcls/engine/train/classification.py deleted file mode 100644 index c3d74f962..000000000 --- a/ppcls/engine/train/classification.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from __future__ import absolute_import, division, print_function - -import datetime -import os -import platform -import sys -import time - -import numpy as np -import paddle - -__dir__ = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) -from ppcls.utils import logger -from ppcls.utils.misc import AverageMeter -from ppcls.engine.train.utils import update_loss, update_metric, log_info - - -def classification_train(trainer, epoch_id, print_batch_step): - tic = time.time() - - train_dataloader = trainer.train_dataloader if trainer.use_dali else trainer.train_dataloader( - ) - for iter_id, batch in enumerate(train_dataloader): - if iter_id >= trainer.max_iter: - break - if iter_id == 5: - for key in trainer.time_info: - trainer.time_info[key].reset() - trainer.time_info["reader_cost"].update(time.time() - tic) - if trainer.use_dali: - batch = [ - paddle.to_tensor(batch[0]['data']), - paddle.to_tensor(batch[0]['label']) - ] - batch_size = batch[0].shape[0] - batch[1] = batch[1].reshape([-1, 1]).astype("int64") - - trainer.global_step += 1 - # image input - if trainer.amp: - with paddle.amp.auto_cast(custom_black_list={ - "flatten_contiguous_range", "greater_than" - }): - out = trainer.model(batch[0]) - loss_dict = trainer.train_loss_func(out, batch[1]) - else: - out = trainer.model(batch[0]) - - # calc loss - if trainer.config["DataLoader"]["Train"]["dataset"].get( - "batch_transform_ops", None): - loss_dict = trainer.train_loss_func(out, batch[1:]) - else: - loss_dict = trainer.train_loss_func(out, batch[1]) - - # step opt and lr - if trainer.amp: - scaled = trainer.scaler.scale(loss_dict["loss"]) - scaled.backward() - trainer.scaler.minimize(trainer.optimizer, scaled) - else: - loss_dict["loss"].backward() - trainer.optimizer.step() - trainer.optimizer.clear_grad() - trainer.lr_sch.step() - - # below code just for logging - # update metric_for_logger - update_metric(trainer, out, batch, batch_size) - # update_loss_for_logger - update_loss(trainer, loss_dict, batch_size) - trainer.time_info["batch_cost"].update(time.time() - tic) - if iter_id % print_batch_step == 0: - log_info(trainer, batch_size, epoch_id, iter_id) - tic = time.time() diff --git a/ppcls/engine/train/retrieval.py b/ppcls/engine/train/train.py similarity index 90% rename from ppcls/engine/train/retrieval.py rename to ppcls/engine/train/train.py index d4a994597..9ea173a9e 100644 --- a/ppcls/engine/train/retrieval.py +++ b/ppcls/engine/train/train.py @@ -29,7 +29,7 @@ from ppcls.utils.misc import AverageMeter from ppcls.engine.train.utils import update_loss, update_metric, log_info -def retrieval_train(trainer, epoch_id, print_batch_step): +def train_epoch(trainer, epoch_id, print_batch_step): tic = time.time() train_dataloader = trainer.train_dataloader if trainer.use_dali else trainer.train_dataloader( @@ -55,10 +55,10 @@ def retrieval_train(trainer, epoch_id, print_batch_step): with paddle.amp.auto_cast(custom_black_list={ "flatten_contiguous_range", "greater_than" }): - out = trainer.model(batch[0], batch[1]) + out = forward(trainer, batch) loss_dict = trainer.train_loss_func(out, batch[1]) else: - out = trainer.model(batch[0], batch[1]) + out = forward(trainer, batch) # calc loss if trainer.config["DataLoader"]["Train"]["dataset"].get( @@ -81,10 +81,15 @@ def retrieval_train(trainer, epoch_id, print_batch_step): # below code just for logging # update metric_for_logger update_metric(trainer, out, batch, batch_size) - # update_loss_for_logger update_loss(trainer, loss_dict, batch_size) trainer.time_info["batch_cost"].update(time.time() - tic) if iter_id % print_batch_step == 0: log_info(trainer, batch_size, epoch_id, iter_id) tic = time.time() + +def forward(trainer, batch): + if trainer.eval_mode == "classification": + return trainer.model(batch[0]) + else: + return trainer.model(batch[0], batch[1]) diff --git a/tools/eval.py b/tools/eval.py index 367f5f8b4..e086da1b5 100644 --- a/tools/eval.py +++ b/tools/eval.py @@ -21,11 +21,11 @@ __dir__ = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.abspath(os.path.join(__dir__, '../'))) from ppcls.utils import config -from ppcls.engine.core import Core +from ppcls.engine.engine import Engine if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - evaler = Core(config, mode="eval") - evaler.eval() + engine = Engine(config, mode="eval") + engine.eval() diff --git a/tools/export_model.py b/tools/export_model.py index 7d324a613..01aba06c1 100644 --- a/tools/export_model.py +++ b/tools/export_model.py @@ -24,11 +24,11 @@ import paddle import paddle.nn as nn from ppcls.utils import config -from ppcls.engine.core import Core +from ppcls.engine.engine import Engine if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - exporter = Core(config, mode="export") - exporter.export() + engine = Engine(config, mode="export") + engine.export() diff --git a/tools/infer.py b/tools/infer.py index 9c00542c1..4f6bf9272 100644 --- a/tools/infer.py +++ b/tools/infer.py @@ -21,11 +21,11 @@ __dir__ = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.abspath(os.path.join(__dir__, '../'))) from ppcls.utils import config -from ppcls.engine.core import Core +from ppcls.engine.engine import Engine if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - inferer = Core(config, mode="infer") - inferer.infer() + engine = Engine(config, mode="infer") + engine.infer() diff --git a/tools/train.py b/tools/train.py index 23a064e7b..1d8359036 100644 --- a/tools/train.py +++ b/tools/train.py @@ -21,11 +21,11 @@ __dir__ = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.abspath(os.path.join(__dir__, '../'))) from ppcls.utils import config -from ppcls.engine.core import Core +from ppcls.engine.engine import Engine if __name__ == "__main__": args = config.parse_args() config = config.get_config( args.config, overrides=args.override, show=False) - trainer = Core(config, mode="train") - trainer.train() + engine = Engine(config, mode="train") + engine.train() From 8c8153e97fdc15f1e8f6fd3429373dd8570fba2a Mon Sep 17 00:00:00 2001 From: cuicheng01 Date: Tue, 24 Aug 2021 03:22:03 +0000 Subject: [PATCH 20/35] Update SwinTransformer pretrained url --- ppcls/arch/backbone/model_zoo/swin_transformer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ppcls/arch/backbone/model_zoo/swin_transformer.py b/ppcls/arch/backbone/model_zoo/swin_transformer.py index f4348fbae..8ce810c2f 100644 --- a/ppcls/arch/backbone/model_zoo/swin_transformer.py +++ b/ppcls/arch/backbone/model_zoo/swin_transformer.py @@ -33,9 +33,9 @@ MODEL_URLS = { "SwinTransformer_base_patch4_window12_384": "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/SwinTransformer_base_patch4_window12_384_pretrained.pdparams", "SwinTransformer_large_patch4_window7_224": - "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/SwinTransformer_large_patch4_window7_224_pretrained.pdparams", + "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/SwinTransformer_large_patch4_window7_224_22kto1k_pretrained.pdparams", "SwinTransformer_large_patch4_window12_384": - "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/SwinTransformer_large_patch4_window12_384_pretrained.pdparams", + "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/SwinTransformer_large_patch4_window12_384_22kto1k_pretrained.pdparams", } __all__ = list(MODEL_URLS.keys()) From 5bf74beb46533152b76cf59e891bafb0ec402cd2 Mon Sep 17 00:00:00 2001 From: dongshuilong Date: Tue, 24 Aug 2021 07:07:17 +0000 Subject: [PATCH 21/35] update according comments --- deploy/auto_log.log | 0 ppcls/engine/engine.py | 15 ++++----------- ppcls/engine/evaluation/classification.py | 8 ++------ ppcls/engine/evaluation/retrieval.py | 8 +------- ppcls/engine/train/train.py | 12 +----------- ppcls/engine/train/utils.py | 10 ---------- 6 files changed, 8 insertions(+), 45 deletions(-) delete mode 100644 deploy/auto_log.log diff --git a/deploy/auto_log.log b/deploy/auto_log.log deleted file mode 100644 index e69de29bb..000000000 diff --git a/ppcls/engine/engine.py b/ppcls/engine/engine.py index 711ec3b70..ad5c584f0 100644 --- a/ppcls/engine/engine.py +++ b/ppcls/engine/engine.py @@ -13,21 +13,13 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function + import os -import sys -import numpy as np - -__dir__ = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(__dir__, '../../'))) - -import time import platform -import datetime -import argparse import paddle -import paddle.nn as nn import paddle.distributed as dist from visualdl import LogWriter +from paddle import nn from ppcls.utils.check import check_gpu from ppcls.utils.misc import AverageMeter @@ -67,7 +59,8 @@ class Engine(object): print_config(config) # init train_func and eval_func - assert self.eval_mode in ["classification", "retrieval"], logger.error("Invalid eval mode: {}".format(self.eval_mode)) + assert self.eval_mode in ["classification", "retrieval"], logger.error( + "Invalid eval mode: {}".format(self.eval_mode)) self.train_epoch_func = train_epoch self.eval_func = getattr(evaluation, self.eval_mode + "_eval") diff --git a/ppcls/engine/evaluation/classification.py b/ppcls/engine/evaluation/classification.py index 38be7cd3f..b1ddc4186 100644 --- a/ppcls/engine/evaluation/classification.py +++ b/ppcls/engine/evaluation/classification.py @@ -14,14 +14,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import os -import sys import time import platform import paddle -__dir__ = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) from ppcls.utils.misc import AverageMeter from ppcls.utils import logger @@ -61,14 +57,14 @@ def classification_eval(evaler, epoch_id=0): out = evaler.model(batch[0]) # calc loss if evaler.eval_loss_func is not None: - loss_dict = evaler.eval_loss_func(out, batch[-1]) + loss_dict = evaler.eval_loss_func(out, batch[1]) for key in loss_dict: if key not in output_info: output_info[key] = AverageMeter(key, '7.5f') output_info[key].update(loss_dict[key].numpy()[0], batch_size) # calc metric if evaler.eval_metric_func is not None: - metric_dict = evaler.eval_metric_func(out, batch[-1]) + metric_dict = evaler.eval_metric_func(out, batch[1]) if paddle.distributed.get_world_size() > 1: for key in metric_dict: paddle.distributed.all_reduce( diff --git a/ppcls/engine/evaluation/retrieval.py b/ppcls/engine/evaluation/retrieval.py index ccba31754..c0da3ace2 100644 --- a/ppcls/engine/evaluation/retrieval.py +++ b/ppcls/engine/evaluation/retrieval.py @@ -14,15 +14,9 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import os -import sys -import time + import platform import paddle - -__dir__ = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) -from ppcls.utils.misc import AverageMeter from ppcls.utils import logger diff --git a/ppcls/engine/train/train.py b/ppcls/engine/train/train.py index 9ea173a9e..9e36a063e 100644 --- a/ppcls/engine/train/train.py +++ b/ppcls/engine/train/train.py @@ -13,19 +13,8 @@ # limitations under the License. from __future__ import absolute_import, division, print_function -import datetime -import os -import platform -import sys import time - -import numpy as np import paddle - -__dir__ = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) -from ppcls.utils import logger -from ppcls.utils.misc import AverageMeter from ppcls.engine.train.utils import update_loss, update_metric, log_info @@ -88,6 +77,7 @@ def train_epoch(trainer, epoch_id, print_batch_step): log_info(trainer, batch_size, epoch_id, iter_id) tic = time.time() + def forward(trainer, batch): if trainer.eval_mode == "classification": return trainer.model(batch[0]) diff --git a/ppcls/engine/train/utils.py b/ppcls/engine/train/utils.py index f4cbce97e..b82694f31 100644 --- a/ppcls/engine/train/utils.py +++ b/ppcls/engine/train/utils.py @@ -14,16 +14,6 @@ from __future__ import absolute_import, division, print_function import datetime -import os -import platform -import sys -import time - -import numpy as np -import paddle - -__dir__ = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(__dir__, '../../../'))) from ppcls.utils import logger from ppcls.utils.misc import AverageMeter From 5b70d442f9b26f79fbb46779eaf4e33b6a787cd3 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Tue, 24 Aug 2021 16:19:41 +0800 Subject: [PATCH 22/35] Update circlemargin.py --- ppcls/arch/gears/circlemargin.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ppcls/arch/gears/circlemargin.py b/ppcls/arch/gears/circlemargin.py index 65967d0d7..87baee839 100644 --- a/ppcls/arch/gears/circlemargin.py +++ b/ppcls/arch/gears/circlemargin.py @@ -28,7 +28,7 @@ class CircleMargin(nn.Layer): weight_attr = paddle.ParamAttr( initializer=paddle.nn.initializer.XavierNormal()) - self.fc0 = paddle.nn.Linear( + self.fc = paddle.nn.Linear( self.embedding_size, self.class_num, weight_attr=weight_attr) def forward(self, input, label): @@ -36,19 +36,22 @@ class CircleMargin(nn.Layer): paddle.sum(paddle.square(input), axis=1, keepdim=True)) input = paddle.divide(input, feat_norm) - weight = self.fc0.weight + weight = self.fc.weight weight_norm = paddle.sqrt( paddle.sum(paddle.square(weight), axis=0, keepdim=True)) weight = paddle.divide(weight, weight_norm) logits = paddle.matmul(input, weight) + if not self.training or label is None: + return logits alpha_p = paddle.clip(-logits.detach() + 1 + self.margin, min=0.) alpha_n = paddle.clip(logits.detach() + self.margin, min=0.) delta_p = 1 - self.margin delta_n = self.margin - index = paddle.fluid.layers.where(label != -1).reshape([-1]) + m_hot = F.one_hot(label.reshape([-1]), num_classes=logits.shape[1]) + logits_p = alpha_p * (logits - delta_p) logits_n = alpha_n * (logits - delta_n) pre_logits = logits_p * m_hot + logits_n * (1 - m_hot) From 860e4aa42182acc9fa4eefb054bce063543a2257 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Tue, 24 Aug 2021 16:20:21 +0800 Subject: [PATCH 23/35] Update cosmargin.py --- ppcls/arch/gears/cosmargin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ppcls/arch/gears/cosmargin.py b/ppcls/arch/gears/cosmargin.py index 51db55086..378e102a2 100644 --- a/ppcls/arch/gears/cosmargin.py +++ b/ppcls/arch/gears/cosmargin.py @@ -46,6 +46,9 @@ class CosMargin(paddle.nn.Layer): weight = paddle.divide(weight, weight_norm) cos = paddle.matmul(input, weight) + if not self.training or label is None: + return cos + cos_m = cos - self.margin one_hot = paddle.nn.functional.one_hot(label, self.class_num) From 60ef76b1b15f6051553dc054abf0966fba53ba21 Mon Sep 17 00:00:00 2001 From: lyuwenyu Date: Wed, 25 Aug 2021 13:20:40 +0800 Subject: [PATCH 24/35] add logger init --- hubconf.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hubconf.py b/hubconf.py index d615a905d..b7f76745a 100644 --- a/hubconf.py +++ b/hubconf.py @@ -41,10 +41,15 @@ class _SysPathG(object): self.path) -with _SysPathG( - os.path.join( - os.path.dirname(os.path.abspath(__file__)), 'ppcls', 'arch')): - import backbone +with _SysPathG(os.path.dirname(os.path.abspath(__file__)), ): + import ppcls + import ppcls.arch.backbone as backbone + + def ppclas_init(): + if ppcls.utils.logger._logger is None: + ppcls.utils.logger.init_logger() + + ppclas_init() def _load_pretrained_parameters(model, name): url = 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/{}_pretrained.pdparams'.format( From 52663edf603d9f2a1cbe96f2cbb8fabc95d5eaab Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Wed, 25 Aug 2021 13:57:24 +0800 Subject: [PATCH 25/35] Update retrieval.py --- ppcls/engine/evaluation/retrieval.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ppcls/engine/evaluation/retrieval.py b/ppcls/engine/evaluation/retrieval.py index c0da3ace2..cd8830a55 100644 --- a/ppcls/engine/evaluation/retrieval.py +++ b/ppcls/engine/evaluation/retrieval.py @@ -124,6 +124,13 @@ def cal_feature(evaler, name='gallery'): feas_norm = paddle.sqrt( paddle.sum(paddle.square(batch_feas), axis=1, keepdim=True)) batch_feas = paddle.divide(batch_feas, feas_norm) + + # do binarize + if self.config["Global"].get("feature_binarize") == "round": + batch_feas = paddle.round(batch_feas).astype("float32") * 2.0 - 1.0 + + if self.config["Global"].get("feature_binarize") == "sign": + batch_feas = paddle.sign(batch_feas).astype("float32") if all_feas is None: all_feas = batch_feas @@ -135,8 +142,10 @@ def cal_feature(evaler, name='gallery'): all_image_id = paddle.concat([all_image_id, batch[1]]) if has_unique_id: all_unique_id = paddle.concat([all_unique_id, batch[2]]) + if evaler.use_dali: dataloader_tmp.reset() + if paddle.distributed.get_world_size() > 1: feat_list = [] img_id_list = [] From 9323b1478a07f0356682b447ea19d11285bf04ed Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Wed, 25 Aug 2021 13:59:54 +0800 Subject: [PATCH 26/35] Create deephashloss.py --- ppcls/loss/deephashloss.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ppcls/loss/deephashloss.py diff --git a/ppcls/loss/deephashloss.py b/ppcls/loss/deephashloss.py new file mode 100644 index 000000000..8f02a3ba0 --- /dev/null +++ b/ppcls/loss/deephashloss.py @@ -0,0 +1,6 @@ + # do binarize + if self.config["Global"].get("feature_binarize") == "round": + batch_feas = paddle.round(batch_feas).astype("float32") * 2.0 - 1.0 + + if self.config["Global"].get("feature_binarize") == "sign": + batch_feas = paddle.sign(batch_feas).astype("float32") From e732d40a45e4785ce439f1dc85d4aed93707cee6 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Wed, 25 Aug 2021 14:00:21 +0800 Subject: [PATCH 27/35] Update deephashloss.py --- ppcls/loss/deephashloss.py | 63 +++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/ppcls/loss/deephashloss.py b/ppcls/loss/deephashloss.py index 8f02a3ba0..b70936994 100644 --- a/ppcls/loss/deephashloss.py +++ b/ppcls/loss/deephashloss.py @@ -1,6 +1,59 @@ - # do binarize - if self.config["Global"].get("feature_binarize") == "round": - batch_feas = paddle.round(batch_feas).astype("float32") * 2.0 - 1.0 +#copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve. +# +#Licensed under the Apache License, Version 2.0 (the "License"); +#you may not use this file except in compliance with the License. +#You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +#Unless required by applicable law or agreed to in writing, software +#distributed under the License is distributed on an "AS IS" BASIS, +#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#See the License for the specific language governing permissions and +#limitations under the License. + +import paddle +import paddle.nn as nn + +class DSHSDLoss(nn.Layer): + """ + # DSHSD(IEEE ACCESS 2019) + # paper [Deep Supervised Hashing Based on Stable Distribution](https://ieeexplore.ieee.org/document/8648432/) + # [DSHSD] epoch:70, bit:48, dataset:cifar10-1, MAP:0.809, Best MAP: 0.809 + # [DSHSD] epoch:250, bit:48, dataset:nuswide_21, MAP:0.809, Best MAP: 0.815 + # [DSHSD] epoch:135, bit:48, dataset:imagenet, MAP:0.647, Best MAP: 0.647 + """ + def __init__(self, n_class, bit, alpha, multi_label=False): + super(DSHSDLoss, self).__init__() + self.m = 2 * bit + self.alpha = alpha + self.multi_label = multi_label + self.n_class = n_class + self.fc = paddle.nn.Linear(bit, n_class, bias_attr=False) + + def forward(self, input, label): + feature = input["features"] + feature = feature.tanh().astype("float32") + + dist = paddle.sum( + paddle.square((paddle.unsqueeze(feature, 1) - paddle.unsqueeze(feature, 0))), + axis=2) + + # label to ont-hot + label = paddle.flatten(label) + label = paddle.nn.functional.one_hot(label, self.n_class).astype("float32") + + s = (paddle.matmul(label, label, transpose_y=True) == 0).astype("float32") + Ld = (1 - s) / 2 * dist + s / 2 * (self.m - dist).clip(min=0) + Ld = Ld.mean() + + logits = self.fc(feature) + if self.multi_label: + # multiple labels classification loss + Lc = (logits - label * logits + ((1 + (-logits).exp()).log())).sum(axis=1).mean() + else: + # single labels classification loss + Lc = (-paddle.nn.functional.softmax(logits).log() * label).sum(axis=1).mean() + + return {"dshsdloss": Lc + Ld * self.alpha} - if self.config["Global"].get("feature_binarize") == "sign": - batch_feas = paddle.sign(batch_feas).astype("float32") From d9ca31a694db44913efdddcff97cf5097a6cf8c6 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Wed, 25 Aug 2021 14:04:50 +0800 Subject: [PATCH 28/35] Update deephashloss.py --- ppcls/loss/deephashloss.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ppcls/loss/deephashloss.py b/ppcls/loss/deephashloss.py index b70936994..49dc3b260 100644 --- a/ppcls/loss/deephashloss.py +++ b/ppcls/loss/deephashloss.py @@ -57,3 +57,35 @@ class DSHSDLoss(nn.Layer): return {"dshsdloss": Lc + Ld * self.alpha} +class LCDSHLoss(paddle.nn.Layer): + """ + # paper [Locality-Constrained Deep Supervised Hashing for Image Retrieval](https://www.ijcai.org/Proceedings/2017/0499.pdf) + # [LCDSH] epoch:145, bit:48, dataset:cifar10-1, MAP:0.798, Best MAP: 0.798 + # [LCDSH] epoch:183, bit:48, dataset:nuswide_21, MAP:0.833, Best MAP: 0.834 + """ + def __init__(self, n_class, _lambda): + super(LCDSHLoss, self).__init__() + self._lambda = _lambda + self.n_class = n_class + + def forward(self, input, label): + feature = input["features"] + label = label.astype("float32") + + # label to ont-hot + label = paddle.flatten(label) + label = paddle.nn.functional.one_hot(label, self.n_class).astype("float32") + + s = 2 * (paddle.matmul(label, label, transpose_y=True) > 0).astype("float32") - 1 + inner_product = paddle.matmul(feature, feature, transpose_y=True) * 0.5 + + inner_product = inner_product.clip(min=-50, max=50) + L1 = paddle.log(1 + paddle.exp(-s * inner_product)).mean() + + b = feature.sign() + inner_product_ = paddle.matmul(b, b, transpose_y=True) * 0.5 + sigmoid = paddle.nn.Sigmoid() + L2 = (sigmoid(inner_product) - sigmoid(inner_product_)).pow(2).mean() + + return {"lcdshloss": L1 + self._lambda * L2} + From 3de99430c0858d138869a98bd7d66671e86a683e Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Wed, 25 Aug 2021 14:06:54 +0800 Subject: [PATCH 29/35] Update deephashloss.py --- ppcls/loss/deephashloss.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppcls/loss/deephashloss.py b/ppcls/loss/deephashloss.py index 49dc3b260..7d4efad16 100644 --- a/ppcls/loss/deephashloss.py +++ b/ppcls/loss/deephashloss.py @@ -57,7 +57,7 @@ class DSHSDLoss(nn.Layer): return {"dshsdloss": Lc + Ld * self.alpha} -class LCDSHLoss(paddle.nn.Layer): +class LCDSHLoss(nn.Layer): """ # paper [Locality-Constrained Deep Supervised Hashing for Image Retrieval](https://www.ijcai.org/Proceedings/2017/0499.pdf) # [LCDSH] epoch:145, bit:48, dataset:cifar10-1, MAP:0.798, Best MAP: 0.798 From 9608c078afabd7e9ef8dd8096496ce7a149da048 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Wed, 25 Aug 2021 14:09:21 +0800 Subject: [PATCH 30/35] Create MV3_Large_1x_Aliproduct_DLBHC.yaml --- .../MV3_Large_1x_Aliproduct_DLBHC.yaml | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml diff --git a/ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml b/ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml new file mode 100644 index 000000000..1838e3100 --- /dev/null +++ b/ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml @@ -0,0 +1,147 @@ +# global configs +Global: + checkpoints: null + pretrained_model: ./output_dlbhc/RecModel/best_model + output_dir: ./output_dlbhc/ + device: gpu + save_interval: 1 + eval_during_train: True + eval_interval: 1 + epochs: 100 + #eval_mode: "retrieval" + print_batch_step: 10 + use_visualdl: False + + # used for static mode and model export + image_shape: [3, 224, 224] + save_inference_dir: ./inference + + #feature postprocess + feature_normalize: False + feature_binarize: "round" + +# model architecture +Arch: + name: "RecModel" + Backbone: + name: "MobileNetV3_large_x1_0" + pretrained: True + class_num: 512 + Head: + name: "FC" + class_num: 50030 + embedding_size: 512 + + infer_output_key: "features" + infer_add_softmax: "false" + +# loss function config for train/eval process +Loss: + Train: + - CELoss: + weight: 1.0 + epsilon: 0.1 + Eval: + - CELoss: + weight: 1.0 + +Optimizer: + name: Momentum + momentum: 0.9 + lr: + name: Piecewise + learning_rate: 0.1 + decay_epochs: [50, 150] + values: [0.1, 0.01, 0.001] + +# data loader for train and eval +DataLoader: + Train: + dataset: + name: ImageNetDataset + image_root: ./dataset/Aliproduct/ + cls_label_path: ./dataset/Aliproduct/train_list.txt + transform_ops: + - DecodeImage: + to_rgb: True + channel_first: False + - ResizeImage: + size: 256 + - RandCropImage: + size: 227 + - RandFlipImage: + flip_code: 1 + - NormalizeImage: + scale: 1.0/255.0 + mean: [0.4914, 0.4822, 0.4465] + std: [0.2023, 0.1994, 0.2010] + order: '' + sampler: + name: DistributedBatchSampler + batch_size: 128 + drop_last: False + shuffle: True + loader: + num_workers: 4 + use_shared_memory: True + + Eval: + dataset: + name: ImageNetDataset + image_root: ./dataset/Aliproduct/ + cls_label_path: ./dataset/Aliproduct/val_list.txt + transform_ops: + - DecodeImage: + to_rgb: True + channel_first: False + - ResizeImage: + size: 227 + - NormalizeImage: + scale: 1.0/255.0 + mean: [0.4914, 0.4822, 0.4465] + std: [0.2023, 0.1994, 0.2010] + order: '' + sampler: + name: DistributedBatchSampler + batch_size: 256 + drop_last: False + shuffle: False + loader: + num_workers: 4 + use_shared_memory: True + +Infer: + infer_imgs: docs/images/whl/demo.jpg + batch_size: 10 + transforms: + - DecodeImage: + to_rgb: True + channel_first: False + - ResizeImage: + resize_short: 256 + - CropImage: + size: 227 + - NormalizeImage: + scale: 1.0/255.0 + mean: [0.4914, 0.4822, 0.4465] + std: [0.2023, 0.1994, 0.2010] + order: '' + - ToCHWImage: + PostProcess: + name: Topk + topk: 5 + class_id_map_file: ppcls/utils/imagenet1k_label_list.txt + +Metric: + Train: + - TopkAcc: + topk: [1, 5] + Eval: + - TopkAcc: + topk: [1, 5] +# - Recallk: +# topk: [1] +# - mAP: +# - Precisionk: +# topk: [1] + From 8e0a5513591d07ed761e68ce5ce1447974b13467 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Wed, 25 Aug 2021 14:34:43 +0800 Subject: [PATCH 31/35] Update deephashloss.py --- ppcls/loss/deephashloss.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ppcls/loss/deephashloss.py b/ppcls/loss/deephashloss.py index 7d4efad16..44c08ef3b 100644 --- a/ppcls/loss/deephashloss.py +++ b/ppcls/loss/deephashloss.py @@ -70,7 +70,6 @@ class LCDSHLoss(nn.Layer): def forward(self, input, label): feature = input["features"] - label = label.astype("float32") # label to ont-hot label = paddle.flatten(label) From 3b19dc9c961307e4705e80c282226ac13a9853e3 Mon Sep 17 00:00:00 2001 From: cuicheng01 Date: Thu, 26 Aug 2021 03:37:20 +0000 Subject: [PATCH 32/35] fix invalid link in getting_started --- docs/en/tutorials/getting_started_en.md | 2 +- docs/zh_CN/tutorials/getting_started.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/tutorials/getting_started_en.md b/docs/en/tutorials/getting_started_en.md index 19142b014..1903a04ef 100644 --- a/docs/en/tutorials/getting_started_en.md +++ b/docs/en/tutorials/getting_started_en.md @@ -23,7 +23,7 @@ Among them, `-c` is used to specify the path of the configuration file, `-o` is `-o use_gpu=True` means to use GPU for training. If you want to use the CPU for training, you need to set `use_gpu` to `False`. -Of course, you can also directly modify the configuration file to update the configuration. For specific configuration parameters, please refer to [Configuration Document](config_en.md). +Of course, you can also directly modify the configuration file to update the configuration. For specific configuration parameters, please refer to [Configuration Document](config_description_en.md). * The output log examples are as follows: * If mixup or cutmix is used in training, top-1 and top-k (default by 5) will not be printed in the log: diff --git a/docs/zh_CN/tutorials/getting_started.md b/docs/zh_CN/tutorials/getting_started.md index 7135b7934..3708d3e82 100644 --- a/docs/zh_CN/tutorials/getting_started.md +++ b/docs/zh_CN/tutorials/getting_started.md @@ -30,7 +30,7 @@ python3 tools/train.py \ 其中,`-c`用于指定配置文件的路径,`-o`用于指定需要修改或者添加的参数,其中`-o Arch.pretrained=False`表示不使用预训练模型,`-o Global.device=gpu`表示使用GPU进行训练。如果希望使用CPU进行训练,则需要将`Global.device`设置为`cpu`。 -更详细的训练配置,也可以直接修改模型对应的配置文件。具体配置参数参考[配置文档](config.md)。 +更详细的训练配置,也可以直接修改模型对应的配置文件。具体配置参数参考[配置文档](config_description.md)。 运行上述命令,可以看到输出日志,示例如下: From c9be0fe00a98510c775a75b619ce70847918f5a8 Mon Sep 17 00:00:00 2001 From: dongshuilong Date: Thu, 26 Aug 2021 07:13:11 +0000 Subject: [PATCH 33/35] fix loss_msg bugs --- ppcls/engine/train/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppcls/engine/train/utils.py b/ppcls/engine/train/utils.py index b82694f31..92eb35d75 100644 --- a/ppcls/engine/train/utils.py +++ b/ppcls/engine/train/utils.py @@ -34,7 +34,7 @@ def update_loss(trainer, loss_dict, batch_size): for key in loss_dict: if key not in trainer.output_info: trainer.output_info[key] = AverageMeter(key, '7.5f') - trainer.output_info[key].update(loss_dict[key].numpy()[0], batch_size) + trainer.output_info[key].update(loss_dict[key].numpy()[0], batch_size) def log_info(trainer, batch_size, epoch_id, iter_id): From f61b53104764e7527c57808ae47c1d360b4edfc0 Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Thu, 26 Aug 2021 16:27:29 +0800 Subject: [PATCH 34/35] Update MV3_Large_1x_Aliproduct_DLBHC.yaml --- ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml b/ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml index 1838e3100..c9a8b7b40 100644 --- a/ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml +++ b/ppcls/configs/Products/MV3_Large_1x_Aliproduct_DLBHC.yaml @@ -1,7 +1,7 @@ # global configs Global: checkpoints: null - pretrained_model: ./output_dlbhc/RecModel/best_model + pretrained_model: null output_dir: ./output_dlbhc/ device: gpu save_interval: 1 @@ -138,7 +138,9 @@ Metric: topk: [1, 5] Eval: - TopkAcc: - topk: [1, 5] + topk: [1, 5] + +# switch to metric below when eval by retrieval # - Recallk: # topk: [1] # - mAP: From d388d69a63a3ed0c91b4ce4a31aad725cf01433e Mon Sep 17 00:00:00 2001 From: Bin Lu Date: Thu, 26 Aug 2021 19:38:40 +0800 Subject: [PATCH 35/35] Update retrieval.py --- ppcls/engine/evaluation/retrieval.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ppcls/engine/evaluation/retrieval.py b/ppcls/engine/evaluation/retrieval.py index cd8830a55..49d9626f6 100644 --- a/ppcls/engine/evaluation/retrieval.py +++ b/ppcls/engine/evaluation/retrieval.py @@ -126,10 +126,10 @@ def cal_feature(evaler, name='gallery'): batch_feas = paddle.divide(batch_feas, feas_norm) # do binarize - if self.config["Global"].get("feature_binarize") == "round": + if evaler.config["Global"].get("feature_binarize") == "round": batch_feas = paddle.round(batch_feas).astype("float32") * 2.0 - 1.0 - if self.config["Global"].get("feature_binarize") == "sign": + if evaler.config["Global"].get("feature_binarize") == "sign": batch_feas = paddle.sign(batch_feas).astype("float32") if all_feas is None: